home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / odbc / qurydemo / query.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-06  |  44.9 KB  |  1,077 lines

  1. /*
  2.     PROGRAM: QURYDEMO
  3.     ========
  4.  
  5.     PURPOSE:
  6.     ========
  7.     demonstrates a simple MDI (Multiple Document Interface)application
  8.     that allows a user to simultaneously connect to multiple
  9.     hetrogeneous databases and perform SQL queries to get results.
  10.  
  11.     FUNCTIONS:
  12.     ==========
  13.     InitSQLEnvironment() - Initialize ODBC library
  14.     DisplayDatabases() - Display available Data Sources
  15.     ConnectDatabase() - Connect to a specific data source
  16.     DriverConnectDatabase() - Connect through driver specific dialogs
  17.     DisplayConnections() - Display List of made connections
  18.     DisplayQueries() - Display list of Query Handles (hstmts)
  19.     NewQueryWindow() - Open a new hstmt and update displays
  20.     ChangeCurrentCursor() - Change current cursor display
  21.     ChangeCurrentQuery() - Change current query display
  22.     DisplayNewCrsrAndStmt() - update cusor & query displays
  23.     FreeConnect() - free a connection
  24.     FreeQuery() - free a query handle
  25.     CloseQueryWindow() - close a query window
  26.     ExecuteQuery() - execute a user specified query
  27.     CloseDatabases() - check if all connections are closed
  28.     FreeSQLEnvironment() - free ODBC library
  29.     DisplayError() - displays SQL Error and Warnings
  30.  
  31.     COMMENTS:
  32.     =========
  33.     Created by Microsoft Corporation.
  34.  
  35.     The application uses MDI Child Window Titles to store values of
  36.     connected SQLHDBCs and SQLHSTMTs. These values are also stored in the
  37.     comboboxes that are displayed on the toolbar.
  38.  
  39. */
  40.  
  41. #include <stdio.h>
  42. #include <string.h>
  43.  
  44. #include <windows.h>
  45.  
  46. #include "sql.h"
  47. #include "sqlext.h"
  48. #include "qurydemo.h"
  49.  
  50. /*
  51.     FUNCTION: InitSQLEnvironment()
  52.     COMMENTS: Allocate an environment handle for ODBC function calls.
  53. */
  54.  
  55. BOOL FAR PASCAL InitSQLEnvironment()
  56. {
  57.    // reset child window count
  58.    nChildCount = 0;
  59.  
  60.    // Allocate an Environment Handle
  61.    if (SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv) != SQL_SUCCESS)
  62.       return FALSE;
  63.  
  64.    return (SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
  65.                          (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER) == SQL_SUCCESS);
  66. }
  67.  
  68. /*
  69.     FUNCTION: DisplayDatabases(HWND hWnd)
  70.     COMMENTS: Display a list of available data sources. Use
  71.           SQLDataSources function call.
  72. */
  73.  
  74. void FAR PASCAL DisplayDatabases(HWND hWnd)
  75. {
  76.    SWORD     nDirection;                             //fetch direction
  77.    SWORD     nDataSourceNameLength;                  //DSN str length
  78.    SWORD     nSourceDescriptionLength;               //Driver Description str length
  79.    char      szDataSourceName[MAXBUFLEN+1];          //DSN string
  80.    char      szSourceDescription[MAXBUFLEN+1];       //Driver Description string
  81.    SQLRETURN nResult;                                //Return Code
  82.  
  83.    //Call SQLDataSources, first with SQL_FETCH_FIRST and from then on
  84.    //with SQL_FETCH_NEXT until it returns SQL_NO_DATA. Add
  85.    //all returned DSNs in the provided combo box for display.
  86.    SendMessage(hWnd, CB_RESETCONTENT, 0, 0);
  87.    for (nDirection = SQL_FETCH_FIRST;
  88.         (nResult = SQLDataSources(henv, nDirection, szDataSourceName, MAXBUFLEN,
  89.                                   &nDataSourceNameLength, szSourceDescription, MAXBUFLEN, &nSourceDescriptionLength)) !=
  90.         SQL_NO_DATA &&
  91.         nResult != SQL_ERROR;
  92.         nDirection = SQL_FETCH_NEXT
  93.         )
  94.       SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szDataSourceName);
  95.    SendMessage(hWnd, CB_SETCURSEL, 0, 0);
  96. }
  97.  
  98. /*
  99.     FUNCTION: ConnectDatabase(HWND hWnd)
  100.     COMMENTS: Connect to a DSN.
  101. */
  102.  
  103. BOOL FAR PASCAL ConnectDatabase(HWND hWnd)
  104. {
  105.    char      szBuffer[MAXBUFLEN+1];  // buffer to display successful connection on hdbc combo-box
  106.    char      szDBName[MAXBUFLEN+1];  // DSN sting
  107.    char      szUserName[MAXBUFLEN+1];// User name
  108.    char      szPassword[MAXBUFLEN+1];// Password
  109.    SQLHDBC   hdbc;                   // hdbc
  110.    SQLRETURN nResult;                // Result code
  111.  
  112.    // check if enough windows are already open, refuse connection
  113.  
  114.    if (nChildCount >= MAXCHILDWNDS) {
  115.       MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND);
  116.       return (FALSE);
  117.    }
  118.  
  119.  
  120.    // retrieve DSN, UID and PWD values from the connect dialog box
  121.  
  122.    GetDlgItemText(hWnd, IDCOMBO_DATASOURCE, szDBName, MAXBUFLEN);
  123.    GetDlgItemText(hWnd, IDTEXT_USERNAME, szUserName, MAXBUFLEN);
  124.    GetDlgItemText(hWnd, IDTEXT_PASSWORD, szPassword, MAXBUFLEN);
  125.  
  126.    // Allocate a new SQLHDBC. If successful then call SQLConnect using the
  127.    // allocated hdbc and supplied connection information.
  128.    if ((nResult = SQLAllocHandle(SQL_HANDLE_DBC,henv, (SQLHDBC FAR *)&hdbc)) != SQL_SUCCESS) {
  129.       DisplayError(nResult, hWnd, SQL_HANDLE_ENV, henv);
  130.       return (FALSE);
  131.    }
  132.  
  133.    nResult = SQLConnect(hdbc,(LPSTR)szDBName,SQL_NTS,(LPSTR)szUserName,SQL_NTS,(LPSTR)szPassword,SQL_NTS);
  134.  
  135.    // if failed to connect, free the allocated hdbc before return
  136.    if (nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO) {
  137.       DisplayError(nResult, hWnd, SQL_HANDLE_DBC, hdbc);
  138.       SQLFreeHandle(SQL_HANDLE_DBC,hdbc);
  139.       return (FALSE);
  140.    }
  141.  
  142.    // display any connection information if driver returns SQL_SUCCESS_WITH_INFO
  143.    if (nResult == SQL_SUCCESS_WITH_INFO)
  144.       DisplayError(nResult, hWnd, SQL_HANDLE_DBC, hdbc);
  145.  
  146.    // update the hdbc(s) combo-box and create a new hstmt and its
  147.    // associated window.
  148.    wsprintf(szBuffer, DSN_HDBC_FORMAT, (LPSTR)szDBName, hdbc);
  149.    nResult = (UINT)SendMessage(hWndCrsrList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  150.    SendMessage(hWndCrsrList, CB_SETCURSEL, (WPARAM)nResult, 0);
  151.    SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  152.    ChangeCurrentCursor(hWndCrsrList);
  153.    NewQueryWindow();
  154.    return (TRUE);
  155. }
  156.  
  157. /*
  158.     FUNCTION: DriverConnectDatabase(HWND hWnd)
  159.     COMMENTS: Connect to a DSN using SQLDriverConnect function call. It
  160.           allows driver manager and drivers to interact with the user
  161.           directly to prompt for connection information.
  162. */
  163.  
  164. BOOL FAR PASCAL DriverConnectDatabase(HWND hWnd)
  165. {
  166.    char      szBuffer[MAXBUFLEN+1];  //display successful connection info on hdbc(s) combo-box
  167.    char      szDBName[MAXBUFLEN+1];  //DSN string
  168.    SWORD     swStrLen;               //String length
  169.    SQLHDBC   hdbc;                   //hdbc
  170.    SQLRETURN nResult;                //result code
  171.  
  172.    // Allocate a new Connection Handle.
  173.    if ((nResult = SQLAllocHandle(SQL_HANDLE_DBC,henv, (SQLHDBC FAR *)&hdbc)) != SQL_SUCCESS) {
  174.       DisplayError(nResult, hWnd, SQL_HANDLE_ENV, henv);
  175.       return (FALSE);
  176.    }
  177.  
  178.    // Call SQLDriverConnect to make a connection request. Provide SQL_DRIVER_COMPLETE_REQUIRED
  179.    // flag sothat driver manager and driver can ask for connection information
  180.    // If failed to connect, free the allocated hdbc in previous step.
  181.    nResult = SQLDriverConnect(hdbc, hWnd, "", 0, szBuffer,  MAXBUFLEN, &swStrLen, SQL_DRIVER_COMPLETE_REQUIRED);
  182.     
  183.  
  184.    if (nResult != SQL_SUCCESS && nResult != SQL_SUCCESS_WITH_INFO) {
  185.       SQLFreeHandle(SQL_HANDLE_DBC,hdbc);
  186.       return (FALSE);
  187.    }
  188.  
  189.    // If driver returns additional information with SQL_SUCCESS_WITH_INFO
  190.    // flag, display the information
  191.    if (nResult == SQL_SUCCESS_WITH_INFO)
  192.       DisplayError(nResult, hWnd, SQL_HANDLE_DBC, hdbc);
  193.  
  194.    // Call SQLGetInfo to find out the DSN name for the above connection.
  195.    // Note, application should not depend upon the DSN name being present
  196.    // in the returned connection string.
  197.    strcpy(szDBName, DEFDBNAME); // initialize the string value
  198.  
  199.  
  200.    SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, (PTR)szDBName, MAXBUFLEN+1, &swStrLen);
  201.     if( !*szDBName)
  202.         strcpy(szDBName,"nameless");
  203.  
  204.    // Display the new connection information in the hdbc(s) combo-box.
  205.    // Create a new hstmt and its associated window.
  206.    wsprintf(szBuffer, DSN_HDBC_FORMAT, (LPSTR)szDBName, hdbc);
  207.    nResult = (UINT)SendMessage(hWndCrsrList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  208.    SendMessage(hWndCrsrList, CB_SETCURSEL, (WPARAM)nResult, 0);
  209.    SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  210.    ChangeCurrentCursor(hWndCrsrList);
  211.    NewQueryWindow();
  212.    return (TRUE);
  213. }
  214.  
  215. /*
  216.     FUNCTION: DisplayConnections(HWND hWndhdbc)
  217.     COMMENTS: Display list of available hdbc(s) in the given list box.
  218. */
  219.  
  220. void FAR PASCAL DisplayConnections(HWND hWndhdbc)
  221. {
  222.    int  nConnects;      // # of connections
  223.    int  nIndex;                 // counter
  224.    char szBuffer[MAXBUFLEN+1];  // string buffer
  225.  
  226.    // read the information from the hdbc(s) combo-box in the tool bar
  227.    // and feed it in the given list box.
  228.  
  229.    SendMessage(hWndhdbc, LB_RESETCONTENT, 0, 0);
  230.    nConnects = (int) SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0);
  231.    for (nIndex = 0; nIndex < nConnects; nIndex++) {
  232.       SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  233.       SendMessage(hWndhdbc, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  234.    }
  235.    SendMessage(hWndhdbc, LB_SETCURSEL, 0, 0);
  236. }
  237.  
  238. /*
  239.     FUNCTION: DisplayQueries(HWND hWndhstmt int nCrsrIndex)
  240.     COMMENTS: Display list of hstmt(s) for the currently selected hdbc
  241.           in the given listbox.
  242. */
  243.  
  244. void FAR PASCAL DisplayQueries(HWND hWndhstmt, HWND hWndhdbc, int nCrsrIndex)
  245. {
  246.    char  szBuffer[MAXBUFLEN+1];  // MDI child window title
  247.    HWND  hWndChild;              // MDI child window handle
  248.    SQLHDBC  hdbc1;               // hdbc in the window title
  249.    SQLHDBC  hdbc2;               // selected hdbc in the list box
  250.    SQLHSTMT hstmt;               // hstmt in the window title
  251.  
  252.    // reset the hstmt list box in the disconnect dialog box
  253.  
  254.    SendMessage(hWndhstmt, LB_RESETCONTENT, 0, 0);
  255.  
  256.    // go through all available MDI child windows and check if the
  257.    // hdbc in the title matches the one selected in the list box.
  258.    // if they match, use the hstmt in the window title to create
  259.    // a new entry in the hstmt(s) list box.
  260.  
  261.    for (hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) {
  262.       // Class name check is necessary as some of MDI child
  263.       // windows may be iconized by the user and MDIClient
  264.       // in such cases create additional windows (such as
  265.       // icon titles).
  266.  
  267.       GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  268.       if (strcmp(szBuffer, ODBCMDICLASS))
  269.          continue;
  270.  
  271.       GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  272.       sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc1, &hstmt);
  273.  
  274.       SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nCrsrIndex, (LPARAM)(LPSTR)szBuffer);
  275.       sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc2);
  276.  
  277.       if (hdbc1 != hdbc2)
  278.          continue;
  279.  
  280.       wsprintf(szBuffer, ((hWndChild == hWndActiveChild) ?  CURQUERY_STRING:    QUERY_STRING), hstmt);
  281.       SendMessage(hWndhstmt, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  282.    }
  283.    SendMessage(hWndhstmt, LB_SETSEL, TRUE, 0);
  284. }
  285.  
  286. /*
  287.     FUNCTION: NewQueryWindow()
  288.     COMMENTS: Create a new hstmt on current hdbc and its associated window
  289. */
  290.  
  291. void FAR PASCAL NewQueryWindow()
  292. {
  293.    int              nCurrenthdbc;           // current selection in the hdbc combobox
  294.    char             szBuffer[MAXBUFLEN+1];  // string in the hdbc combobox on the toolbar
  295.    char             szDBName[MAXBUFLEN+1];  // DSN string
  296.    SQLHDBC          hdbc;                   // hdbc value in the combobox
  297.    SQLHSTMT         hstmt;                  // hstmt
  298.    MDICREATESTRUCT  mcs;                    // MDI child window create structure
  299.    SQLRETURN        nResult;                // Result code
  300.  
  301.    szDBName[0]='\0';
  302.     szBuffer[0]= '\0';
  303.     
  304.     // check if there is hdbc selected in the combobox
  305.  
  306.     if ((nCurrenthdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0)) == CB_ERR) {
  307.       MessageBox(hWndFrame, MAKECONNECT, NOHDBCERROR, MB_OK | MB_ICONHAND);
  308.       return;
  309.    }
  310.  
  311.    // check if the number of windows exceeds MAXCHILDWNDS
  312.  
  313.    if (nChildCount >= MAXCHILDWNDS) {
  314.       MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND);
  315.       return;
  316.    }
  317.  
  318.    // Scan DSN string and hdbc value from the combo-box
  319.    SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nCurrenthdbc, (LPARAM)(LPSTR)szBuffer);
  320.    sscanf(szBuffer, SCANDSNHDBC_FORMAT, szDBName, &hdbc);
  321.  
  322.  
  323.    // Allocate a new Statement Handle on the scanned hdbc
  324.    if ((nResult = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt)) != SQL_SUCCESS) {
  325.       DisplayError(nResult, hWndFrame, SQL_HANDLE_DBC, hdbc);
  326.       return;
  327.    }
  328.  
  329.    // create a new MDI client window. maximized, if the previous is so.
  330.    mcs.szClass = ODBCMDICLASS;
  331.    mcs.szTitle = UNTITLED;
  332.    mcs.hOwner  = hAppInstance;
  333.    mcs.style   = hWndActiveChild && IsZoomed(hWndActiveChild) ? WS_MAXIMIZE : 0;
  334.    mcs.x = mcs.cx = mcs.y = mcs.cy = CW_USEDEFAULT;
  335.    hWndActiveChild = (HWND)(UINT)SendMessage(hWndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mcs);
  336.  
  337.    // check if it was created, if it wasn't free up resource and flag warning
  338.    if (!hWndActiveChild) {
  339.       MessageBox(hWndFrame, CREATECHILDERR, EXECERROR, MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
  340.       SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
  341.       return;
  342.    }
  343.  
  344.    // display the DSN string, SQLHDBC and SQLHSTMT in the title of newly
  345.    // created window. Increment the child window counter
  346.    wsprintf(szBuffer, QUERY_STRING, hstmt);
  347.    SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  348.    SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  349.    wsprintf(szBuffer, DSN_HDBC_HSTMT_FORMAT, (LPSTR)szDBName, hdbc, hstmt);
  350.    SetWindowText(hWndActiveChild, szBuffer);
  351.    nChildCount++;
  352.  
  353.    // update the hstmt(s) combo-box in the tool bar.
  354.    ChangeCurrentQuery(hWndStmtList);
  355. }
  356.  
  357. /*
  358.     FUNCTION: ChangeCurrentCursor(HWND hWndCrsrList)
  359.     COMMENTS: Change the displayed hdbc in the hdbc(s) combobox
  360.           Also activate the appropriate MDI child window that
  361.           has the same hdbc as the new hdbc in the combobox.
  362. */
  363.  
  364. void FAR PASCAL ChangeCurrentCursor(HWND hWndCrsrList)
  365. {
  366.    int      nNewhdbc;               //new hdbc position
  367.    int      nConnects;              //# of connections
  368.    int      nIndex;                 //counter
  369.    char     szBuffer[MAXBUFLEN+1];  //string buffer
  370.    BOOL     bChangedFocus;          //Activate a different MDI child?
  371.    HWND     hWndChild;              //MDI Child window
  372.    SQLHDBC  hdbc1;                  //hdbc in the window title
  373.    SQLHDBC  hdbc2;                  //hdbc in the combobox
  374.    SQLHSTMT hstmt;                  //hstmt in the window title
  375.  
  376.    // check to see if the current selection in the combo-box
  377.    // differs from the previous selection, if it is the same then
  378.    // simply return. Check is made by searching a marked string
  379.    // in the hdbc(s) combobox.
  380.    nNewhdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0);
  381.    nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0);
  382.  
  383.    for(nIndex = 0; nIndex < nConnects; nIndex++) {
  384.       SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  385.       if (strstr(szBuffer, CUR_MARK))
  386.          break;
  387.    }
  388.  
  389.    if (nIndex == nNewhdbc)
  390.       return;
  391.  
  392.    // if there was a current marked hdbc in the combobox, remove the
  393.    // mark from the string and replace it in the combobox.
  394.    if (nIndex != nConnects) {
  395.       SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  396.       szBuffer[strlen(szBuffer)-2] = '\0';
  397.       SendMessage(hWndCrsrList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer);
  398.       SendMessage(hWndCrsrList, CB_DELETESTRING, nIndex+1, 0);
  399.    }
  400.  
  401.    // Create a new marked string with currently selected hdbc string in
  402.    // the combobox and replace it with the original.
  403.    SendMessage(hWndCrsrList, CB_GETLBTEXT, nNewhdbc, (LPARAM)(LPSTR)szBuffer);
  404.    strcat(szBuffer, CUR_MARK);
  405.    SendMessage(hWndCrsrList, CB_INSERTSTRING, nNewhdbc, (LPARAM)(LPSTR)szBuffer);
  406.    SendMessage(hWndCrsrList, CB_DELETESTRING, nNewhdbc+1, 0);
  407.    SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  408.  
  409.    // reset the hstmt(s) combobox. Search through the MDI child windows
  410.    // and collect all hstmt(s) from window titles that have the same
  411.    // hdbc value as the newly selected hdbc in the hdbc(s) combo-box above.
  412.    SendMessage(hWndStmtList, CB_RESETCONTENT, 0, 0);
  413.    for (bChangedFocus=FALSE, hWndChild=GetWindow(hWndMDIClient, GW_CHILD);  hWndChild; hWndChild = GetWindow(
  414.                                                                                                              hWndChild, GW_HWNDNEXT)) {
  415.       // check class name to skip iconized titles or other
  416.       // such non MDI Child windows
  417.       GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  418.       if (strcmp(szBuffer, ODBCMDICLASS))
  419.          continue;
  420.  
  421.       GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  422.       sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc1, &hstmt);
  423.  
  424.       SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nNewhdbc, (LPARAM)(LPSTR)szBuffer);
  425.       sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc2);
  426.  
  427.       if (hdbc1 != hdbc2)
  428.          continue;
  429.  
  430.       if (!bChangedFocus) {
  431.          // If the first match is found, change the active window
  432.          // and update the hstmt(s) combobox with a new entry that
  433.          // has hstmt marked with current marker.
  434.          bChangedFocus = TRUE;
  435.          hWndActiveChild = hWndChild;
  436.          SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0);
  437.          wsprintf(szBuffer, CURQUERY_STRING, hstmt);
  438.          SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  439.          SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  440.       }
  441.       else {
  442.          // simply add the hstmt in the hstmt(s) combobox.
  443.          wsprintf(szBuffer, QUERY_STRING, hstmt);
  444.          SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  445.       }
  446.    }
  447. }
  448.  
  449. /*
  450.     FUNCTION: ChangeCurrentQuery(HWND hWndStmtList)
  451.     COMMENTS: Change the current selection in the hstmt(s) combobox.
  452.           Update the current marker in the combobox and activate
  453.           proper MDI Child window.
  454. */
  455.  
  456. void FAR PASCAL ChangeCurrentQuery(HWND hWndStmtList)
  457. {
  458.    int      nNewhstmt;              //new selection in combobox
  459.    int      nStmts;                 //# of hstmts
  460.    int      nIndex;                 //counter
  461.    char     szBuffer[MAXBUFLEN+1];  //string buffer to update displays
  462.    HWND     hWndChild;              //MDI child window handle
  463.    SQLHDBC  hdbc1 = NULL;                  //hdbc in hdbc(s) combobox
  464.    SQLHDBC  hdbc2 = NULL;                  //hdbc in child window title
  465.    SQLHSTMT hstmt1 = NULL;                 //newly selected hstmt
  466.    SQLHSTMT hstmt2 = NULL;                 //hstmt in child window title
  467.  
  468.    // find the index of new selection and total number of hstmt(s)
  469.    nNewhstmt = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0);
  470.    nStmts = (int)SendMessage(hWndStmtList, CB_GETCOUNT, 0, 0);
  471.  
  472.    // check if the current selection is same as previous one, if
  473.    // so simply return. Check for marker to determine previous selection
  474.    for(nIndex = 0; nIndex < nStmts; nIndex++) {
  475.       SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  476.       if (strstr(szBuffer, CUR_MARK))
  477.          break;
  478.    }
  479.  
  480.    if (nIndex == nNewhstmt)
  481.       return;
  482.  
  483.    // if a previous selection was found, remove current marker
  484.    // and update it in the hstmt(s) combobox.
  485.    if (nIndex != nStmts) {
  486.       SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  487.       szBuffer[strlen(szBuffer)-2] = '\0';
  488.       SendMessage(hWndStmtList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer);
  489.       SendMessage(hWndStmtList, CB_DELETESTRING, nIndex+1, 0);
  490.    }
  491.  
  492.    // mark the current selection and update it in the hstmt(s) combobox
  493.    SendMessage(hWndStmtList, CB_GETLBTEXT, nNewhstmt, (LPARAM)(LPSTR)szBuffer);
  494.    strcat(szBuffer, CUR_MARK);
  495.    SendMessage(hWndStmtList, CB_INSERTSTRING, nNewhstmt, (LPARAM)(LPSTR)szBuffer);
  496.    SendMessage(hWndStmtList, CB_DELETESTRING, nNewhstmt+1, 0);
  497.    SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  498.  
  499.    // scan hstmt value and hdbc value from current selection in
  500.    // hdbc(s) and hstmt(s) comboboxes.
  501.    sscanf(szBuffer, QUERY_STRING, &hstmt1);
  502.  
  503.    SendMessage(hWndCrsrList, CB_GETLBTEXT, (UINT)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0),
  504.                (LPARAM)(LPSTR)szBuffer);
  505.    sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc1);
  506.     
  507.  
  508.    // go through list of MDI Child windows and match the hstmt and hdbc
  509.    // values. If a match if found (must be), activate the window
  510.    for (hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) {
  511.       // ignore non MDI child windows
  512.       GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  513.       if (strcmp(szBuffer, ODBCMDICLASS))
  514.          continue;
  515.  
  516.       GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  517.       sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc2, &hstmt2);
  518.  
  519.       if (hdbc1 == hdbc2 && hstmt1 == hstmt2) {
  520.          hWndActiveChild = hWndChild;
  521.          SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0);
  522.          break;
  523.       }
  524.    }
  525. }
  526.  
  527. /*
  528.     FUNCTION: DisplayNewCrsrAndStmt()
  529.     COMMENTS: If user changes currently active MDI Child Window, both
  530.           hstmt(s) and hdbc(s) comboboxes need to be updated to
  531.           reflect currently selected MDI child. match the hstmt and
  532.           hdbc value in the title of MDI child to those on display
  533.           in hstmt(s) and hdbc(s) comboboxes respectively.
  534. */
  535.  
  536. void FAR PASCAL DisplayNewCrsrAndStmt()
  537. {
  538.    int      nConnects;              // # of hdbc(s)
  539.    int      nStmts;                 // # of hstmt(s)
  540.    int      nOldhdbc;               // prev selection in hdbc combobox
  541.    int      nOldhstmt;              // prev selection in hstmt combobox
  542.    int      nIndex;                 // counter
  543.    char     szBuffer[MAXBUFLEN+1];  // display buffer
  544.    HWND     hWndChild;              // MDI Child window
  545.    SQLHDBC  hdbc1;                  // hdbc in window title
  546.    SQLHDBC  hdbc2;                  // hdbc in hdbc(s) combobox
  547.    SQLHSTMT hstmt1;                 // hstmt in window title
  548.    SQLHSTMT hstmt2;                 // hstmt in hstmt(s) combobox
  549.  
  550.    // scan hdbc and hstmt values from newly selected window
  551.    GetWindowText(hWndActiveChild, szBuffer, MAXBUFLEN);
  552.    sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc1, &hstmt1);
  553.  
  554.    // search through list of hdbc(s) in hdbc combobox and find
  555.    // matching hdbc. remove marker from prev selection and add
  556.    // marker to the new selection. update combobox accordingly.
  557.    nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0);
  558.    nOldhdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0);
  559.  
  560.    for(hdbc2 = (SQLHDBC)(nIndex = 0); hdbc1 != hdbc2; nIndex++) {
  561.       SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  562.       sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc2);
  563.    }
  564.  
  565.    if (--nIndex != nOldhdbc) // change in hdbc combobox required.
  566.       {
  567.          SendMessage(hWndCrsrList, CB_GETLBTEXT, nOldhdbc, (LPARAM)(LPSTR)szBuffer);
  568.          szBuffer[strlen(szBuffer)-2] = '\0';
  569.          SendMessage(hWndCrsrList, CB_INSERTSTRING, nOldhdbc, (LPARAM)(LPSTR)szBuffer);
  570.          SendMessage(hWndCrsrList, CB_DELETESTRING, nOldhdbc+1, 0);
  571.  
  572.          SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  573.          strcat(szBuffer, CUR_MARK);
  574.          SendMessage(hWndCrsrList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer);
  575.          SendMessage(hWndCrsrList, CB_DELETESTRING, nIndex+1, 0);
  576.          SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  577.  
  578.          // reset the hstmt(s) combobox, search through the list
  579.          // of MDI child windows and find all hstmt(s) associated to
  580.          // new hdbc. Build the new list of hstmt(s) for the hstmt
  581.          // combobox. Mark the one hstmt that matches the currently
  582.          // activated MDI child window.
  583.          SendMessage(hWndStmtList, CB_RESETCONTENT, 0, 0);
  584.          for (hWndChild=GetWindow(hWndMDIClient,GW_CHILD);hWndChild;hWndChild=GetWindow(hWndChild,GW_HWNDNEXT)) {
  585.             GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  586.             if (strcmp(szBuffer, ODBCMDICLASS))
  587.                continue;
  588.  
  589.             GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  590.             sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc2, &hstmt2);
  591.  
  592.             if (hdbc1 != hdbc2)
  593.                continue;
  594.  
  595.             if (hWndActiveChild == hWndChild) {
  596.                wsprintf(szBuffer, CURQUERY_STRING, hstmt2);
  597.                SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  598.                SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  599.             }
  600.             else {
  601.                wsprintf(szBuffer, QUERY_STRING, hstmt2);
  602.                SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  603.             }
  604.          }
  605.       }
  606.    else // no change in hdbc combobox required
  607.       {
  608.          // go through the list of hstmt(s) in hstmt combobox.
  609.          // find the one that matches the currently activated MDI
  610.          // child window.
  611.          nOldhstmt = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0);
  612.          nStmts = (int)SendMessage(hWndStmtList, CB_GETCOUNT, 0, 0);
  613.  
  614.          for(hstmt2 = (SQLHDBC)(nIndex = 0); hstmt1 != hstmt2; nIndex++) {
  615.             SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  616.             sscanf(szBuffer, QUERY_STRING, &hstmt2);
  617.          }
  618.  
  619.          if (--nIndex != nOldhstmt) // new index in hstmt differs from previous selection
  620.             {
  621.                // remove the marker from previous selection. Add
  622.                // it to the new string and update the combobox display
  623.                SendMessage(hWndStmtList, CB_GETLBTEXT, nOldhstmt, (LPARAM)(LPSTR)szBuffer);
  624.                szBuffer[strlen(szBuffer)-2] = '\0';
  625.                SendMessage(hWndStmtList, CB_INSERTSTRING, nOldhstmt, (LPARAM)(LPSTR)szBuffer);
  626.                SendMessage(hWndStmtList, CB_DELETESTRING, nOldhstmt+1, 0);
  627.  
  628.                SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  629.                strcat(szBuffer, CUR_MARK);
  630.                SendMessage(hWndStmtList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer);
  631.                SendMessage(hWndStmtList, CB_DELETESTRING, nIndex+1, 0);
  632.                SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  633.             }
  634.       }
  635. }
  636.  
  637. /*
  638.     FUNCTION: FreeConnect(HWND hWndhdbc)
  639.     COMMENTS: Disconnect and Free the currently selected hdbc in
  640.           the hdbc listbox in disconnect dialog. Call SQLDisconnect
  641.           and SQLFreeConnect to free the hdbc. Close all MDI
  642.           child windows associated with this hdbc. That will
  643.           automatically free associated hstmt(s).
  644. */
  645.  
  646. void FAR PASCAL FreeConnect(HWND hWndhdbc)
  647. {
  648.    int     nIndex;                 // current selection in the listbox of disconnect dlg
  649.    int     nCurrent;               // current selection in hdbc(s) combobox
  650.    char    szBuffer[MAXBUFLEN+1];  // display buffer
  651.    char    szSelect[MAXBUFLEN+1];  // original selection in hdbc(s) combobox
  652.    char    szDBName[MAXBUFLEN+1];  // DSN string
  653.    HWND    hWndChild;              // MDI Child window
  654.    SQLHDBC hdbc1 = NULL;                  // hdbc in the list box of disconnect dlg
  655.    SQLHDBC hdbc2 = NULL;                  // hdbc in the MDI child window title
  656.  
  657.    szDBName[0]='\0';
  658.     // check current selection in the list box of disconnect dialog. scan
  659.    // hdbc value from the current selection.
  660.    if ((nIndex = (int)SendMessage(hWndhdbc, LB_GETCURSEL, 0, 0)) == LB_ERR)
  661.       return;
  662.  
  663.    SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer);
  664.    sscanf(szBuffer, SCANDSNHDBC_FORMAT, szDBName, &hdbc1);
  665.     
  666.  
  667.    // go through the list of MDI child windows and find matching hdbc(s)
  668.    // close all children who have the same hdbc value. Closing them
  669.    // automatically frees associated hstmts. see CloseQueryWindow.
  670.    for(hWndChild = GetWindow(hWndMDIClient, GW_CHILD); hWndChild; ) {
  671.       // store next window handle before destroying the currentone
  672.       HWND hWndTemp = GetWindow(hWndChild, GW_HWNDNEXT);
  673.  
  674.       // ignore non MDI child windows
  675.       GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  676.       if (!strcmp(szBuffer, ODBCMDICLASS)) {
  677.          GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  678.          sscanf(szBuffer, SCANHDBC_TITLEFORMAT, &hdbc2);
  679.             
  680.          if (hdbc1 == hdbc2) {
  681.             // destroy the window and restart search
  682.             SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0);
  683.             hWndTemp = GetWindow(hWndMDIClient, GW_CHILD);
  684.          }
  685.       }
  686.       hWndChild = hWndTemp;
  687.    }
  688.  
  689.    // call SQLDisconnect and SQLFreeConnect to disconnect and free hdbc
  690.    SQLDisconnect(hdbc1);
  691.    SQLFreeHandle(SQL_HANDLE_DBC,hdbc1);
  692.  
  693.    // update the hdbc(s) combobox display by removing the deleted hdbc
  694.    // from the list and reselecting the previous selection
  695.    wsprintf(szBuffer, DSN_HDBC_FORMAT, (LPSTR)szDBName, hdbc1);
  696.    nCurrent = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0);
  697.    SendMessage(hWndCrsrList, CB_GETLBTEXT, nCurrent, (LPARAM)(LPSTR)szSelect);
  698.    nIndex = (int)SendMessage(hWndCrsrList, CB_FINDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  699.    SendMessage(hWndCrsrList, CB_DELETESTRING, (WPARAM)nIndex, 0);
  700.    SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szSelect);
  701.  
  702.    // if there is no query window open and the current selected SQLHDBC
  703.    // was deleted, make sure to make the next available SQLHDBC as current
  704.    if (SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) &&
  705.        !GetWindow(hWndMDIClient, GW_CHILD) && (nCurrent == nIndex)) {
  706.       if ((nCurrent = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0))!=CB_ERR)
  707.          return;
  708.       SendMessage(hWndCrsrList, CB_GETLBTEXT, 0, (LPARAM)(LPSTR)szSelect);
  709.       strcat(szSelect, CUR_MARK);
  710.       SendMessage(hWndCrsrList, CB_INSERTSTRING, 0, (LPARAM)(LPSTR)szSelect);
  711.       SendMessage(hWndCrsrList, CB_DELETESTRING, 1, 0);
  712.       SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szSelect);
  713.    }
  714. }
  715.  
  716. /*
  717.     FUNCTION: FreeQuery(HWND hWndhstmt, HWND hWndhdbc, int nIndex)
  718.     COMMENTS: Free a query window based upon current selection in
  719.           hstmt list box in the disconnect dialog.
  720. */
  721.  
  722. void FAR PASCAL FreeQuery(HWND hWndhstmt, HWND hWndhdbc, int nIndex)
  723. {
  724.    char     szBuffer[MAXBUFLEN+1];  // display buffer
  725.    HWND     hWndChild;      // MDI child window
  726.    SQLHDBC  hdbc1;          // hdbc in the hdbc listbox of disconnect dlg
  727.    SQLHDBC  hdbc2;          // hdbc in the MDI child window title
  728.    SQLHSTMT hstmt1;         // hstmt in the hstmt listbox of disconnect dlg
  729.    SQLHSTMT hstmt2;         // hstmt in the MDI child window title
  730.  
  731.    // scan the hstmt and hdbc values from the current selections in
  732.    // respective listboxes of disconnect dialog box.
  733.    SendMessage(hWndhstmt, LB_GETTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  734.    sscanf(szBuffer, QUERY_STRING, &hstmt1);
  735.    SendMessage(hWndhdbc, LB_GETTEXT, (UINT)SendMessage(hWndhdbc, LB_GETCURSEL,  0, 0), (LPARAM)(LPSTR)szBuffer);
  736.    sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc1);
  737.  
  738.    // go through the list of MDI child windows and find matching window
  739.    // that has same values for hdbc and hstmt. Destroy the matching window.
  740.    // that will call CloseQueryWindow and thus free up associated hstmt.
  741.    for(hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT)) {
  742.       // ignore non MDI child windows
  743.       GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  744.       if (strcmp(szBuffer, ODBCMDICLASS))
  745.          continue;
  746.       GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  747.       sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc2, &hstmt2);
  748.       if (hdbc1 == hdbc2 && hstmt1 == hstmt2)
  749.          break;
  750.    }
  751.    SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0);
  752. }
  753.  
  754. /*
  755.     FUNCTION: CloseQueryWindow(HWND hWnd)
  756.     COMMENTS: Close a Query window. Call SQLFreeHandle to free
  757.           associated hstmt.
  758. */
  759.  
  760. void FAR PASCAL CloseQueryWindow(HWND hWnd)
  761. {
  762.    char szBuffer[MAXBUFLEN+1];  // display buffer
  763.    char szSelect[MAXBUFLEN+1];  // current selection in hstmt(s) combobox
  764.    SQLHSTMT hstmt;              // hstmt value in window title
  765.  
  766.    // scan the hstmt value from the window title
  767.    GetWindowText(hWnd, szBuffer, MAXBUFLEN);
  768.    sscanf(szBuffer, SCANHSTMT_TITLEFORMAT, &hstmt);
  769.  
  770.    // Drop the current Statement Handle
  771.    SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
  772.  
  773.    // find the matching hstmt in the hstmt(s) combobox and remove it
  774.    // from the list. Closure of a MDI child window will cause MDIClient
  775.    // to automatically activate a different child window if available.
  776.    // that will automatically refresh the hstmt and hdbc displays. See
  777.    // DisplayNewCrsrAndStmt function.
  778.    wsprintf(szBuffer, QUERY_STRING, hstmt);
  779.    SendMessage(hWndStmtList, CB_GETLBTEXT, (WPARAM)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0), (LPARAM)(LPSTR)szSelect);
  780.    SendMessage(hWndStmtList, CB_DELETESTRING, (WPARAM)SendMessage(hWndStmtList, CB_FINDSTRING, 0,
  781.                                                                   (LPARAM)(LPSTR)szBuffer), 0);
  782.    SendMessage(hWndStmtList, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPSTR)szSelect);
  783.  
  784.    // decrement the child window counter.
  785.    nChildCount--;
  786. }
  787.  
  788. /*
  789.     FUNCTION: ExecuteQuery()
  790.     COMMENTS: Execute the user typed SQL Statements in the currently
  791.           active MDI child window. If successful, then prepare
  792.           the list of results and display it in the child listbox.
  793.           Display errors in the ODBC function(s) failed.
  794. */
  795.  
  796. void FAR PASCAL ExecuteQuery()
  797. {
  798.    char      szBuffer[MAXBUFLEN+1];      // display buffer
  799.    HWND      hList;                      // result listbox handle
  800.    SQLHDBC   hdbc;                       // hdbc
  801.    SQLHSTMT  hstmt;                      // hstmt
  802.    SWORD     nCols = 0;                  // # of result columns
  803.    SWORD     nCount;                     // index
  804.    SWORD     swColType;                  // column data type
  805.    SWORD     swColScale;                 // column scale
  806.    SWORD     swColNull;                  // nullable column ?
  807.    SWORD     swColLength = MAXDATALEN;   // column data length
  808.    DWORD     dwText;                     // tab stop for listbox
  809.    UDWORD    udwColDef;                  // precision on the column
  810.    SQLRETURN nReturn;                    // return code
  811.    HCURSOR   hOldCursor;                 // default cursor handle
  812.    int       nRows;                      // # of result rows
  813.  
  814.    // check if there is an active window available
  815.    if (!hWndActiveChild) {
  816.       MessageBox(hWndFrame, ((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) <=0) ?
  817.                              MAKECONNECT : OPENWINDOW ), NOHSTMTERROR, MB_OK | MB_ICONHAND);
  818.       return;
  819.    }
  820.  
  821.    // change cursor shape to hour glass
  822.    hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));
  823.  
  824.    // initialize column data and column data length arrays
  825.    for (nCount = 0; nCount < MAX_COL; nCount++) {
  826.       dwDataLen[nCount] = 0;
  827.       rgbData[nCount][0] = '\0';
  828.    }
  829.  
  830.    // scan hdbc, hstmt values
  831.    GetWindowText(hWndActiveChild, szBuffer, MAXBUFLEN);
  832.    sscanf(szBuffer, SCANHDBCHSTMT_FORMAT, &hdbc, &hstmt);
  833.  
  834.    // get the user typed SQL
  835.    GetWindowText(GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDTEXT_SQL), szBuffer, MAXBUFLEN);
  836.  
  837.    // execute SQL and process errors if any
  838.    // call SQLExecDirect to execute the SQL statement
  839.    nReturn = SQLExecDirect(hstmt, szBuffer, SQL_NTS);
  840.    if (nReturn != SQL_SUCCESS) {
  841.       DisplayError(nReturn, hWndActiveChild, SQL_HANDLE_STMT, hstmt);
  842.  
  843.       // if the return value was just information, carry on
  844.       if (nReturn != SQL_SUCCESS_WITH_INFO) {
  845.          // Close the open result set.
  846.          SQLCloseCursor(hstmt);
  847.          SetCursor(hOldCursor);
  848.          return;
  849.       }
  850.    }
  851.  
  852.    // call SQLNumResultCols to calculate the number of columns in
  853.    // the result set, if more than the MAX_COL (the array boundary)
  854.    // limit the number to MAX_COL and display truncation warning.
  855.    // if it is 0, the statement probably was a non-SELECT simply return
  856.    nReturn = SQLNumResultCols(hstmt, &nCols);
  857.    if (nCols >= MAX_COL) {
  858.       nCols = MAX_COL;
  859.       wsprintf(szDispBuffer, COLTRUNC_WARNG, MAX_COL);
  860.       MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION);
  861.    }
  862.    else if (nCols == 0) {
  863.       // Close the open result set.
  864.       SQLCloseCursor(hstmt);
  865.       SetCursor(hOldCursor);
  866.       return;
  867.    }
  868.  
  869.    // call SQLBindCol to bind column data array and column data length
  870.    // array to the result set
  871.    for(nCount=0; nCount<nCols; nCount++)
  872.       SQLBindCol(hstmt, (UWORD)(nCount+1), SQL_C_CHAR, rgbData[nCount], MAXDATALEN, &dwDataLen[nCount]);
  873.  
  874.    // reset the display in the list box. Set tabstops to display
  875.    // multiple columns in the list box separated by tabs.
  876.    hList = GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDLIST_RSLT);
  877.  
  878.    SendMessage(hList, LB_RESETCONTENT, 0, 0);
  879.    SendMessage(hList, WM_SETREDRAW, FALSE, 0);
  880.    dwText = LISTTABSTOP;
  881.    SendMessage(hList, LB_SETTABSTOPS, (WPARAM)1, (LPARAM)(LPINT)&dwText);
  882.  
  883.    // call SQLDescribeCol to get description of each column in the
  884.    // result set. Store the column name in the display buffer and
  885.    // make it the first entry in the results list box of the MDI
  886.    // child window.
  887.    for(nCount=1, szDispBuffer[0]='\0'; nCount <= nCols; nCount++) {
  888.       SQLDescribeCol(hstmt, nCount, szBuffer, MAXDATALEN, &swColLength, &swColType, &udwColDef,
  889.                      &swColScale, &swColNull);
  890.       strcat(szDispBuffer, szBuffer);
  891.       dwText = strlen(szDispBuffer);
  892.       szDispBuffer[dwText++] = '\t';
  893.       szDispBuffer[dwText] = '\0';
  894.    }
  895.    if (*szDispBuffer)
  896.       szDispBuffer[strlen(szDispBuffer)-1]='\0';
  897.    SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szDispBuffer);
  898.  
  899.    // call SQLFetch to fetch each row of the result set. Extract data
  900.    // value and store it in the display buffer, separated by tabs.
  901.    // continue until SQLFetch fails.
  902.    for(nRows = 0; (nReturn = SQLFetch(hstmt))==SQL_SUCCESS || nReturn==SQL_SUCCESS_WITH_INFO;) {
  903.       if (nReturn != SQL_SUCCESS)
  904.          DisplayError(nReturn, hWndActiveChild, SQL_HANDLE_STMT, hstmt);
  905.       for(nCount=0, szDispBuffer[0]='\0'; nCount<nCols; nCount++) {
  906.          // check if the column is a null value?
  907.          strcat(szDispBuffer, (dwDataLen[nCount]==SQL_NULL_DATA)?NULLDATASTRING:rgbData[nCount]);
  908.          dwText = strlen(szDispBuffer);
  909.          szDispBuffer[dwText++] = '\t';
  910.          szDispBuffer[dwText] = '\0';
  911.       }
  912.       if (*szDispBuffer)
  913.          szDispBuffer[strlen(szDispBuffer)-1]='\0';
  914.       else
  915.          break;
  916.       SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szDispBuffer);
  917.       if (++nRows == MAX_ROW) {
  918.          wsprintf(szDispBuffer, ROWTRUNC_WARNG, MAX_ROW);
  919.          MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION);
  920.          break;
  921.       }
  922.    }
  923.  
  924.    // set the horizontal scroll extent in the list box and ask for repaint.
  925.    SendMessage(hList, LB_SETHORIZONTALEXTENT, (WPARAM)(nCols*LISTHORZSCROLL+LISTHORZEXT), 0);
  926.    SendMessage(hList, WM_SETREDRAW, TRUE, 0);
  927.  
  928.    // if there was any error returned by SQLFetch, display it
  929.    if (nReturn == SQL_ERROR)
  930.       DisplayError(nReturn, hWndActiveChild, SQL_HANDLE_STMT, hstmt);
  931.  
  932.    // Close the open result set.
  933.    // Unbind all bound columns.
  934.    SQLCloseCursor(hstmt);
  935.    SQLFreeStmt(hstmt, SQL_UNBIND);
  936.  
  937.    // restore the cursor to default value
  938.    SetCursor(hOldCursor);
  939. }
  940.  
  941. /*
  942.     FUNCTION: CloseDatabases()
  943.     COMMENTS: Go through all open connections (hdbcs) and hstmt(s)
  944.           and close them one by one.
  945. */
  946.  
  947. BOOL FAR PASCAL CloseDatabases()
  948. {
  949.    int     nIndex;                 // index
  950.    int     nCount;                 // # of connected hdbc(s)
  951.    char    szBuffer[MAXBUFLEN+1];  // display string buffer
  952.    HWND    hWndChild;              // MDI Child Window
  953.    SQLHDBC hdbc1;                  // hdbc value in the hdbc(s) combobox
  954.    SQLHDBC hdbc2;                  // hdbc value in the MDI Child window title
  955.  
  956.    // get count of connected hdbc(s) from the hdbc(s) combobox on the toolbar
  957.    if (!(nCount = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0)))
  958.       return (TRUE);
  959.  
  960.    // go through all available MDI child windows and for each hdbc,
  961.    // find the matching MDI child window and ask it for closure, thereby
  962.    // freeing the associated hstmt (see CloseQueryWindow). Once all
  963.    // associated hstmt(s) are freed, free the hdbc
  964.    for (nIndex = 0; nIndex < nCount; nIndex++) {
  965.       // scan current indexed hdbc from hdbc(s) combobox
  966.       SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer);
  967.       sscanf(szBuffer, SCANHDBC_FORMAT, &hdbc1);
  968.  
  969.       // search through the list of MDI Child Windows
  970.       for(hWndChild = GetWindow(hWndMDIClient, GW_CHILD); hWndChild; ) {
  971.          // store the next child, before destroying the current
  972.          HWND hWndTemp = GetWindow(hWndChild, GW_HWNDNEXT);
  973.  
  974.          // ignore non MDI child windows
  975.          GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  976.          if (!strcmp(szBuffer, ODBCMDICLASS)) {
  977.             GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  978.             sscanf(szBuffer, SCANHDBC_TITLEFORMAT, &hdbc2);
  979.             if (hdbc1 == hdbc2) {
  980.                // destroy the window and restart search
  981.                SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0);
  982.                hWndTemp = GetWindow(hWndMDIClient, GW_CHILD);
  983.             }
  984.          }
  985.          hWndChild = hWndTemp;
  986.       }
  987.  
  988.       // call SQLDisconnect and SQLFreeConnect to disconnect and
  989.       // free the curren hdbc resource
  990.       SQLDisconnect(hdbc1);
  991.       SQLFreeHandle(SQL_HANDLE_DBC,hdbc1);
  992.    }
  993.  
  994.    // reset the hdbc(s) combobox display and display all connections
  995.    // closed message. return success to let application exit.
  996.    SendMessage(hWndCrsrList, CB_RESETCONTENT, 0, 0);
  997.    MessageBox(hWndFrame, CLOSEALLHDBC, LOGOUTINFO,  MB_OK | MB_ICONINFORMATION);
  998.    return (TRUE);
  999. }
  1000.  
  1001. /*
  1002.     FUNCTION: FreeSQLEnvironment()
  1003.     COMMENTS: Free the ODBC environment.
  1004. */
  1005.  
  1006. BOOL FAR PASCAL FreeSQLEnvironment()
  1007. {
  1008.    // Free up all ODBC related resources
  1009.    return (SQLFreeHandle(SQL_HANDLE_ENV,henv) == SQL_SUCCESS);
  1010. }
  1011.  
  1012. /*
  1013.     FUNCTION: DisplayError(SQLRETURN nResult, HWND hWnd, SWORD fHandleType, SQLHANDLE handle)
  1014.     COMMENTS: Format and display errors or warnings.
  1015. */
  1016.  
  1017. void FAR PASCAL DisplayError(SQLRETURN nResult, HWND hWnd, SWORD fHandleType, SQLHANDLE handle)
  1018. {
  1019.    UCHAR    szErrState[SQL_SQLSTATE_SIZE+1];    // SQL Error State string
  1020.    UCHAR    szErrText[SQL_MAX_MESSAGE_LENGTH+1];    // SQL Error Text string
  1021.    char szBuffer[SQL_SQLSTATE_SIZE+SQL_MAX_MESSAGE_LENGTH+MAXBUFLEN+1];
  1022.    // formatted Error text Buffer
  1023.    SWORD    wErrMsgLen;             // Error message length
  1024.    UDWORD   dwErrCode;              // Native Error code
  1025.    int  iSize;                      // Display Error Text size
  1026.    SQLRETURN  nErrResult;             // Return Code from SQLGetDiagRec
  1027.    SWORD sMsgNum = 1;
  1028.    SWORD fFirstRun = TRUE;
  1029.  
  1030.    szBuffer[0] = '\0';
  1031.  
  1032.    do
  1033.       {
  1034.          // continue to bring messageboxes till all errors are displayed.
  1035.          // more than one message box may be reqd. as err text has fixed
  1036.          // string size.
  1037.  
  1038.          // initialize display buffer with the string in error text buffer
  1039.          strcpy(szDispBuffer, szBuffer);
  1040.  
  1041.          // call SQLGetDiagRec function with proper ODBC handles, repeatedly until
  1042.          // function returns SQL_NO_DATA. Concatenate all error strings
  1043.          // in the display buffer and display all results.
  1044.          while ((nErrResult = SQLGetDiagRec(fHandleType, handle, sMsgNum++,
  1045.                                             szErrState, &dwErrCode, szErrText,
  1046.                                             SQL_MAX_MESSAGE_LENGTH-1, &wErrMsgLen))
  1047.                 != SQL_NO_DATA) {
  1048.  
  1049.                 
  1050.                 if(nErrResult == SQL_ERROR || nErrResult == SQL_INVALID_HANDLE)
  1051.                     break;
  1052.  
  1053.             wsprintf(szBuffer, SQLERR_FORMAT, (LPSTR)szErrState, dwErrCode, (LPSTR)szErrText);
  1054.             iSize = strlen(szDispBuffer);
  1055.             if (iSize && (iSize+strlen(szBuffer)+1) >= MAXDISPLAYSIZE)
  1056.                break;
  1057.             if (iSize)
  1058.                strcat(szDispBuffer, "\n");
  1059.             strcat(szDispBuffer, szBuffer);
  1060.          }
  1061.  
  1062.          // display proper ERROR or WARNING message with proper title
  1063.             
  1064.          if (nResult == SQL_SUCCESS_WITH_INFO)
  1065.             MessageBox(hWnd, szDispBuffer, (fFirstRun? SQLWRNMSGTITLE : SQLWRNCNTDTITLE),
  1066.                        MB_OK | MB_ICONINFORMATION);
  1067.          else
  1068.             MessageBox(hWnd, szDispBuffer, (fFirstRun? SQLERRMSGTITLE : SQLERRCNTDTITLE),
  1069.                        MB_OK | MB_ICONEXCLAMATION);
  1070.  
  1071.          if (fFirstRun)
  1072.             fFirstRun = FALSE;
  1073.       }
  1074.    while (!(nErrResult == SQL_NO_DATA || nErrResult == SQL_ERROR || nErrResult == SQL_INVALID_HANDLE));
  1075. }
  1076. /********************************************* END OF FILE **************************************************/
  1077.