DIALOGS.C
/*-------------------------------------------------------------------------- 
  Dialogs.c -- Cursors dialogs 
 
  Description: 
      This sample is spread across four files, each named for the role 
      the contained functions play.  Each file header contains a brief 
      description of its purpose and the routines it contains. 
 
      DIALOGS.C contains those routines used to display and manage 
      dialogs.  Those functions are: 
 
         AddEditControls - Dynamically create edit controls for UPDATE 
                        dialog 
         AddDlgProc      - Manage add row dialog 
         CenterDialog    - Center a dialog over its parent window 
         DoDialog        - Display a dialog 
         MyCreateDialog - Create a modeless dialog 
         GetEditControls - Retrieve values from dynamically created 
                        edit controls 
         IsMsgWaiting    - Check for waiting messages 
 
         AboutDlgProc    - Manage about box 
         AbsDlgProc      - Manage absolute row number dialog 
         DataDlgProc     - Manage large data display dialog 
         FindDlgProc    - Manager dialog to get text string to find in result set 
         RelDlgProc      - Manage relative row number dialog 
         StmtDlgProc     - Manage SQL statement dialog 
         UpdateDlgProc   - Manage update row dialog 
         SqlTablesDlgProc- handle SQLTables-type request 
         ClassOnCommand - handle a command message 
 
 
  This code is furnished on an as-is basis as part of the ODBC SDK and is 
  intended for example purposes only. 
 
--------------------------------------------------------------------------*/ 
 
// Includes ---------------------------------------------------------------- 
#include "headers.h" 
 
#include    "resource.h" 
#include "crsrdemo.h" 
 
 
 
const char szCREATE[] = "CREATE TABLE %s (id int NOT NULL, name char(31) NOT NULL, C3 int)"; 
const char szDROP[]   = "DROP TABLE %s"; 
const char szINSERT[] = "INSERT INTO %s VALUES (?, '-FakeTable-FakeTable-FakeTable-', NULL)"; 
 
const int   xFIRST = 10; 
const int   cxSEP  = 6; 
const int   cySEP  = 3; 
const int   cxNAME = 35; 
const int   cyNAME = 8; 
const int   cxEDIT = 180; 
const int   cyEDIT = 10; 
 
const DWORD dwDLGSTYLE    = DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU; 
const DWORD dwSTATICSTYLE = WS_CHILD | WS_VISIBLE | SS_RIGHT; 
const DWORD dwEDITSTYLE   = WS_BORDER | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | ES_LEFT; 
 
#define STMTError(x) ODBCError(SQL_NULL_HENV, SQL_NULL_HDBC, lpmtbl->hstmt, (x)) 
 
#define  USERDATA GWL_USERDATA 
 
 
// Types ------------------------------------------------------------------- 
typedef struct tagMTBL {                  // Make table structure 
   SQLHSTMT hstmt;                        //   HSTMT in use 
   SDWORD   i;                            //   Rows inserted 
} MTBL, FAR *LPMTBL; 
 
 
// Prototypes -------------------------------------------------------------- 
void INTFUNC AddEditControls(HWND, LPCHILD); 
void INTFUNC CenterDialog(HWND); 
BOOL INTFUNC GetEditControls(HWND, LPCHILD); 
BOOL INTFUNC IsMsgWaiting(HWND); 
BOOL INTFUNC DlgProcFilter(HWND, UINT, WPARAM, LPARAM); 
 
 
/* AddEditControls --------------------------------------------------------- 
   Description: Add one edit control for each updateable bound column to 
                the dialog box 
                --------------------------------------------------------------------------*/ 
void INTFUNC AddEditControls(HWND hDlg, LPCHILD lpChild) 
{ 
#define DLGX(x)   (((x) * LOWORD(dwBaseUnits)) / 4) 
#define DLGY(y)   (((y) * HIWORD(dwBaseUnits)) / 8) 
 
   HWND  hWnd; 
   HFONT hfont; 
   RECT  rc; 
   LPCOL lpcol; 
   char  sz[cbMAXSQL]; 
   char  szFmt[cbSTRLEN]; 
   DWORD dwBaseUnits; 
   UINT  idName, idEdit; 
   int      xName, yName; 
   int      cxName, cyName; 
   int      xEdit, yEdit; 
   int      cxEdit, cyEdit; 
   int      i; 
   HDC   hdc; 
   SIZE  size; 
 
   // Determine basic characteristics and start position in dialog 
   hfont = (HFONT)SendDlgItemMessage(hDlg, IDC_STATIC1, 
                                     WM_GETFONT, 0, 0L); 
 
   dwBaseUnits = GetDialogBaseUnits(); 
 
   cxName = DLGX(cxNAME); 
   cyName = DLGY(cyNAME); 
   cxEdit = DLGX(cxEDIT); 
   cyEdit = DLGY(cyEDIT); 
 
   LoadString(g_hinst, IDS_COLNAME, szFmt, sizeof(szFmt)); 
 
   // Calculate the size of the largest name label 
 
   hdc = GetDC(NULL); 
 
   if( hdc ) { 
      for( i = 0, lpcol = lpChild->lpcol; i < lpChild->ccol; i++, lpcol++ ) 
         if( IsUpdateable(lpcol->fSqlType) ) { 
            wsprintf(sz, szFmt, lpcol->szName); 
            GetTextExtentPoint(hdc, sz, lstrlen(sz), &size); 
            if( size.cx > cxName ) 
               cxName = size.cx; 
         } 
      ReleaseDC(NULL, hdc); 
   } 
 
   GetWindowRect(GetDlgItem(hDlg, IDOK), &rc); 
 
   xName = DLGX(xFIRST); 
   yName = (4 * DLGY(cySEP)) + (DLGY(cySEP) / 2) + (2 * (rc.bottom - rc.top)); 
 
   xEdit = xName + cxName + DLGX(cxSEP); 
 
   idName = stc1; 
   idEdit = edt1; 
 
   // For each bound, updateable column, create and add an edit control 
   for (i=0, lpcol=lpChild->lpcol; i < lpChild->ccol; i++, lpcol++) { 
      if (IsUpdateable(lpcol->fSqlType)) { 
 
         // Create control label 
         wsprintf(sz, szFmt, lpcol->szName); 
 
         hWnd = CreateWindow(szSTATICCLASS, sz, dwSTATICSTYLE, 
                             xName, yName, cxName, cyName, hDlg, 
                             (HMENU)idName, g_hinst, NULL); 
 
         FORWARD_WM_SETFONT(hWnd, hfont, 0, SendMessage); 
 
         // Create (and intialize) edit control 
         yEdit = yName - ((cyEDIT - cyNAME) / 2); 
 
         GetCurrentValue(sz, lpcol, lpChild); 
 
         hWnd = CreateWindow(szEDITCLASS, sz, dwEDITSTYLE, 
                             xEdit, yEdit, cxEdit, cyEdit, hDlg, 
                             (HMENU)idEdit, g_hinst, NULL); 
 
         FORWARD_WM_SETFONT(hWnd, hfont, 0, SendMessage); 
 
         // Limit number of characters user can type to column display size 
         Edit_LimitText(hWnd, lpcol->cbc-1); 
 
         yName += cyEdit + DLGY(cySEP); 
 
         idName++; 
         idEdit++; 
      } 
   } 
 
   // Grow dialog so that all controls are visible 
   GetClientRect(hDlg, &rc); 
 
   rc.top    = 0; 
   rc.bottom = yName + DLGY(cySEP); 
 
   rc.left   = 0; 
   rc.right  = (2 * DLGX(xFIRST)) + DLGX(cxNAME) + DLGX(cxEDIT) + DLGX(cxSEP); 
 
   AdjustWindowRect(&rc, dwDLGSTYLE, FALSE); 
   MoveWindow(hDlg, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE); 
 
   // Place OK and Cancel buttons appropriately 
   GetClientRect(hDlg, &rc); 
   {  RECT  rcButton; 
      int      x, y; 
 
      GetWindowRect(GetDlgItem(hDlg, IDOK), &rcButton); 
 
      x = rc.right - DLGX(cxSEP) - (rcButton.right - rcButton.left); 
      y = DLGY(cySEP); 
 
      MoveWindow(GetDlgItem(hDlg, IDOK), 
                 x, y, 
                 rcButton.right - rcButton.left, 
                 rcButton.bottom - rcButton.top, 
                 TRUE); 
 
      y += rcButton.bottom - rcButton.top + (DLGY(cySEP) / 2); 
 
      GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rcButton); 
      MoveWindow(GetDlgItem(hDlg, IDCANCEL), 
                 x, y, 
                 rcButton.right - rcButton.left, 
                 rcButton.bottom - rcButton.top, 
                 TRUE); 
   } 
 
   return; 
} 
 
 
/* CenterDialog ------------------------------------------------------------ 
   Description: Center dialog over its owning parent window 
                If the entire dialog does not fit on the desktop, 
                ensure upper left corner is always visible 
                --------------------------------------------------------------------------*/ 
void INTFUNC CenterDialog(HWND hDlg) 
{ 
   RECT  rcDlg, rcScr, rcParent; 
   int      cx, cy; 
 
   GetWindowRect(hDlg, &rcDlg); 
   cx = rcDlg.right  - rcDlg.left; 
   cy = rcDlg.bottom - rcDlg.top; 
 
   GetWindowRect(GetParent(hDlg), &rcParent); 
   rcDlg.top    = rcParent.top + 
      (((rcParent.bottom - rcParent.top) - cy) >> 1); 
   rcDlg.left   = rcParent.left + 
      (((rcParent.right - rcParent.left) - cx) >> 1); 
   rcDlg.bottom = rcDlg.top  + cy; 
   rcDlg.right  = rcDlg.left + cx; 
 
   GetWindowRect(GetDesktopWindow(), &rcScr); 
   if (rcDlg.bottom > rcScr.bottom) { 
      rcDlg.bottom = rcScr.bottom; 
      rcDlg.top    = rcDlg.bottom - cy; 
   } 
   if (rcDlg.right  > rcScr.right) { 
      rcDlg.right = rcScr.right; 
      rcDlg.left  = rcDlg.right - cx; 
   } 
 
   if (rcDlg.left < 0) rcDlg.left = 0; 
   if (rcDlg.top  < 0) rcDlg.top  = 0; 
 
   MoveWindow(hDlg, rcDlg.left, rcDlg.top, cx, cy, FALSE); 
   return; 
} 
 
 
/* DoDialog ---------------------------------------------------------------- 
   Description: Launch a dialog passing child window variables 
   --------------------------------------------------------------------------*/ 
int INTFUNC DoDialog(HWND    hWndParent, 
                     int     nDlgResNum, 
                     DLGPROC lpDlgProc) 
{ 
   HWND  hWnd; 
   LPCHILD  lpChild; 
   int      nRC; 
 
   hWnd    = FORWARD_WM_MDIGETACTIVE(g_hwndClient, SendMessage); 
   lpChild = (hWnd 
              ? (LPCHILD)GetWindowLong(hWnd, 0) 
              : NULL); 
 
   nRC = DialogBoxParam(g_hinst, 
                        MAKEINTRESOURCE(nDlgResNum), 
                        hWndParent, 
                        lpDlgProc, 
                        (LONG)lpChild); 
   return nRC; 
} 
 
/* MyCreateDialog ------------------------------------------------------------ 
   Description: Launch a  modeless dialog passing child window variables 
--------------------------------------------------------------------------*/ 
 
HWND INTFUNC MyCreateDialog(HWND    hWndParent, 
                            int     nDlgResNum, 
                            DLGPROC lpDlgProc) 
{ 
   HWND  hWnd, hWndRet; 
   LPCHILD  lpChild; 
 
   hWnd    = FORWARD_WM_MDIGETACTIVE(g_hwndClient, SendMessage); 
   lpChild = (hWnd 
              ? (LPCHILD)GetWindowLong(hWnd, 0) 
              : NULL); 
 
   hWndRet = CreateDialogParam(g_hinst, 
                               MAKEINTRESOURCE(nDlgResNum), 
                               hWndParent, 
                               lpDlgProc, 
                               (LPARAM)lpChild); 
   return hWndRet; 
} 
 
/* GetEditControls --------------------------------------------------------- 
   Description: Get values from edit controls and move to row-set buffers 
   --------------------------------------------------------------------------*/ 
BOOL INTFUNC GetEditControls(HWND hDlg, LPCHILD lpChild) 
{ 
   LPCOL lpcol; 
   char  sz[cbMAXSQL]; 
   UINT  idEdit; 
   BOOL  fChangeMade; 
   int      i; 
 
   fChangeMade = FALSE; 
   idEdit      = edt1; 
 
   // For each bound, updateable column, retrieve the value 
   for (i=0, lpcol=lpChild->lpcol; i < lpChild->ccol; i++, lpcol++) { 
      if (IsUpdateable(lpcol->fSqlType)) { 
 
         // Get the control value 
         SendDlgItemMessage(hDlg, idEdit, WM_GETTEXT, 
                            (WPARAM)sizeof(sz), (LPARAM)((LPSTR)sz)); 
 
         // Move into row-set buffer 
         if (SetCurrentValue(sz, lpcol, lpChild) && !fChangeMade) 
            fChangeMade = TRUE; 
 
         idEdit++; 
      } 
   } 
 
   return fChangeMade; 
} 
 
 
/* IsMsgWaiting ------------------------------------------------------------ 
   Description: Return TRUE if the Cancel button has been pressed 
   --------------------------------------------------------------------------*/ 
BOOL INTFUNC IsMsgWaiting(HWND hWnd) 
{ 
   MSG   msg; 
 
   UNREF_PARAM (hWnd); 
 
   // Check all waiting messages 
   while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 
 
      // Process message 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
 
      // Return TRUE if the Cancel button was pressed 
      if ((msg.message == WM_COMMAND 
           && GET_WM_COMMAND_ID(msg.wParam, msg.lParam) == IDCANCEL) 
          || msg.message == WMU_CANCEL) 
         return TRUE; 
   } 
   return FALSE; 
} 
 
/* OptionsDlgProc ---------------------------------------------------------- 
   Description: handle options dialog 
----------------------------------------------------------------------------*/ 
 
BOOL EXPFUNC OptionsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
 
 
   switch (msg) { 
 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
 
      SetWindowLong(hDlg, USERDATA, (LONG)lParam); 
      InitializeDialogControls(hDlg, (LPCHILD) lParam); 
 
      return TRUE; 
 
     case WM_COMMAND: 
      (void) HANDLE_WM_COMMAND(hDlg,wParam,lParam,ClassOnCommand); 
      break; 
 
      // New option dialog selected 
 
     case WMU_NEWOPTION: 
      { 
         LPCHILD  lpChild = (LPCHILD) GetWindowLong(hDlg, USERDATA); 
 
         if (g_hwndChildDialog) 
            DestroyWindow(g_hwndChildDialog); 
 
         g_hwndChildDialog = MyCreateDialog(hDlg, 
                                            (int) lParam, 
                                            ChildOptDlgProc); 
 
         SetFocus(GetDlgItem(hDlg, IDC_OPTIONLIST)); 
 
         break; 
      } 
 
 
      // Set title of option area 
 
 
     case WMU_SETSUBTEXT: 
      { 
         char  szBuffer[1000]; 
 
         ListBox_GetText(GetDlgItem(hDlg, wParam), 
                         ListBox_GetCurSel(GetDlgItem(hDlg,wParam)), 
                         szBuffer); 
 
         Static_SetText( GetDlgItem(hDlg, IDC_OPTIONAREA_TITLE), 
                        szBuffer); 
         break; 
 
      } 
 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
/* ChildOptDlgProc -------------------------------------------------------- 
   Description: handle generic dialog 
----------------------------------------------------------------------------*/ 
 
BOOL EXPFUNC ChildOptDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
 
   switch (msg) { 
 
 
     case WM_INITDIALOG: 
      SetWindowLong(hDlg, USERDATA, (LONG)lParam); 
      InitializeDialogControls(hDlg, (LPCHILD) lParam); 
 
      // Align the window to a hidden static in the parent 
 
      (void) AlignToControl(hDlg, GetParent(hDlg), IDC_OPTION_WINPOS); 
 
      return TRUE; 
 
     case WM_COMMAND: 
      return (BOOL)HANDLE_WM_COMMAND(hDlg,wParam,lParam,ClassOnCommand); 
 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* AboutDlgProc ------------------------------------------------------------ 
   Description: Display about box 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC AboutDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   UNREF_PARAM (lParam); 
 
   switch (msg) { 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
      return TRUE; 
 
     case WM_COMMAND: 
      if (GET_WM_COMMAND_ID(wParam, lParam) == IDOK 
          || GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL) { 
         EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* AbsDlgProc -------------------------------------------------------------- 
   Description: Get absolute row number to fetch 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC AbsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   LPCHILD  lpChild; 
   char  sz[11]; 
   char  *EndPtr; 
   SDWORD   arow; 
 
   lpChild = (LPCHILD)GetWindowLong(hDlg, USERDATA); 
 
   switch (msg) { 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
 
      lpChild = (LPCHILD)lParam; 
 
      SetWindowLong(hDlg, USERDATA, (LONG)lpChild); 
      wsprintf(sz, "%ld", lpChild->arow); 
      SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), sz); 
      SendDlgItemMessage(hDlg, IDC_EDIT1, 
                         EM_LIMITTEXT, sizeof(sz)-1, 0L); 
      return TRUE; 
 
     case WM_COMMAND: 
      switch (GET_WM_COMMAND_ID(wParam, lParam)) { 
        case IDOK: 
         GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), sz, sizeof(sz)); 
         arow = strtol((char*) sz, &EndPtr, 10); 
         for (; *EndPtr && 
              ISWHITE(*EndPtr); EndPtr = AnsiNext(EndPtr)); 
         // the number inputed is within '0' to '9' or + or - 
         if (*EndPtr != '\0') { 
            MessageBox(hDlg, 
                       "Invalid absolute row number", 
                       NULL, 
                       MB_ICONSTOP); 
            return TRUE; 
         } 
         lpChild->arow = arow; 
 
        case IDCANCEL: 
         EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* DataDlgProc ------------------------------------------------------------- 
   Description: Display large data value (retrieved via SQLGetData) 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC DataDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   switch (msg) { 
     case WM_INITDIALOG: { 
        LPBIGCOL  lpbc; 
        char      sz[cbSTRLEN]; 
        char      szNum[cbSTRLEN]; 
        char      szFmt[cbSTRLEN]; 
 
        CenterDialog(hDlg); 
 
        lpbc = (LPBIGCOL)lParam; 
 
        if (lpbc->cb == SQL_NULL_DATA) { 
           lstrcpy(lpbc->lpsz, g_szNull); 
           lpbc->cb = 0; 
           _ltoa(0, szNum, 10); 
        } 
        else if (lpbc->cb == SQL_NO_TOTAL) 
           lstrcpy(szNum, g_szUnknown); 
        else 
           _ltoa(lpbc->cb, szNum, 10); 
 
        LoadString(g_hinst, IDS_DATADLG, szFmt, sizeof(szFmt)); 
        wsprintf(sz, szFmt, lpbc->szName, szNum); 
        SetWindowText(GetDlgItem(hDlg, IDC_TEXT1), sz); 
 
        SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), lpbc->lpsz); 
        return TRUE; 
     } 
 
     case WM_COMMAND: 
      switch (GET_WM_COMMAND_ID(wParam, lParam)) { 
        case IDOK: 
        case IDCANCEL: 
         EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* RelDlgProc -------------------------------------------------------------- 
   Description: Get relative row offset to fetch 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC RelDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   LPCHILD  lpChild; 
   char  sz[7]; 
 
   lpChild = (LPCHILD)GetWindowLong(hDlg, USERDATA); 
 
   switch (msg) { 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
 
      lpChild = (LPCHILD)lParam; 
      SetWindowLong(hDlg, USERDATA, (LONG)lpChild); 
 
      wsprintf(sz, "%ld", lpChild->rrow); 
      SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), sz); 
      SendDlgItemMessage(hDlg, IDC_EDIT1, 
                         EM_LIMITTEXT, sizeof(sz)-1, 0L); 
      return TRUE; 
 
     case WM_COMMAND: 
      switch (GET_WM_COMMAND_ID(wParam, lParam)) { 
        case IDOK: { 
           SDWORD rrow; 
           char   *EndPtr; 
 
           GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), sz, sizeof(sz)); 
           rrow = strtol((char*) sz, &EndPtr, 10); 
           for (; *EndPtr && 
                ISWHITE(*EndPtr); EndPtr = AnsiNext(EndPtr)); 
           // the number inputed is within '0' to '9' or + or - 
           if (*EndPtr != '\0' || rrow < -100000 || rrow > 100000) { 
              MessageBox(hDlg, 
                         "Step amount must be between -100,000 and 100,000", 
                         NULL, 
                         MB_ICONSTOP); 
              return TRUE; 
           } 
           lpChild->rrow = rrow; 
        } 
 
        case IDCANCEL: 
         EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* StmtDlgProc ------------------------------------------------------------- 
   Description: Get SQL statement to execute 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC StmtDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   LPCHILD  lpChild; 
 
   lpChild = (LPCHILD)GetWindowLong(hDlg, USERDATA); 
 
   switch (msg) { 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
 
      lpChild = (LPCHILD)lParam; 
      SetWindowLong(hDlg, USERDATA, (LONG)lpChild); 
 
      SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), lpChild->sql); 
      SendDlgItemMessage(hDlg, IDC_EDIT1, EM_LIMITTEXT, cbMAXSQL-1, 0L); 
      return TRUE; 
 
     case WM_COMMAND: 
      switch (GET_WM_COMMAND_ID(wParam, lParam)) { 
        case IDOK: 
         GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), 
                       lpChild->sql, cbMAXSQL); 
 
         lpChild->dwOperation = OPER_SELECT; 
 
 
        case IDCANCEL: 
         EndDialog(hDlg, wParam); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* UpdateDlgProc ----------------------------------------------------------- 
   Description: Get new values with which to update the current row 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC UpdateDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   LPCHILD  lpChild; 
 
   lpChild = (LPCHILD)GetWindowLong(hDlg, USERDATA); 
 
   switch (msg) { 
 
      // Build dialog dynamically, adding appropriate edit controls 
     case WM_INITDIALOG: 
      lpChild = (LPCHILD)lParam; 
 
      SetWindowLong(hDlg, USERDATA, (LONG)lpChild); 
      AddEditControls(hDlg, lpChild); 
      SendDlgItemMessage(hDlg,edt1,EM_SETSEL,GET_EM_SETSEL_MPS(0, -1)); 
 
      CenterDialog(hDlg); 
      SetFocus(GetDlgItem(hDlg, edt1)); 
      return FALSE; 
 
      // Close dialog updating row-set buffer (if OK) with new values 
     case WM_COMMAND: 
      switch (GET_WM_COMMAND_ID(wParam, lParam)) { 
        case IDOK: 
         if (!GetEditControls(hDlg, lpChild)) 
            GET_WM_COMMAND_ID(wParam, lParam) = IDCANCEL; 
 
        case IDCANCEL: 
         EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
 
/* FindDlgProc ------------------------------------------------------------- 
   Description: Get text string to find in result set 
   --------------------------------------------------------------------------*/ 
BOOL EXPFUNC FindDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   LPCHILD  lpChild; 
 
   lpChild = (LPCHILD)GetWindowLong(hDlg, USERDATA); 
 
   switch (msg) { 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
 
      lpChild = (LPCHILD)lParam; 
      SetWindowLong(hDlg, USERDATA, (LONG)lpChild); 
 
      SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), lpChild->sql); 
      SendDlgItemMessage(hDlg, IDC_EDIT1, EM_LIMITTEXT, cbMAXSQL-1, 0L); 
      return TRUE; 
 
     case WM_COMMAND: 
      switch (GET_WM_COMMAND_ID(wParam, lParam)) { 
        case IDOK: 
         GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), 
                       lpChild->sql, cbMAXSQL); 
 
        case IDCANCEL: 
         EndDialog(hDlg, wParam); 
         return TRUE; 
      } 
      break; 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
} 
 
/*--------------------------------------------------------------------------- 
** SQLTablesDlgProc -- get information for SQLTables and similar functions 
----------------------------------------------------------------------------*/ 
BOOL EXPFUNC SQLTablesDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   LPCHILD  lpChild; 
 
   lpChild = (LPCHILD)GetWindowLong(hDlg, USERDATA); 
 
   switch (msg) { 
     case WM_INITDIALOG: 
      CenterDialog(hDlg); 
 
      lpChild = (LPCHILD)lParam; 
      SetWindowLong(hDlg, USERDATA, (LONG)lpChild); 
 
      // Set the default button 
      if (!(lpChild->dwGuiFlags & GUIF_TABLES_RADIO)) { 
         lpChild->dwOperation = IDC_TABLE_RAD_TABLE; 
         lpChild->dwRadioButton = IDC_TABLE_RAD_TABLE; 
      } 
 
      // Set the dialog up 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,lpChild->dwRadioButton), 
                   lpChild->dwRadioButton, 
                   ACT_INIT); 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,lpChild->dwRadioButton), 
                   lpChild->dwRadioButton, 
                   ACT_TRIGGER); 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,IDC_TABLEINFO_QUALIFIER), 
                   IDC_TABLEINFO_QUALIFIER, 
                   ACT_INIT); 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,IDC_TABLEINFO_NAME), 
                   IDC_TABLEINFO_NAME, 
                   ACT_INIT); 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,IDC_TABLEINFO_OWNER), 
                   IDC_TABLEINFO_OWNER, 
                   ACT_INIT); 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,IDC_TABLEINFO_TYPE), 
                   IDC_TABLEINFO_TYPE, 
                   ACT_INIT); 
 
      ControlValue(  lpChild, 
                   hDlg, 
                   GetDlgItem(hDlg,IDC_TABLEINFO_COLNAME), 
                   IDC_TABLEINFO_COLNAME, 
                   ACT_INIT); 
      return TRUE; 
 
     case WM_COMMAND: 
      return (BOOL)HANDLE_WM_COMMAND(hDlg, wParam, lParam, ClassOnCommand); 
      break; 
 
   } 
 
   return DlgProcFilter(hDlg, msg, wParam, lParam); 
 
} 
 
/*---ClassCommand--------------------------------------------------------- 
   Filters commands for dialogs.   Forwards those messages that we think 
   are interesting to a handler that processes the events. 
---------------------------------------------------------------------------*/ 
 
VOID INTFUNC ClassOnCommand(HWND hWnd, int iId, HWND hWndCtl, UINT uNotify) 
{ 
   LPCHILD  lpChild; 
 
   lpChild = (LPCHILD)GetWindowLong(hWnd,USERDATA); 
 
   if (!(lpChild)) 
      return; 
 
   switch (uNotify) { 
 
     case   BN_CLICKED:       // button control selected 
     case   EN_UPDATE:        // edit box has been updated 
     case   LBN_SELCHANGE:       // listbox has gotten a message 
      ControlValue(lpChild, hWnd, hWndCtl, iId, ACT_TRIGGER); 
      break; 
 
   } 
} 
 
 
/* 
 ** ControlValue -- Initialize a control's value from the child's state, or 
 **               set the child's state from the control.   All control- 
 **               specific logic should go here. 
 ** 
 ** Parameters: 
 **      lpChild  -- child state 
 **      hDlg  --  id of the active dialog 
 **      hCtl  --  control's window 
 **      iId      --  control's id 
 **      iAction  -- Action to take -- ACT_INIT or ACT_TRIGGER 
 ** 
 ** No return value 
 */ 
 
VOID INTFUNC ControlValue (LPCHILD     lpChild, 
                           HWND     hDlg, 
                           HWND     hCtl, 
                           int         iId, 
                           int         iAction) 
{ 
   int      iLbSelection; 
   DWORD dwListData; 
   BOOL  fTemp; 
   UCHAR szBuffer[MAXNAME]; 
 
   const DIALOG_PAIR dpOptList[] = { 
      {"Binding",          IDD_BIND_OPTIONS}, 
      {"General options",     IDD_GENERAL_OPTIONS}, 
      {"Scrolling Options",   IDD_SCROLLING_OPTIONS}, 
      {"Concurrency Options", IDD_CONCURRENCY_OPTIONS}}; 
 
   switch (iId) { 
 
     case   IDOK:                   // generic OK 
     case   IDCANCEL:                  // generic CANCEL 
      if (iAction == ACT_TRIGGER) { 
         if (g_hwndChildDialog) { 
            g_hwndChildDialog = NULL; 
         } 
         EndDialog(hDlg, iId); 
      } 
      break; 
 
     case IDC_RADIO_BINDROW: 
     case IDC_RADIO_BINDCOL: 
      if (SetOrGetCheck(hCtl, iAction, (iId == lpChild->fBindByRow))) { 
         lpChild->fBindByRow = iId; 
      } 
      break; 
 
     case IDC_RADIO_READONLY: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->fConcurrency == SQL_CONCUR_READ_ONLY))) { 
         lpChild->fConcurrency = SQL_CONCUR_READ_ONLY; 
      } 
      break; 
     case IDC_RADIO_LOCKING: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->fConcurrency == SQL_CONCUR_LOCK))) { 
         lpChild->fConcurrency = SQL_CONCUR_LOCK; 
      } 
      break; 
     case IDC_RADIO_OPTIMISTIC: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->fConcurrency == SQL_CONCUR_ROWVER))) { 
         lpChild->fConcurrency = SQL_CONCUR_ROWVER; 
      } 
      break; 
     case IDC_RADIO_OPTIMVALUE: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->fConcurrency == SQL_CONCUR_VALUES))) { 
         lpChild->fConcurrency = SQL_CONCUR_VALUES; 
      } 
      break; 
 
     case IDC_RADIO_FORWARD: 
      if (SetOrGetCheck(hCtl, iAction, 
(lpChild->crowKeyset == SQL_CURSOR_FORWARD_ONLY))) { 
         lpChild->crowKeyset = SQL_CURSOR_FORWARD_ONLY; 
      } 
      break; 
     case IDC_RADIO_SNAPSHOT: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->crowKeyset == SQL_CURSOR_STATIC))) { 
         lpChild->crowKeyset = SQL_CURSOR_STATIC; 
      } 
      break; 
     case IDC_RADIO_KEYSET: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->crowKeyset == SQL_CURSOR_KEYSET_DRIVEN))) { 
         lpChild->crowKeyset = SQL_CURSOR_KEYSET_DRIVEN; 
      } 
      break; 
     case IDC_RADIO_DYNAMIC: 
      if (SetOrGetCheck(hCtl, iAction, 
                        (lpChild->crowKeyset == SQL_CURSOR_DYNAMIC))) { 
         lpChild->crowKeyset = SQL_CURSOR_DYNAMIC; 
      } 
      break; 
 
     case IDC_CHECK_BINDALL: 
      fTemp = SetOrGetCheck(hCtl,iAction, (lpChild->fBindAll)); 
      lpChild->fBindAll = fTemp; 
      Edit_Enable(GetDlgItem(hDlg,IDC_EDIT_BIND), !(fTemp)); 
      Static_Enable(GetDlgItem(hDlg, IDC_STATIC_NBIND), !(fTemp)); 
      break; 
 
     case IDC_EDIT_BIND: 
      if (lpChild->fBind) 
         wsprintf((LPSTR)szBuffer,"%s", lpChild->szBind); 
      else  wsprintf((LPSTR)szBuffer,"%u", lpChild->cBind); 
      SetOrGetEditArray(hCtl, szBuffer, iAction); 
      if (iAction == ACT_TRIGGER) { 
         lpChild->fBind = TRUE; 
         strncpy(lpChild->szBind, szBuffer, cbINTLEN); 
         lpChild->szBind[cbINTLEN-1] = '\0'; 
      } 
      break; 
 
     case IDC_EDIT_ROWSETSIZE: 
      if (lpChild->fRowset) 
         wsprintf((LPSTR)szBuffer,"%s", lpChild->szRowset); 
      else wsprintf((LPSTR)szBuffer,"%u", lpChild->crowRowset); 
      SetOrGetEditArray(hCtl, szBuffer, iAction); 
      if (iAction == ACT_TRIGGER) { 
         lpChild->fRowset = TRUE; 
         strncpy(lpChild->szRowset, szBuffer, cbINTLEN); 
         lpChild->szRowset[cbINTLEN-1] = '\0'; 
      } 
      break; 
 
     case IDC_MAXCOL: 
      if (lpChild->fMaxBind) 
         wsprintf((LPSTR)szBuffer, "%s", lpChild->szMaxBind); 
      else wsprintf((LPSTR)szBuffer, "%ld", lpChild->crowMaxBind); 
      SetOrGetEditArray(hCtl, szBuffer, iAction); 
      if (iAction == ACT_TRIGGER) { 
         lpChild->fMaxBind = TRUE; 
         strncpy(lpChild->szMaxBind, szBuffer, cbINTLEN); 
         lpChild->szMaxBind[cbINTLEN-1] = '\0'; 
      } 
      break; 
 
     case IDC_TABLE_RAD_STATISTICS:       // TABLEINFO->STATSTICS 
     case IDC_TABLE_RAD_COLUMN:           // TABLEINFO->COLUMNS 
     case IDC_TABLE_RAD_PRIV:          // TABLEINFO->PRIVILEGES 
     case IDC_TABLE_RAD_PROC:          // TABLEINFO->PROCEDURES 
     case IDC_TABLE_RAD_TABLE:            // TABLEINFO->TABLES 
 
      // Initialize the button, or set iAction to its value 
      // Hide any fields not related to the button, show fields related 
 
      if( SetOrGetCheck(hCtl, iAction, 
                        (iId == (int)lpChild->dwRadioButton)) ) 
         lpChild->dwOperation = (UWORD) iId; 
 
      if (iAction == ACT_TRIGGER) { 
         lpChild->dwGuiFlags |= GUIF_TABLES_RADIO; 
         lpChild->dwRadioButton = iId; 
         (void) SetHiddenFields(hDlg, iId); 
      } 
      break; 
 
     case IDC_CHECK_FETCH: 
      if (SetOrGetCheck(hCtl, iAction, (int)IS_ALLWFETCH(lpChild))) 
         lpChild->dwGuiFlags |= GUIF_ALWAYSFETCH; 
      else 
         lpChild->dwGuiFlags &= ~GUIF_ALWAYSFETCH; 
 
      break; 
 
     case IDC_CHECK_ASYNC: 
      lpChild->fAsync = SetOrGetCheck(hCtl,iAction,lpChild->fAsync); 
      break; 
 
     case IDC_TABLEINFO_QUALIFIER:        // TABLEINFO->QUALIFIER 
      SetOrGetEditArray(hCtl, lpChild->szQualifier, iAction); 
      break; 
 
     case IDC_TABLEINFO_NAME:          // TABLEINFO->NAME 
      SetOrGetEditArray(hCtl, lpChild->szTable, iAction); 
      break; 
 
     case IDC_TABLEINFO_OWNER:            // TABLEINFO->OWNER 
      SetOrGetEditArray(hCtl, lpChild->szUser, iAction); 
      break; 
 
     case IDC_TABLEINFO_TYPE:          // TABLEINFO->TYPE 
      SetOrGetEditArray(hCtl, lpChild->szType, iAction); 
      break; 
 
     case IDC_TABLEINFO_COLNAME:          // TABLEINFO->COLUMN NAME 
      SetOrGetEditArray(hCtl, lpChild->szColName, iAction); 
      break; 
 
     case IDC_OPTIONLIST:              // OPTIONS->options 
      { 
 
         if (iAction == ACT_INIT) { 
            InitializeListBox(hDlg, 
                              IDC_OPTIONLIST, 
                              &dpOptList[0], 
                              sizeof(dpOptList) / sizeof(DIALOG_PAIR), 
                              IDD_GENERAL_OPTIONS); 
         } 
 
         // Get the title and data for the currently-selected list box 
 
         iLbSelection = ListBox_GetCurSel(hCtl); 
         dwListData   = ListBox_GetItemData(hCtl, iLbSelection); 
 
         SendMessage(hDlg,WMU_NEWOPTION, iLbSelection,(LPARAM)dwListData); 
         SendMessage(hDlg,WMU_SETSUBTEXT,iId, 0); 
 
         break; 
      } 
 
   } 
} 
 
/* 
** SetOrGetCheck      -- set a value based upon a button action, or set a 
**                 check button if the action is equal to a value 
**                 Also used for radios 
** 
** Parameters: 
**    hCtl     -- control handle 
**    iAction     -- ACT_INIT or ACT_TRIGGER 
**    bEqual      -- Initialization -- should value be set? 
** 
** Returns: 
**    TRUE if checkbox is now set 
*/ 
INLINE BOOL SetOrGetCheck( 
                          HWND   hCtl, 
                          int    iAction, 
                          BOOL   bEqual) 
{ 
   if (iAction == ACT_INIT) { 
      Button_SetCheck(hCtl, bEqual); 
      return bEqual; 
   } 
 
   if (iAction == ACT_TRIGGER) { 
      Button_SetCheck(hCtl, Button_GetCheck(hCtl)); 
      return Button_GetCheck(hCtl); 
   } 
 
   return FALSE; 
} 
 
 
/* 
** SetOrGetEditArray -- set the value of an array from an edit control, or 
**                set the edit control from the array  (inline) 
** 
** Parameters: 
**    hCtl  -- control 
**    lpStr -- string 
**    iAction  -- ACT_INIT or ACT_TRIGGER 
** 
** Notes:   Assumes lpStr is MAXNAME bytes long 
*/ 
INLINE VOID SetOrGetEditArray( 
                              HWND  hCtl, 
                              UCHAR FAR *lpStr, 
                              int      iAction) 
{ 
   if (iAction == ACT_INIT) 
      Edit_SetText(hCtl, (LPSTR)lpStr); 
   else 
      if (iAction == ACT_TRIGGER) 
         Edit_GetText(hCtl, (LPSTR)lpStr, MAXNAME - 1); 
} 
 
/* 
** SetHiddenFields -- show or hide hidden fields in a dialog box, depending 
**               upon the action taken. 
** 
** Parameters: 
**    hDlg  -- dialog we are dealing with 
**    iAct  -- action 
** 
*/ 
BOOL    INTFUNC SetHiddenFields( 
                                HWND   hWnd, 
                                int    iAct) 
{ 
   HWND  hTTag, hCol; 
   HWND  hType, hCTag; 
 
   // Get handles for all of the windows we want to deal with 
 
   hTTag = GetDlgItem(hWnd, IDC_TYPETAG); 
   hCol  = GetDlgItem(hWnd, IDC_COLTAG); 
 
   hType = GetDlgItem(hWnd, IDC_TABLEINFO_TYPE); 
   hCTag = GetDlgItem(hWnd, IDC_TABLEINFO_COLNAME); 
 
   if (hType) { 
      Edit_Enable(hType, (iAct == IDC_TABLE_RAD_TABLE)  ? 1 : 0); 
      ShowWindow(hType,  (iAct == IDC_TABLE_RAD_TABLE)  ? SW_SHOW : SW_HIDE); 
      ShowWindow(hTTag,  (iAct == IDC_TABLE_RAD_TABLE)  ? SW_SHOW : SW_HIDE); 
 
      Edit_Enable(hCTag, (iAct == IDC_TABLE_RAD_COLUMN) ? 1 : 0); 
      ShowWindow(hCol,   (iAct == IDC_TABLE_RAD_COLUMN) ? SW_SHOW : SW_HIDE); 
      ShowWindow(hCTag,  (iAct == IDC_TABLE_RAD_COLUMN) ? SW_SHOW : SW_HIDE); 
 
      return TRUE; 
   } 
 
   return FALSE; 
} 
 
/* 
 **   InitializeListBox -- initialize a listbox from a DIALOG_PAIR 
 **                     structure. 
 ** 
 **  Parameters: 
 **      hWnd     --  window the list box lives in 
 **      lbId     --  resource id of the list box 
 **      dpOptList   --  pointer to option list structure 
 **      iEntries --  number of entries in the list box 
 **      iDefId      --  default to select 
 ** 
 ** 
 **  Returns:  FALSE 
 ** 
 */ 
 
BOOL INTFUNC InitializeListBox( 
   HWND                    hWnd, 
   int                     lbId, 
   const DIALOG_PAIR FAR   *dpOptList  , 
   int                     iEntries, 
   int                     iDefId) 
{ 
 
   int            iDlg, iIndex; 
   HWND        hOptionBox; 
   LPSTR       szDefaultTitle; 
   hOptionBox  =  GetDlgItem(hWnd, lbId); 
 
 
   for (iDlg = 0; iDlg < iEntries; iDlg++) { 
      iIndex = ListBox_AddString(hOptionBox, 
                                 dpOptList[iDlg].szDlgPairTitle); 
 
      ListBox_SetItemData(hOptionBox, 
                          iIndex, 
                          dpOptList[iDlg].iDlgPairDlgId); 
 
 
      if (iDefId == dpOptList[iDlg].iDlgPairDlgId) { 
         szDefaultTitle = dpOptList[iDlg].szDlgPairTitle; 
      } 
 
   } 
 
   ListBox_SetCurSel(hOptionBox, 
                     ListBox_FindStringExact(hOptionBox, 0, szDefaultTitle)); 
 
   return FALSE; 
} 
 
/* 
** InitializeDialogControls   -- Initialize all of the controls in a dialog 
**                      from the lpchild structure.   Callback function. 
** 
** Parameters: 
**    hDlg     -- dialog handle 
**    lpChild     -- state structure 
** 
*/ 
 
VOID INTFUNC InitializeDialogControls( 
                                      HWND   hDlg, 
                                      LPCHILD   lpChild) 
{ 
   FARPROC     ControlInstance = MakeProcInstance((FARPROC)InitControlCallback, 
                                                  g_hinst); 
 
   EnumChildWindows(hDlg, (WNDENUMPROC)ControlInstance, (LPARAM)lpChild); 
   FreeProcInstance(ControlInstance); 
 
} 
 
 
 
/* 
** InitControlCallback  -- callback function for initializing controls 
** 
** Parameters: 
**    hwndChild   -- child window handle 
**    lParam      -- lparam (lpChild from EnumChildProc 
*/ 
 
BOOL CALLBACK InitControlCallback( 
                                  HWND hwndChild, 
                                  LPARAM  lParam) 
{ 
   int      iControl= GetDlgCtrlID(hwndChild); 
 
   if (iControl) { 
      ControlValue((LPCHILD) lParam, 
                   GetParent(hwndChild), 
                   hwndChild, 
                   iControl, 
                   ACT_INIT); 
 
   } 
   return TRUE; 
} 
 
 
 
BOOL INTFUNC DlgProcFilter(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
 
   switch (msg) { 
     case WM_SETTEXT: 
     case WM_NCPAINT: 
     case WM_NCACTIVATE: 
      SetWindowLong(hDlg, DWL_MSGRESULT,0L); 
      return TRUE; 
   } 
   return FALSE; 
} 
 
/* 
** AlignToControl -- align a window to a control in a dialog 
** 
** Parameters: 
**    hWnd  -- window to align 
**    hParent -- parent dialog 
**    iCtlId   -- control Id 
** 
** Returns: BOOL that moveWindow returns 
*/ 
 
BOOL INTFUNC AlignToControl( 
                            HWND hWnd, 
                            HWND hParent, 
                            int     iCtlId) 
{ 
   HWND  hwndDrawArea; 
   RECT  rcDrawArea, rcChildWnd; 
   POINT ptPoint; 
 
 
   hwndDrawArea = GetDlgItem(hParent, iCtlId); 
   GetWindowRect(hwndDrawArea, &rcDrawArea); 
   GetWindowRect(hWnd, &rcChildWnd); 
 
   ptPoint.x = rcDrawArea.left; 
   ptPoint.y = rcDrawArea.top; 
 
   ScreenToClient(hWnd, &ptPoint); 
 
   return (MoveWindow(  hWnd, 
                      ptPoint.x, 
                      ptPoint.y, 
                      rcChildWnd.right- rcChildWnd.left, 
                      rcChildWnd.bottom - rcChildWnd.top, 
                      FALSE)); 
}