QUERY.C
/* 
    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: 
    ========== 
    InitSQLEnvironment() - Initialize ODBC library 
    DisplayDatabases() - Display available Data Sources 
    ConnectDatabase() - Connect to a specific data source 
    DriverConnectDatabase() - Connect through driver specific dialogs 
    DisplayConnections() - Display List of made connections 
    DisplayQueries() - Display list of Query Handles (hstmts) 
    NewQueryWindow() - Open a new hstmt and update displays 
    ChangeCurrentCursor() - Change current cursor display 
    ChangeCurrentQuery() - Change current query display 
    DisplayNewCrsrAndStmt() - update cusor & query displays 
    FreeConnect() - free a connection 
    FreeQuery() - free a query handle 
    CloseQueryWindow() - close a query window 
    ExecuteQuery() - execute a user specified query 
    CloseDatabases() - check if all connections are closed 
    FreeSQLEnvironment() - free ODBC library 
    DisplayError() - displays SQL Error and Warnings 
 
    COMMENTS: 
    ========= 
    Created by Microsoft Corporation. 
 
    The application uses MDI Child Window Titles to store values of 
    connected SQLHDBCs and SQLHSTMTs. These values are also stored in the 
    comboboxes that are displayed on the toolbar. 
 
*/ 
 
#include <stdio.h> 
#include <string.h> 
 
#include <windows.h> 
 
#include "sql.h" 
#include "sqlext.h" 
#include "qurydemo.h" 
 
/* 
    FUNCTION: InitSQLEnvironment() 
    COMMENTS: Allocate an environment handle for ODBC function calls. 
*/ 
 
BOOL FAR PASCAL InitSQLEnvironment() 
{ 
   // reset child window count 
   nChildCount = 0; 
 
   // Allocate an Environment Handle 
   if (SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv) != SQL_SUCCESS) 
      return FALSE; 
 
   return (SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, 
                         (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER) == SQL_SUCCESS); 
} 
 
/* 
    FUNCTION: DisplayDatabases(HWND hWnd) 
    COMMENTS: Display a list of available data sources. Use 
          SQLDataSources function call. 
*/ 
 
void FAR PASCAL DisplayDatabases(HWND hWnd) 
{ 
   SWORD     nDirection;                             //fetch direction 
   SWORD     nDataSourceNameLength;                  //DSN str length 
   SWORD     nSourceDescriptionLength;               //Driver Description str length 
   char      szDataSourceName[MAXBUFLEN+1];          //DSN string 
   char      szSourceDescription[MAXBUFLEN+1];       //Driver Description string 
   SQLRETURN nResult;                                //Return Code 
 
   //Call SQLDataSources, first with SQL_FETCH_FIRST and from then on 
   //with SQL_FETCH_NEXT until it returns SQL_NO_DATA. Add 
   //all returned DSNs in the provided combo box for display. 
   SendMessage(hWnd, CB_RESETCONTENT, 0, 0); 
   for (nDirection = SQL_FETCH_FIRST; 
        (nResult = SQLDataSources(henv, nDirection, szDataSourceName, MAXBUFLEN, 
                                  &nDataSourceNameLength, szSourceDescription, MAXBUFLEN, &nSourceDescriptionLength)) != 
        SQL_NO_DATA && 
        nResult != SQL_ERROR; 
        nDirection = SQL_FETCH_NEXT 
        ) 
      SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szDataSourceName); 
   SendMessage(hWnd, CB_SETCURSEL, 0, 0); 
} 
 
/* 
    FUNCTION: ConnectDatabase(HWND hWnd) 
    COMMENTS: Connect to a DSN. 
*/ 
 
BOOL FAR PASCAL ConnectDatabase(HWND hWnd) 
{ 
   char      szBuffer[MAXBUFLEN+1];  // buffer to display successful connection on hdbc combo-box 
   char      szDBName[MAXBUFLEN+1];  // DSN sting 
   char      szUserName[MAXBUFLEN+1];// User name 
   char      szPassword[MAXBUFLEN+1];// Password 
   SQLHDBC   hdbc;                   // hdbc 
   SQLRETURN nResult;                // Result code 
 
   // check if enough windows are already open, refuse connection 
 
   if (nChildCount >= MAXCHILDWNDS) { 
      MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND); 
      return (FALSE); 
   } 
 
 
   // retrieve DSN, UID and PWD values from the connect dialog box 
 
   GetDlgItemText(hWnd, IDCOMBO_DATASOURCE, szDBName, MAXBUFLEN); 
   GetDlgItemText(hWnd, IDTEXT_USERNAME, szUserName, MAXBUFLEN); 
   GetDlgItemText(hWnd, IDTEXT_PASSWORD, szPassword, MAXBUFLEN); 
 
   // Allocate a new SQLHDBC. If successful then call SQLConnect using the 
   // allocated hdbc and supplied connection information. 
   if ((nResult = SQLAllocHandle(SQL_HANDLE_DBC,henv, (SQLHDBC FAR *)&hdbc)) != SQL_SUCCESS) { 
      DisplayError(nResult, hWnd, SQL_HANDLE_ENV, henv); 
      return (FALSE); 
   } 
 
   nResult = SQLConnect(hdbc,(LPSTR)szDBName,SQL_NTS,(LPSTR)szUserName,SQL_NTS,(LPSTR)szPassword,SQL_NTS); 
 
   // if failed to connect, free the allocated hdbc before return 
   if (nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO) { 
      DisplayError(nResult, hWnd, SQL_HANDLE_DBC, hdbc); 
      SQLFreeHandle(SQL_HANDLE_DBC,hdbc); 
      return (FALSE); 
   } 
 
   // display any connection information if driver returns SQL_SUCCESS_WITH_INFO 
   if (nResult == SQL_SUCCESS_WITH_INFO) 
      DisplayError(nResult, hWnd, SQL_HANDLE_DBC, hdbc); 
 
   // update the hdbc(s) combo-box and create a new hstmt and its 
   // associated window. 
   wsprintf(szBuffer, DSN_HDBC_FORMAT, (LPSTR)szDBName, hdbc); 
   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); 
   NewQueryWindow(); 
   return (TRUE); 
} 
 
/* 
    FUNCTION: DriverConnectDatabase(HWND hWnd) 
    COMMENTS: Connect to a DSN using SQLDriverConnect function call. It 
          allows driver manager and drivers to interact with the user 
          directly to prompt for connection information. 
*/ 
 
BOOL FAR PASCAL DriverConnectDatabase(HWND hWnd) 
{ 
   char      szBuffer[MAXBUFLEN+1];  //display successful connection info on hdbc(s) combo-box 
   char      szDBName[MAXBUFLEN+1];  //DSN string 
   SWORD     swStrLen;               //String length 
   SQLHDBC   hdbc;                   //hdbc 
   SQLRETURN nResult;                //result code 
 
   // Allocate a new Connection Handle. 
   if ((nResult = SQLAllocHandle(SQL_HANDLE_DBC,henv, (SQLHDBC FAR *)&hdbc)) != SQL_SUCCESS) { 
      DisplayError(nResult, hWnd, SQL_HANDLE_ENV, henv); 
      return (FALSE); 
   } 
 
   // Call SQLDriverConnect to make a connection request. Provide SQL_DRIVER_COMPLETE_REQUIRED 
   // flag sothat driver manager and driver can ask for connection information 
   // If failed to connect, free the allocated hdbc in previous step. 
   nResult = SQLDriverConnect(hdbc, hWnd, "", 0, szBuffer,  MAXBUFLEN, &swStrLen, SQL_DRIVER_COMPLETE_REQUIRED); 
 
 
   if (nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO) { 
      SQLFreeHandle(SQL_HANDLE_DBC,hdbc); 
      return (FALSE); 
   } 
 
   // If driver returns additional information with SQL_SUCCESS_WITH_INFO 
   // flag, display the information 
   if (nResult == SQL_SUCCESS_WITH_INFO) 
      DisplayError(nResult, hWnd, SQL_HANDLE_DBC, hdbc); 
 
   // Call SQLGetInfo to find out the DSN name for the above connection. 
   // Note, application should not depend upon the DSN name being present 
   // in the returned connection string. 
   strcpy(szDBName, DEFDBNAME); // initialize the string value 
 
 
   SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, (PTR)szDBName, MAXBUFLEN+1, &swStrLen); 
if( !*szDBName) 
strcpy(szDBName,"nameless"); 
 
   // Display the new connection information in the hdbc(s) combo-box. 
   // Create a new hstmt and its associated window. 
   wsprintf(szBuffer, DSN_HDBC_FORMAT, (LPSTR)szDBName, hdbc); 
   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); 
   NewQueryWindow(); 
   return (TRUE); 
} 
 
/* 
    FUNCTION: DisplayConnections(HWND hWndhdbc) 
    COMMENTS: Display list of available hdbc(s) in the given list box. 
*/ 
 
void FAR PASCAL DisplayConnections(HWND hWndhdbc) 
{ 
   int  nConnects;      // # of connections 
   int  nIndex;                 // counter 
   char szBuffer[MAXBUFLEN+1];  // string buffer 
 
   // read the information from the hdbc(s) combo-box in the tool bar 
   // and feed it in the given list box. 
 
   SendMessage(hWndhdbc, LB_RESETCONTENT, 0, 0); 
   nConnects = (int) SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0); 
   for (nIndex = 0; nIndex < nConnects; nIndex++) { 
      SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
      SendMessage(hWndhdbc, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
   } 
   SendMessage(hWndhdbc, LB_SETCURSEL, 0, 0); 
} 
 
/* 
    FUNCTION: DisplayQueries(HWND hWndhstmt int nCrsrIndex) 
    COMMENTS: Display list of hstmt(s) for the currently selected hdbc 
          in the given listbox. 
*/ 
 
void FAR PASCAL DisplayQueries(HWND hWndhstmt, HWND hWndhdbc, int nCrsrIndex) 
{ 
   char  szBuffer[MAXBUFLEN+1];  // MDI child window title 
   HWND  hWndChild;              // MDI child window handle 
   SQLHDBC  hdbc1;               // hdbc in the window title 
   SQLHDBC  hdbc2;               // selected hdbc in the list box 
   SQLHSTMT hstmt;               // hstmt in the window title 
 
   // reset the hstmt list box in the disconnect dialog box 
 
   SendMessage(hWndhstmt, LB_RESETCONTENT, 0, 0); 
 
   // go through all available MDI child windows and check if the 
   // hdbc in the title matches the one selected in the list box. 
   // if they match, use the hstmt in the window title to create 
   // a new entry in the hstmt(s) 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, ODBCMDICLASS)) 
         continue; 
 
      GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
      sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc1, &hstmt); 
 
      SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nCrsrIndex, (LPARAM)(LPSTR)szBuffer); 
      sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc2); 
 
      if (hdbc1 != hdbc2) 
         continue; 
 
      wsprintf(szBuffer, ((hWndChild == hWndActiveChild) ?  CURQUERY_STRING:    QUERY_STRING), hstmt); 
      SendMessage(hWndhstmt, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
   } 
   SendMessage(hWndhstmt, LB_SETSEL, TRUE, 0); 
} 
 
/* 
    FUNCTION: NewQueryWindow() 
    COMMENTS: Create a new hstmt on current hdbc and its associated window 
*/ 
 
void FAR PASCAL NewQueryWindow() 
{ 
   int              nCurrenthdbc;           // current selection in the hdbc combobox 
   char             szBuffer[MAXBUFLEN+1];  // string in the hdbc combobox on the toolbar 
   char             szDBName[MAXBUFLEN+1];  // DSN string 
   SQLHDBC          hdbc;                   // hdbc value in the combobox 
   SQLHSTMT         hstmt;                  // hstmt 
   MDICREATESTRUCT  mcs;                    // MDI child window create structure 
   SQLRETURN        nResult;                // Result code 
 
   szDBName[0]='\0'; 
szBuffer[0]= '\0'; 
 
// check if there is hdbc selected in the combobox 
 
if ((nCurrenthdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0)) == CB_ERR) { 
      MessageBox(hWndFrame, MAKECONNECT, NOHDBCERROR, 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 DSN string and hdbc value from the combo-box 
   SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nCurrenthdbc, (LPARAM)(LPSTR)szBuffer); 
   sscanf(szBuffer, SCANDSNHDBC_FORMAT, szDBName, &hdbc); 
 
 
   // Allocate a new Statement Handle on the scanned hdbc 
   if ((nResult = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt)) != SQL_SUCCESS) { 
      DisplayError(nResult, hWndFrame, SQL_HANDLE_DBC, hdbc); 
      return; 
   } 
 
   // create a new MDI client window. maximized, if the previous is so. 
   mcs.szClass = ODBCMDICLASS; 
   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); 
      SQLFreeHandle(SQL_HANDLE_STMT,hstmt); 
      return; 
   } 
 
   // display the DSN string, SQLHDBC and SQLHSTMT in the title of newly 
   // created window. Increment the child window counter 
   wsprintf(szBuffer, QUERY_STRING, hstmt); 
   SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
   SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
   wsprintf(szBuffer, DSN_HDBC_HSTMT_FORMAT, (LPSTR)szDBName, hdbc, hstmt); 
   SetWindowText(hWndActiveChild, szBuffer); 
   nChildCount++; 
 
   // update the hstmt(s) combo-box in the tool bar. 
   ChangeCurrentQuery(hWndStmtList); 
} 
 
/* 
    FUNCTION: ChangeCurrentCursor(HWND hWndCrsrList) 
    COMMENTS: Change the displayed hdbc in the hdbc(s) combobox 
          Also activate the appropriate MDI child window that 
          has the same hdbc as the new hdbc in the combobox. 
*/ 
 
void FAR PASCAL ChangeCurrentCursor(HWND hWndCrsrList) 
{ 
   int      nNewhdbc;               //new hdbc position 
   int      nConnects;              //# of connections 
   int      nIndex;                 //counter 
   char     szBuffer[MAXBUFLEN+1];  //string buffer 
   BOOL     bChangedFocus;          //Activate a different MDI child? 
   HWND     hWndChild;              //MDI Child window 
   SQLHDBC  hdbc1;                  //hdbc in the window title 
   SQLHDBC  hdbc2;                  //hdbc in the combobox 
   SQLHSTMT hstmt;                  //hstmt in the window title 
 
   // 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 hdbc(s) combobox. 
   nNewhdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0); 
   nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0); 
 
   for(nIndex = 0; nIndex < nConnects; nIndex++) { 
      SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
      if (strstr(szBuffer, CUR_MARK)) 
         break; 
   } 
 
   if (nIndex == 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 (nIndex != nConnects) { 
      SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
      szBuffer[strlen(szBuffer)-2] = '\0'; 
      SendMessage(hWndCrsrList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer); 
      SendMessage(hWndCrsrList, CB_DELETESTRING, nIndex+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 hstmt(s) combobox. Search through the MDI child windows 
   // and collect all hstmt(s) from window titles that have the same 
   // hdbc value as the newly selected hdbc in the hdbc(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, ODBCMDICLASS)) 
         continue; 
 
      GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
      sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc1, &hstmt); 
 
      SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nNewhdbc, (LPARAM)(LPSTR)szBuffer); 
      sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc2); 
 
      if (hdbc1 != hdbc2) 
         continue; 
 
      if (!bChangedFocus) { 
         // If the first match is found, change the active window 
         // and update the hstmt(s) combobox with a new entry that 
         // has hstmt marked with current marker. 
         bChangedFocus = TRUE; 
         hWndActiveChild = hWndChild; 
         SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0); 
         wsprintf(szBuffer, CURQUERY_STRING, hstmt); 
         SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
         SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
      } 
      else { 
         // simply add the hstmt in the hstmt(s) combobox. 
         wsprintf(szBuffer, QUERY_STRING, hstmt); 
         SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
      } 
   } 
} 
 
/* 
    FUNCTION: ChangeCurrentQuery(HWND hWndStmtList) 
    COMMENTS: Change the current selection in the hstmt(s) combobox. 
          Update the current marker in the combobox and activate 
          proper MDI Child window. 
*/ 
 
void FAR PASCAL ChangeCurrentQuery(HWND hWndStmtList) 
{ 
   int      nNewhstmt;              //new selection in combobox 
   int      nStmts;                 //# of hstmts 
   int      nIndex;                 //counter 
   char     szBuffer[MAXBUFLEN+1];  //string buffer to update displays 
   HWND     hWndChild;              //MDI child window handle 
   SQLHDBC  hdbc1 = NULL;                  //hdbc in hdbc(s) combobox 
   SQLHDBC  hdbc2 = NULL;                  //hdbc in child window title 
   SQLHSTMT hstmt1 = NULL;                 //newly selected hstmt 
   SQLHSTMT hstmt2 = NULL;                 //hstmt in child window title 
 
   // find the index of new selection and total number of hstmt(s) 
   nNewhstmt = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0); 
   nStmts = (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(nIndex = 0; nIndex < nStmts; nIndex++) { 
      SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
      if (strstr(szBuffer, CUR_MARK)) 
         break; 
   } 
 
   if (nIndex == nNewhstmt) 
      return; 
 
   // if a previous selection was found, remove current marker 
   // and update it in the hstmt(s) combobox. 
   if (nIndex != nStmts) { 
      SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
      szBuffer[strlen(szBuffer)-2] = '\0'; 
      SendMessage(hWndStmtList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer); 
      SendMessage(hWndStmtList, CB_DELETESTRING, nIndex+1, 0); 
   } 
 
   // mark the current selection and update it in the hstmt(s) combobox 
   SendMessage(hWndStmtList, CB_GETLBTEXT, nNewhstmt, (LPARAM)(LPSTR)szBuffer); 
   strcat(szBuffer, CUR_MARK); 
   SendMessage(hWndStmtList, CB_INSERTSTRING, nNewhstmt, (LPARAM)(LPSTR)szBuffer); 
   SendMessage(hWndStmtList, CB_DELETESTRING, nNewhstmt+1, 0); 
   SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
 
   // scan hstmt value and hdbc value from current selection in 
   // hdbc(s) and hstmt(s) comboboxes. 
   sscanf(szBuffer, QUERY_STRING, &hstmt1); 
 
   SendMessage(hWndCrsrList, CB_GETLBTEXT, (UINT)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0), 
               (LPARAM)(LPSTR)szBuffer); 
   sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc1); 
 
 
   // go through list of MDI Child windows and match the hstmt and hdbc 
   // 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, ODBCMDICLASS)) 
         continue; 
 
      GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
      sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc2, &hstmt2); 
 
      if (hdbc1 == hdbc2 && hstmt1 == hstmt2) { 
         hWndActiveChild = hWndChild; 
         SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0); 
         break; 
      } 
   } 
} 
 
/* 
    FUNCTION: DisplayNewCrsrAndStmt() 
    COMMENTS: If user changes currently active MDI Child Window, both 
          hstmt(s) and hdbc(s) comboboxes need to be updated to 
          reflect currently selected MDI child. match the hstmt and 
          hdbc value in the title of MDI child to those on display 
          in hstmt(s) and hdbc(s) comboboxes respectively. 
*/ 
 
void FAR PASCAL DisplayNewCrsrAndStmt() 
{ 
   int      nConnects;              // # of hdbc(s) 
   int      nStmts;                 // # of hstmt(s) 
   int      nOldhdbc;               // prev selection in hdbc combobox 
   int      nOldhstmt;              // prev selection in hstmt combobox 
   int      nIndex;                 // counter 
   char     szBuffer[MAXBUFLEN+1];  // display buffer 
   HWND     hWndChild;              // MDI Child window 
   SQLHDBC  hdbc1;                  // hdbc in window title 
   SQLHDBC  hdbc2;                  // hdbc in hdbc(s) combobox 
   SQLHSTMT hstmt1;                 // hstmt in window title 
   SQLHSTMT hstmt2;                 // hstmt in hstmt(s) combobox 
 
   // scan hdbc and hstmt values from newly selected window 
   GetWindowText(hWndActiveChild, szBuffer, MAXBUFLEN); 
   sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc1, &hstmt1); 
 
   // search through list of hdbc(s) in hdbc combobox and find 
   // matching hdbc. remove marker from prev selection and add 
   // marker to the new selection. update combobox accordingly. 
   nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0); 
   nOldhdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0); 
 
   for(hdbc2 = (SQLHDBC)(nIndex = 0); hdbc1 != hdbc2; nIndex++) { 
      SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
      sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc2); 
   } 
 
   if (--nIndex != nOldhdbc) // change in hdbc combobox required. 
      { 
         SendMessage(hWndCrsrList, CB_GETLBTEXT, nOldhdbc, (LPARAM)(LPSTR)szBuffer); 
         szBuffer[strlen(szBuffer)-2] = '\0'; 
         SendMessage(hWndCrsrList, CB_INSERTSTRING, nOldhdbc, (LPARAM)(LPSTR)szBuffer); 
         SendMessage(hWndCrsrList, CB_DELETESTRING, nOldhdbc+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 hstmt(s) combobox, search through the list 
         // of MDI child windows and find all hstmt(s) associated to 
         // new hdbc. Build the new list of hstmt(s) for the hstmt 
         // combobox. Mark the one hstmt 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, ODBCMDICLASS)) 
               continue; 
 
            GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
            sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc2, &hstmt2); 
 
            if (hdbc1 != hdbc2) 
               continue; 
 
            if (hWndActiveChild == hWndChild) { 
               wsprintf(szBuffer, CURQUERY_STRING, hstmt2); 
               SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
               SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
            } 
            else { 
               wsprintf(szBuffer, QUERY_STRING, hstmt2); 
               SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer); 
            } 
         } 
      } 
   else // no change in hdbc combobox required 
      { 
         // go through the list of hstmt(s) in hstmt combobox. 
         // find the one that matches the currently activated MDI 
         // child window. 
         nOldhstmt = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0); 
         nStmts = (int)SendMessage(hWndStmtList, CB_GETCOUNT, 0, 0); 
 
         for(hstmt2 = (SQLHDBC)(nIndex = 0); hstmt1 != hstmt2; nIndex++) { 
            SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
            sscanf(szBuffer, QUERY_STRING, &hstmt2); 
         } 
 
         if (--nIndex != nOldhstmt) // new index in hstmt differs from previous selection 
            { 
               // remove the marker from previous selection. Add 
               // it to the new string and update the combobox display 
               SendMessage(hWndStmtList, CB_GETLBTEXT, nOldhstmt, (LPARAM)(LPSTR)szBuffer); 
               szBuffer[strlen(szBuffer)-2] = '\0'; 
               SendMessage(hWndStmtList, CB_INSERTSTRING, nOldhstmt, (LPARAM)(LPSTR)szBuffer); 
               SendMessage(hWndStmtList, CB_DELETESTRING, nOldhstmt+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); 
            } 
      } 
} 
 
/* 
    FUNCTION: FreeConnect(HWND hWndhdbc) 
    COMMENTS: Disconnect and Free the currently selected hdbc in 
          the hdbc listbox in disconnect dialog. Call SQLDisconnect 
          and SQLFreeConnect to free the hdbc. Close all MDI 
          child windows associated with this hdbc. That will 
          automatically free associated hstmt(s). 
*/ 
 
void FAR PASCAL FreeConnect(HWND hWndhdbc) 
{ 
   int     nIndex;                 // current selection in the listbox of disconnect dlg 
   int     nCurrent;               // current selection in hdbc(s) combobox 
   char    szBuffer[MAXBUFLEN+1];  // display buffer 
   char    szSelect[MAXBUFLEN+1];  // original selection in hdbc(s) combobox 
   char    szDBName[MAXBUFLEN+1];  // DSN string 
   HWND    hWndChild;              // MDI Child window 
   SQLHDBC hdbc1 = NULL;                  // hdbc in the list box of disconnect dlg 
   SQLHDBC hdbc2 = NULL;                  // hdbc in the MDI child window title 
 
   szDBName[0]='\0'; 
// check current selection in the list box of disconnect dialog. scan 
   // hdbc 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, SCANDSNHDBC_FORMAT, szDBName, &hdbc1); 
 
 
   // go through the list of MDI child windows and find matching hdbc(s) 
   // close all children who have the same hdbc value. Closing them 
   // automatically frees associated hstmts. see CloseQueryWindow. 
   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, ODBCMDICLASS)) { 
         GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
         sscanf(szBuffer, SCANHDBC_TITLEFORMAT, &hdbc2); 
 
         if (hdbc1 == hdbc2) { 
            // destroy the window and restart search 
            SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0); 
            hWndTemp = GetWindow(hWndMDIClient, GW_CHILD); 
         } 
      } 
      hWndChild = hWndTemp; 
   } 
 
   // call SQLDisconnect and SQLFreeConnect to disconnect and free hdbc 
   SQLDisconnect(hdbc1); 
   SQLFreeHandle(SQL_HANDLE_DBC,hdbc1); 
 
   // update the hdbc(s) combobox display by removing the deleted hdbc 
   // from the list and reselecting the previous selection 
   wsprintf(szBuffer, DSN_HDBC_FORMAT, (LPSTR)szDBName, hdbc1); 
   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 SQLHDBC 
   // was deleted, make sure to make the next available SQLHDBC 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); 
   } 
} 
 
/* 
    FUNCTION: FreeQuery(HWND hWndhstmt, HWND hWndhdbc, int nIndex) 
    COMMENTS: Free a query window based upon current selection in 
          hstmt list box in the disconnect dialog. 
*/ 
 
void FAR PASCAL FreeQuery(HWND hWndhstmt, HWND hWndhdbc, int nIndex) 
{ 
   char     szBuffer[MAXBUFLEN+1];  // display buffer 
   HWND     hWndChild;      // MDI child window 
   SQLHDBC  hdbc1;          // hdbc in the hdbc listbox of disconnect dlg 
   SQLHDBC  hdbc2;          // hdbc in the MDI child window title 
   SQLHSTMT hstmt1;         // hstmt in the hstmt listbox of disconnect dlg 
   SQLHSTMT hstmt2;         // hstmt in the MDI child window title 
 
   // scan the hstmt and hdbc values from the current selections in 
   // respective listboxes of disconnect dialog box. 
   SendMessage(hWndhstmt, LB_GETTEXT, nIndex, (LPARAM)(LPSTR)szBuffer); 
   sscanf(szBuffer, QUERY_STRING, &hstmt1); 
   SendMessage(hWndhdbc, LB_GETTEXT, (UINT)SendMessage(hWndhdbc, LB_GETCURSEL,  0, 0), (LPARAM)(LPSTR)szBuffer); 
   sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc1); 
 
   // go through the list of MDI child windows and find matching window 
   // that has same values for hdbc and hstmt. Destroy the matching window. 
   // that will call CloseQueryWindow and thus free up associated hstmt. 
   for(hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) { 
      // ignore non MDI child windows 
      GetClassName(hWndChild, szBuffer, MAXBUFLEN); 
      if (strcmp(szBuffer, ODBCMDICLASS)) 
         continue; 
      GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
      sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc2, &hstmt2); 
      if (hdbc1 == hdbc2 && hstmt1 == hstmt2) 
         break; 
   } 
   SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0); 
} 
 
/* 
    FUNCTION: CloseQueryWindow(HWND hWnd) 
    COMMENTS: Close a Query window. Call SQLFreeHandle to free 
          associated hstmt. 
*/ 
 
void FAR PASCAL CloseQueryWindow(HWND hWnd) 
{ 
   char szBuffer[MAXBUFLEN+1];  // display buffer 
   char szSelect[MAXBUFLEN+1];  // current selection in hstmt(s) combobox 
   SQLHSTMT hstmt;              // hstmt value in window title 
 
   // scan the hstmt value from the window title 
   GetWindowText(hWnd, szBuffer, MAXBUFLEN); 
   sscanf(szBuffer, SCANHSTMT_TITLEFORMAT, &hstmt); 
 
   // Drop the current Statement Handle 
   SQLFreeHandle(SQL_HANDLE_STMT,hstmt); 
 
   // find the matching hstmt in the hstmt(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 hstmt and hdbc displays. See 
   // DisplayNewCrsrAndStmt function. 
   wsprintf(szBuffer, QUERY_STRING, hstmt); 
   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--; 
} 
 
/* 
    FUNCTION: ExecuteQuery() 
    COMMENTS: 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 ODBC function(s) failed. 
*/ 
 
void FAR PASCAL ExecuteQuery() 
{ 
   char      szBuffer[MAXBUFLEN+1];      // display buffer 
   HWND      hList;                      // result listbox handle 
   SQLHDBC   hdbc;                       // hdbc 
   SQLHSTMT  hstmt;                      // hstmt 
   SWORD     nCols = 0;                  // # of result columns 
   SWORD     nCount;                     // index 
   SWORD     swColType;                  // column data type 
   SWORD     swColScale;                 // column scale 
   SWORD     swColNull;                  // nullable column ? 
   SWORD     swColLength = MAXDATALEN;   // column data length 
   DWORD     dwText;                     // tab stop for listbox 
   UDWORD    udwColDef;                  // precision on the column 
   SQLRETURN nReturn;                    // return code 
   HCURSOR   hOldCursor;                 // default cursor handle 
   int       nRows;                      // # of result rows 
 
   // check if there is an active window available 
   if (!hWndActiveChild) { 
      MessageBox(hWndFrame, ((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) <=0) ? 
                             MAKECONNECT : OPENWINDOW ), NOHSTMTERROR, MB_OK | MB_ICONHAND); 
      return; 
   } 
 
   // change cursor shape to hour glass 
   hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); 
 
   // initialize column data and column data length arrays 
   for (nCount = 0; nCount < MAX_COL; nCount++) { 
      dwDataLen[nCount] = 0; 
      rgbData[nCount][0] = '\0'; 
   } 
 
   // scan hdbc, hstmt values 
   GetWindowText(hWndActiveChild, szBuffer, MAXBUFLEN); 
   sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc, &hstmt); 
 
   // get the user typed SQL 
   GetWindowText(GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDTEXT_SQL), szBuffer, MAXBUFLEN); 
 
   // execute SQL and process errors if any 
   // call SQLExecDirect to execute the SQL statement 
   nReturn = SQLExecDirect(hstmt, szBuffer, SQL_NTS); 
   if (nReturn != SQL_SUCCESS) { 
      DisplayError(nReturn, hWndActiveChild, SQL_HANDLE_STMT, hstmt); 
 
      // if the return value was just information, carry on 
      if (nReturn != SQL_SUCCESS_WITH_INFO) { 
         // Close the open result set. 
         SQLCloseCursor(hstmt); 
         SetCursor(hOldCursor); 
         return; 
      } 
   } 
 
   // call SQLNumResultCols 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 
   nReturn = SQLNumResultCols(hstmt, &nCols); 
   if (nCols >= MAX_COL) { 
      nCols = MAX_COL; 
      wsprintf(szDispBuffer, COLTRUNC_WARNG, MAX_COL); 
      MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION); 
   } 
   else if (nCols == 0) { 
      // Close the open result set. 
      SQLCloseCursor(hstmt); 
      SetCursor(hOldCursor); 
      return; 
   } 
 
   // call SQLBindCol to bind column data array and column data length 
   // array to the result set 
   for(nCount=0; nCount<nCols; nCount++) 
      SQLBindCol(hstmt, (UWORD)(nCount+1), SQL_C_CHAR, rgbData[nCount], MAXDATALEN, &dwDataLen[nCount]); 
 
   // 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); 
 
   // call SQLDescribeCol to get 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=1, szDispBuffer[0]='\0'; nCount <= nCols; nCount++) { 
      SQLDescribeCol(hstmt, nCount, szBuffer, MAXDATALEN, &swColLength, &swColType, &udwColDef, 
                     &swColScale, &swColNull); 
      strcat(szDispBuffer, szBuffer); 
      dwText = strlen(szDispBuffer); 
      szDispBuffer[dwText++] = '\t'; 
      szDispBuffer[dwText] = '\0'; 
   } 
   if (*szDispBuffer) 
      szDispBuffer[strlen(szDispBuffer)-1]='\0'; 
   SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szDispBuffer); 
 
   // call SQLFetch to fetch each row of the result set. Extract data 
   // value and store it in the display buffer, separated by tabs. 
   // continue until SQLFetch fails. 
   for(nRows = 0; (nReturn = SQLFetch(hstmt))==SQL_SUCCESS || nReturn==SQL_SUCCESS_WITH_INFO;) { 
      if (nReturn != SQL_SUCCESS) 
         DisplayError(nReturn, hWndActiveChild, SQL_HANDLE_STMT, hstmt); 
      for(nCount=0, szDispBuffer[0]='\0'; nCount<nCols; nCount++) { 
         // check if the column is a null value? 
         strcat(szDispBuffer, (dwDataLen[nCount]==SQL_NULL_DATA)?NULLDATASTRING:rgbData[nCount]); 
         dwText = strlen(szDispBuffer); 
         szDispBuffer[dwText++] = '\t'; 
         szDispBuffer[dwText] = '\0'; 
      } 
      if (*szDispBuffer) 
         szDispBuffer[strlen(szDispBuffer)-1]='\0'; 
      else 
         break; 
      SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szDispBuffer); 
      if (++nRows == MAX_ROW) { 
         wsprintf(szDispBuffer, ROWTRUNC_WARNG, MAX_ROW); 
         MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION); 
         break; 
      } 
   } 
 
   // set the horizontal scroll extent in the list box and ask for repaint. 
   SendMessage(hList, LB_SETHORIZONTALEXTENT, (WPARAM)(nCols*LISTHORZSCROLL+LISTHORZEXT), 0); 
   SendMessage(hList, WM_SETREDRAW, TRUE, 0); 
 
   // if there was any error returned by SQLFetch, display it 
   if (nReturn == SQL_ERROR) 
      DisplayError(nReturn, hWndActiveChild, SQL_HANDLE_STMT, hstmt); 
 
   // Close the open result set. 
   // Unbind all bound columns. 
   SQLCloseCursor(hstmt); 
   SQLFreeStmt(hstmt, SQL_UNBIND); 
 
   // restore the cursor to default value 
   SetCursor(hOldCursor); 
} 
 
/* 
    FUNCTION: CloseDatabases() 
    COMMENTS: Go through all open connections (hdbcs) and hstmt(s) 
          and close them one by one. 
*/ 
 
BOOL FAR PASCAL CloseDatabases() 
{ 
   int     nIndex;                 // index 
   int     nCount;                 // # of connected hdbc(s) 
   char    szBuffer[MAXBUFLEN+1];  // display string buffer 
   HWND    hWndChild;              // MDI Child Window 
   SQLHDBC hdbc1;                  // hdbc value in the hdbc(s) combobox 
   SQLHDBC hdbc2;                  // hdbc value in the MDI Child window title 
 
   // get count of connected hdbc(s) from the hdbc(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 hdbc, 
   // find the matching MDI child window and ask it for closure, thereby 
   // freeing the associated hstmt (see CloseQueryWindow). Once all 
   // associated hstmt(s) are freed, free the hdbc 
   for (nIndex = 0; nIndex < nCount; nIndex++) { 
      // scan current indexed hdbc from hdbc(s) combobox 
      SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer); 
      sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc1); 
 
      // 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, ODBCMDICLASS)) { 
            GetWindowText(hWndChild, szBuffer, MAXBUFLEN); 
            sscanf(szBuffer, SCANHDBC_TITLEFORMAT, &hdbc2); 
            if (hdbc1 == hdbc2) { 
               // destroy the window and restart search 
               SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0); 
               hWndTemp = GetWindow(hWndMDIClient, GW_CHILD); 
            } 
         } 
         hWndChild = hWndTemp; 
      } 
 
      // call SQLDisconnect and SQLFreeConnect to disconnect and 
      // free the curren hdbc resource 
      SQLDisconnect(hdbc1); 
      SQLFreeHandle(SQL_HANDLE_DBC,hdbc1); 
   } 
 
   // reset the hdbc(s) combobox display and display all connections 
   // closed message. return success to let application exit. 
   SendMessage(hWndCrsrList, CB_RESETCONTENT, 0, 0); 
   MessageBox(hWndFrame, CLOSEALLHDBC, LOGOUTINFO,  MB_OK | MB_ICONINFORMATION); 
   return (TRUE); 
} 
 
/* 
    FUNCTION: FreeSQLEnvironment() 
    COMMENTS: Free the ODBC environment. 
*/ 
 
BOOL FAR PASCAL FreeSQLEnvironment() 
{ 
   // Free up all ODBC related resources 
   return (SQLFreeHandle(SQL_HANDLE_ENV,henv) == SQL_SUCCESS); 
} 
 
/* 
    FUNCTION: DisplayError(SQLRETURN nResult, HWND hWnd, SWORD fHandleType, SQLHANDLE handle) 
    COMMENTS: Format and display errors or warnings. 
*/ 
 
void FAR PASCAL DisplayError(SQLRETURN nResult, HWND hWnd, SWORD fHandleType, SQLHANDLE handle) 
{ 
   UCHAR    szErrState[SQL_SQLSTATE_SIZE+1];    // SQL Error State string 
   UCHAR    szErrText[SQL_MAX_MESSAGE_LENGTH+1];    // SQL Error Text string 
   char szBuffer[SQL_SQLSTATE_SIZE+SQL_MAX_MESSAGE_LENGTH+MAXBUFLEN+1]; 
   // formatted Error text Buffer 
   SWORD    wErrMsgLen;             // Error message length 
   UDWORD   dwErrCode;              // Native Error code 
   int  iSize;                      // Display Error Text size 
   SQLRETURN  nErrResult;             // Return Code from SQLGetDiagRec 
   SWORD sMsgNum = 1; 
   SWORD fFirstRun = TRUE; 
 
   szBuffer[0] = '\0'; 
 
   do 
      { 
         // continue to bring messageboxes till all errors are displayed. 
         // more than one message box may be reqd. as err text has fixed 
         // string size. 
 
         // initialize display buffer with the string in error text buffer 
         strcpy(szDispBuffer, szBuffer); 
 
         // call SQLGetDiagRec function with proper ODBC handles, repeatedly until 
         // function returns SQL_NO_DATA. Concatenate all error strings 
         // in the display buffer and display all results. 
         while ((nErrResult = SQLGetDiagRec(fHandleType, handle, sMsgNum++, 
                                            szErrState, &dwErrCode, szErrText, 
                                            SQL_MAX_MESSAGE_LENGTH-1, &wErrMsgLen)) 
                != SQL_NO_DATA) { 
 
 
if(nErrResult == SQL_ERROR || nErrResult == SQL_INVALID_HANDLE) 
break; 
 
            wsprintf(szBuffer, SQLERR_FORMAT, (LPSTR)szErrState, dwErrCode, (LPSTR)szErrText); 
            iSize = strlen(szDispBuffer); 
            if (iSize && (iSize+strlen(szBuffer)+1) >= MAXDISPLAYSIZE) 
               break; 
            if (iSize) 
               strcat(szDispBuffer, "\n"); 
            strcat(szDispBuffer, szBuffer); 
         } 
 
         // display proper ERROR or WARNING message with proper title 
 
         if (nResult == SQL_SUCCESS_WITH_INFO) 
            MessageBox(hWnd, szDispBuffer, (fFirstRun? SQLWRNMSGTITLE : SQLWRNCNTDTITLE), 
                       MB_OK | MB_ICONINFORMATION); 
         else 
            MessageBox(hWnd, szDispBuffer, (fFirstRun? SQLERRMSGTITLE : SQLERRCNTDTITLE), 
                       MB_OK | MB_ICONEXCLAMATION); 
 
         if (fFirstRun) 
            fFirstRun = FALSE; 
      } 
   while (!(nErrResult == SQL_NO_DATA || nErrResult == SQL_ERROR || nErrResult == SQL_INVALID_HANDLE)); 
} 
/********************************************* END OF FILE **************************************************/