home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Internet Business Development Kit / PRODUCT_CD.iso / sqlsvr / odbcsdk / samples / admndemo / results.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-07  |  28.2 KB  |  950 lines

  1. //*---------------------------------------------------------------------------------
  2. //|  ODBC System Administrator
  3. //|
  4. //|  This code is furnished on an as-is basis as part of the ODBC SDK and is
  5. //|  intended for example purposes only.
  6. //|
  7. //|    Title:    RESULTS.C
  8. //|        This module contains functions which allow you to view results via an
  9. //|        owner-drawn list box.  Having the list box functionality made it easy
  10. //|        to implement Pipes, but has some serious draw-backs as far as record
  11. //|        limits, storage methods, etc...  If you are looking for a great way to
  12. //|        paint data in a grid, check out the C++ or Cursor Demo samples that came
  13. //|        with this SDK.
  14. //*---------------------------------------------------------------------------------
  15. #include <stdio.h>
  16. #include "errcheck.h"
  17. #include "standard.h"
  18. #include "results.h"
  19. #include "math.h"
  20. #include "ini.h"
  21.  
  22.  
  23. //------------------------------------------------------------------------
  24. //  Defines
  25. //------------------------------------------------------------------------
  26. VSZFile;
  27.  
  28.  
  29. //------------------------------------------------------------------------
  30. //  Globals
  31. //------------------------------------------------------------------------
  32. char szErrMsg[100];
  33. dCSEG(char) szONE[]                                =    "1";
  34. dCSEG(char) szZERO[]                                =    "0";
  35. dCSEG(char) szdate[]                                =     "%02u/%02u/%02u";
  36. dCSEG(char) sztime[]                                =    "%02u:%02u:%02u";
  37. dCSEG(char) sztimestmp[]                        =    "%02u/%02u/%02u %02u:%02u:%02u.%lu";
  38. dCSEG(char) szTypeNotFound[]                    =    "Not found";
  39. dCSEG(char) szMaxRowsFetched[]                =    "Maximum rows fetched.  Total rows: %lu";
  40.  
  41.  
  42. struct {
  43.     SWORD    type;                                // Data type value
  44.     LPSTR    sztype;                            // String equivalent
  45.     } SqlTypes[] = {
  46. // type                        sztype
  47. // -------------------    -----------------------------
  48.     SQL_BIGINT,                "SQL_BIGINT=-5",
  49.     SQL_BINARY,                "SQL_BINARY=-2",
  50.     SQL_BIT,                    "SQL_BIT=-7",
  51.     SQL_CHAR,                "SQL_CHAR=1",
  52.     SQL_DATE,                "SQL_DATE=9",
  53.     SQL_DECIMAL,            "SQL_DECIMAL=3",
  54.     SQL_DOUBLE,                "SQL_DOUBLE=8",
  55.     SQL_FLOAT,                "SQL_FLOAT=6",
  56.     SQL_INTEGER,            "SQL_INTEGER=4",
  57.     SQL_LONGVARBINARY,    "SQL_LONGVARBINARY=-4",
  58.     SQL_LONGVARCHAR,        "SQL_LONGVARCHAR=-1",
  59.     SQL_NUMERIC,            "SQL_NUMERIC=2",
  60.     SQL_REAL,                "SQL_REAL=7",
  61.     SQL_SMALLINT,            "SQL_SMALLINT=5",
  62.     SQL_TIME,                "SQL_TIME=10",
  63.     SQL_TIMESTAMP,            "SQL_TIMESTAMP=11",
  64.     SQL_TINYINT,            "SQL_TINYINT=-6",
  65.     SQL_VARBINARY,            "SQL_VARBINARY=-3",
  66.     SQL_VARCHAR,            "SQL_VARCHAR=12",
  67.     };
  68.  
  69.  
  70. struct {
  71.     SWORD type;                                // Data type value
  72.     LPSTR sztype;                            // String equivalent
  73.     } CTypes[] = {
  74. // type                        sztype
  75. // -------------------    -----------------------------
  76.     SQL_C_BINARY,            "SQL_C_BINARY=-2",
  77.     SQL_C_BIT,                "SQL_C_BIT=-7",
  78.     SQL_C_CHAR,                "SQL_C_CHAR=1",
  79.     SQL_C_DATE,                "SQL_C_DATE=9",
  80.     SQL_C_DOUBLE,            "SQL_C_DOUBLE=8",
  81.     SQL_C_FLOAT,            "SQL_C_FLOAT=7",
  82.     SQL_C_LONG,                "SQL_C_LONG=4",
  83.     SQL_C_SHORT,            "SQL_C_SHORT=5",
  84.     SQL_C_TIME,                "SQL_C_TIME=10",
  85.     SQL_C_TIMESTAMP,        "SQL_C_TIMESTAMP=11",
  86.     SQL_C_TINYINT,            "SQL_C_TINYINT=-6",
  87.     };
  88.  
  89. typedef struct tagDATATYPE{
  90.     SWORD type;                                // Data type value
  91.     LPSTR sztype;                            // String equivalent
  92.     } DATATYPE;
  93.  
  94.  
  95. //------------------------------------------------------------------------
  96. //  Local function prototypes
  97. //------------------------------------------------------------------------
  98. void CheckDisplayMode(LPSTR strin, SDWORD cbin, LPSTR strout);
  99. BOOL INTFUN                 DrawRow(DRAWITEMSTRUCT FAR * dw, 
  100.                                     RESULTSSET FAR * rs, int xLeftCol, int xRightCol, BOOL fSelect);
  101.  
  102.  
  103. //*------------------------------------------------------------------------
  104. //| CreateResultsSet:
  105. //|    This is the first function that should be called to create a
  106. //|        results set.  When there is no more use for the results set,
  107. //|        call DeleteResultsSet to delete it.
  108. //|
  109. //|    Parameters:
  110. //|        in        rs                        Pointer to a new results set
  111. //|        in        hwndClient            Client window
  112. //|        in        hInst                    Instance handle of caller
  113. //|        in        count                    How many columns in the results set
  114. //|        in        szTitle                Title for the window
  115. //|
  116. //|    Returns:
  117. //|        TRUE if there were no errors,
  118. //|        FALSE otherwise
  119. //*------------------------------------------------------------------------
  120. BOOL EXTFUN CreateResultsSet(RESULTSSET FAR * rs, HWND hwndClient, HINSTANCE hInst,
  121.                 int count, LPSTR szTitle)
  122. {
  123.     if(!rs ||
  124.         count <=0)
  125.         return FALSE;
  126.  
  127.     memset(rs, 0, sizeof(RESULTSSET));
  128.     rs->cbColumns = count;
  129.     rs->hInst = hInst;
  130.     rs->hwndClient = hwndClient;
  131.     if(*szTitle)
  132.         lstrcpy(rs->szTitle, szTitle);
  133.  
  134.     rs->md = (METADATA FAR *)GetMemory(sizeof(METADATA) * count);
  135.     if(!rs->md) 
  136.         return FALSE;
  137.  
  138.     return TRUE;
  139. }
  140.  
  141.  
  142. //*------------------------------------------------------------------------
  143. //| SetMetaDataColumn:
  144. //|    This function must be called for each column in the results set.  The
  145. //|        information placed for each row can be obtained using ODBC functions
  146. //|        such as SQLDescribeCol and SQLColAttributes.
  147. //|    Parameters:
  148. //|        in        rs                        Pointer to a results set
  149. //|        in        iCol                    Column number
  150. //|        in        szCol                    Pointer to column name
  151. //|        in        szTypeName            Data type name
  152. //|        in        fSqlType                ODBC data type number
  153. //|        in        precision            Precision
  154. //|        in        scale                    Scale
  155. //|        in        cbDisplay            Display size
  156. //|        in        fAlign                Alignment
  157. //|    Returns:
  158. //|        Nothing
  159. //*------------------------------------------------------------------------
  160. BOOL EXTFUN SetMetaDataColumn(RESULTSSET FAR * rs, int iCol, LPSTR szCol,
  161.         LPSTR szTypeName, SDWORD fSqlType, UDWORD precision, SWORD scale,
  162.         int cbDisplay, UINT fAlign)
  163. {
  164.     if(!rs ||
  165.         iCol < 0 ||
  166.         !szCol ||
  167.         !*szCol ||
  168.         !szTypeName ||
  169.         !*szTypeName) {
  170.         PostError((LPSTR)szInvalidParms);
  171.         return FALSE;
  172.         }
  173.  
  174.     rs->md[iCol].szColumnName = (LPSTR)GetMemory(lstrlen(szCol)+1);
  175.     if(!rs->md[iCol].szColumnName)
  176.         return FALSE;
  177.     precision = min(precision, MAXBYTES);
  178.     lstrcpy(rs->md[iCol].szColumnName, szCol);
  179.     lstrcpy(rs->md[iCol].szTypeName, szTypeName);
  180.     rs->md[iCol].fSqlType = fSqlType;
  181.     rs->md[iCol].precision = precision;
  182.     rs->md[iCol].scale = scale;
  183.     rs->md[iCol].cbDisplaySize = cbDisplay;
  184.     rs->md[iCol].fAlign = fAlign;
  185.     rs->md[iCol].cbOffset = (iCol > 0) ? (UINT)(precision + rs->md[iCol-1].cbOffset) : (UINT)(precision);
  186.     ++rs->md[iCol].cbOffset;                    // Room for terminators
  187.     
  188.     return TRUE;
  189. }
  190.  
  191.  
  192.  
  193. //*------------------------------------------------------------------------
  194. //| AllocateRowData:
  195. //|    Call this function for each row in the results set to allocate
  196. //|        memory and insert a row into the results set.
  197. //|    Parameters:
  198. //|        in        rs                        Pointer to results set
  199. //|        in        rd                        Pointer to a row data structure
  200. //|        in        cColor                Text color
  201. //|        in        cBkg                    Background color
  202. //|    Returns:
  203. //|        Pointer to a ROWDATA structure
  204. //*------------------------------------------------------------------------
  205. ROWDATA FAR * AllocateRowData(RESULTSSET FAR * rs, COLORREF cColor, COLORREF cBkg)
  206. {
  207.     ROWDATA FAR *    rd;
  208.     int                dex;
  209.     
  210.     if(!rs) {
  211.         PostError((LPSTR)szInvalidParms);
  212.         return FALSE; 
  213.         }
  214.     rd = (ROWDATA FAR *)GetMemory(sizeof(ROWDATA));
  215.     if(!rd)
  216.         return NULL;
  217.     rd->textColor = cColor;
  218.     rd->bkgrnd = cBkg;
  219.     rd->cd = (COLUMNDATA FAR *)GetMemory((sizeof(COLUMNDATA) * rs->cbColumns));
  220.     if(!rd->cd)
  221.         return NULL;
  222.     rd->data = (LPSTR)GetMemory(rs->md[rs->cbColumns-1].cbOffset + 1);
  223.     if(!rd->data)
  224.         return NULL;
  225.     rd->cd[0].szCols = rd->data;
  226.     for(dex=1;  dex<rs->cbColumns;  dex++)
  227.         rd->cd[dex].szCols = rd->data + rs->md[dex-1].cbOffset;
  228.  
  229.     return rd;
  230. }
  231.  
  232.  
  233.  
  234. //*------------------------------------------------------------------------
  235. //| SetColumnData:
  236. //|    Call this function for a particular column in a ROWDATA structure.
  237. //|        If memory has been allocated for the column, it will be freed
  238. //|        and reallocated for the new string.
  239. //|    Parameters:
  240. //|        in        icol                    Which column?
  241. //|        in        rd                        Pointer to a row data structure
  242. //|        in        str                    Pointer to the new buffer
  243. //|    Returns:
  244. //|        TRUE if successful
  245. //|        FALSE on error
  246. //*------------------------------------------------------------------------
  247. BOOL EXTFUN SetColumnData(int icol, ROWDATA FAR * rd, LPSTR str)
  248. {
  249.     if(!str ||
  250.         !*str)
  251.         return FALSE;
  252.         
  253.     lstrcpy(rd->cd[icol].szCols, str);
  254.     return TRUE;
  255. }
  256.  
  257.  
  258. //*------------------------------------------------------------------------
  259. //| FreeRowData:
  260. //|    Pass a pointer to the ROWDATA structure to free.  Obviously since 
  261. //|        you are asked for a RESULTSSET pointer, you should call this
  262. //|        function before freeing the results set data.
  263. //| Parms:
  264. //|    in            rs                            Pointer to results set
  265. //|    in            rd                            Pointer to row data
  266. //| Returns:
  267. //|    Nothing.
  268. //*------------------------------------------------------------------------
  269. void EXTFUN FreeRowData(RESULTSSET FAR * rs, ROWDATA FAR * rd)
  270. {
  271.     ReleaseMemory(rd->data);
  272.     ReleaseMemory((LPVOID)rd->cd);
  273.     ReleaseMemory((LPVOID)rd);
  274. }
  275.  
  276.  
  277.  
  278. //*------------------------------------------------------------------------
  279. //| FreeResultsSet:
  280. //|    Call this function to free all of the memory for a results set.
  281. //| Parms:
  282. //|    in            rs                            Pointer to results set data to free
  283. //| Returns:
  284. //|    TRUE        If successful
  285. //|    FALSE        if there was an error
  286. //*------------------------------------------------------------------------
  287. void EXTFUN FreeResultsSet(RESULTSSET FAR * rs)
  288. {
  289.     int    dex;
  290.  
  291.     DeleteObject(rs->hFont);
  292.  
  293.     for(dex=0;  dex<rs->cbColumns;  dex++)
  294.         ReleaseMemory(rs->md[dex].szColumnName);   
  295.     ReleaseMemory(rs->md);
  296.    ReleaseMemory(rs);
  297.     return;
  298. }
  299.  
  300.  
  301.  
  302. //*------------------------------------------------------------------------
  303. //| CreateResultsFont:
  304. //|    This function is called to create a font for the results set.  The 
  305. //|    default font is used if the lf parameter is NULL.  Alternatively
  306. //|    the user can pass in a complete LOGFONT structure to use for the
  307. //|    font.
  308. //| Parms:
  309. //|    in            rs                            Pointer to results set to store info
  310. //|    in            hwnd                        Window handle to verify font
  311. //|    in            lf                            LOGFONT structure to use, NULL for dft
  312. //| Returns:              
  313. //|    Nothing.
  314. //*------------------------------------------------------------------------
  315. void CreateResultsFont(RESULTSSET FAR * rs, HWND hwnd, LOGFONT FAR * lf)
  316. {
  317.     HDC                            hdc;
  318.     LOGFONT                        logfont;
  319.     HFONT                            hf;
  320.     TEXTMETRIC                    tm;
  321.     SIZE                            sz;
  322.     int                            tmp, dex, cbExtra;
  323.  
  324.     if(!lf) {
  325.         memset(&logfont, 0, sizeof(LOGFONT));
  326.         GetDefaultFont(&logfont);
  327.         }
  328.     else
  329.         memmove(&logfont, lf, sizeof(LOGFONT));
  330.  
  331.     rs->hFont = CreateFontIndirect(&logfont);
  332.     hdc = GetDC(hwnd);
  333.     hf = SelectObject(hdc, rs->hFont);
  334.     GetTextMetrics(hdc, &tm);
  335.     rs->cx = tm.tmAveCharWidth;
  336.     
  337.     rs->cy = tm.tmHeight + tm.tmExternalLeading;
  338.     cbExtra = GetSystemMetrics(SM_CYBORDER);
  339.     rs->cTitleHeight = rs->cy + (7 * cbExtra);
  340.     rs->yTitleLoc = (rs->cTitleHeight / 2) + rs->cy;
  341.     for(dex=0, tmp=0;  dex<rs->cbColumns;  dex++) {
  342.         GetTextExtentPoint(hdc, rs->md[dex].szColumnName, 
  343.                         lstrlen(rs->md[dex].szColumnName), &sz);
  344.         rs->md[dex].cColWidth = (rs->md[dex].cbDisplaySize * rs->cx) + (7 * cbExtra);
  345.         rs->md[dex].cColWidth = max((UINT)(sz.cx * 1.5), 
  346.                             rs->md[dex].cColWidth);
  347.         rs->md[dex].xCol = tmp;
  348.         tmp += rs->md[dex].cColWidth;
  349.         }
  350.     rs->cRowWidth = tmp;
  351.  
  352.     SelectObject(hdc,hf);
  353.     ReleaseDC(hwnd, hdc);
  354. }
  355.  
  356.  
  357. //*------------------------------------------------------------------------
  358. //| FindRightCol:
  359. //|    This function will take the left column and a results set descriptor
  360. //|        and return the right column index based on what will fit in the
  361. //|        window.
  362. //| Parms:
  363. //|    in            rs                            Pointer to results set to store info
  364. //|    in            xLeftCol                    Current left column index
  365. //|    in            cWidth                    Available width
  366. //| Returns:              
  367. //|    Index to be used for right column
  368. //*------------------------------------------------------------------------
  369. int FindRightCol(RESULTSSET FAR * rs, int xLeftCol, int cWidth)
  370. {        
  371.     int xRightCol;
  372.     int cSpace;
  373.     
  374.     xRightCol = xLeftCol;
  375.     cSpace = cWidth - rs->md[xLeftCol].cColWidth;
  376.     while(cSpace>0 &&
  377.         xRightCol < rs->cbColumns-1) {
  378.         ++xRightCol;
  379.         cSpace -= rs->md[xRightCol].cColWidth;
  380.         }
  381.     return xRightCol;
  382. }
  383.  
  384.  
  385. //*------------------------------------------------------------------------
  386. //| DrawRowData:
  387. //|    This function will do the actual drawing on the screen based on the
  388. //|        control structures passed in.
  389. //| Parms:
  390. //|    in            rs                            Pointer to results set to store info
  391. //|    in            dwitem                    Draw structure
  392. //|    in            xLeftCol                    Current left column index
  393. //|    in            xRightCol                Right column index
  394. //| Returns:              
  395. //|    Nothing.
  396. //*------------------------------------------------------------------------
  397. void DrawRowData(RESULTSSET FAR * rs, DRAWITEMSTRUCT FAR * dwitem,
  398.                     int xLeftCol, int xRightCol)
  399. {
  400.     switch(dwitem->itemAction) {
  401.         case ODA_DRAWENTIRE:
  402.         case ODA_SELECT:
  403.             DrawRow(dwitem, rs, xLeftCol, xRightCol, 
  404.                             (dwitem->itemState == ODS_SELECTED));
  405.             return;
  406.         }
  407. }
  408.  
  409.  
  410. //*------------------------------------------------------------------------
  411. //| DrawColumnTitles:
  412. //|   This function is called when we need to paint the column titles for a
  413. //|        results set.  We will simply write them out.
  414. //| Parms:
  415. //|    in            hdc                        Handle to our device contex
  416. //|    in            rs                            Our results set to draw
  417. //|    in            crect                        Client rectangle to paint in
  418. //|    in            xLeftCol                    Left column
  419. //|    in            xRightCol                Right column
  420. //| Returns:              
  421. //|    Nothing.
  422. //*------------------------------------------------------------------------
  423. void INTFUN DrawColumnTitles(HDC hdc, RESULTSSET FAR * rs, 
  424.                 RECT FAR * crect, int xLeftCol, int xRightCol)
  425. {
  426.    int                     dex, offset, cright=0;
  427.    RECT                    rect;
  428.    HFONT                    hf;
  429.    
  430.     hf = SelectObject(hdc, rs->hFont);
  431.    SetTextColor(hdc, RDATA_BLACK);
  432.     offset = 0 - rs->md[xLeftCol].xCol;
  433.    for (dex=xLeftCol; dex<=xRightCol; dex++) 
  434.         cright += rs->md[dex].cColWidth;
  435.     Rectangle(hdc, crect->left, crect->top, min(cright, crect->right), crect->bottom+1);
  436.     SetBkColor(hdc, RDATA_GRAY);
  437.  
  438.     rect.top = crect->top +1;
  439.     rect.bottom = crect->bottom;
  440.     for(dex=xLeftCol;  dex<=xRightCol;  dex++) {
  441.         rect.left = rs->md[dex].xCol + offset;
  442.         rect.right = rect.left + rs->md[dex].cColWidth;
  443.         MoveTo(hdc, rect.right, rect.top);
  444.         LineTo(hdc, rect.right, rect.bottom);
  445.         ++rect.left;
  446. #ifdef TITLE_DEBUG
  447. {
  448.     char tmpbuff[50];
  449.     wsprintf(tmpbuff, "Column: %d, left=%d, top=%d, right=%d, bottom=%d",
  450.                 dex,
  451.                 rect.left, rect.top,
  452.                 rect.right, rect.bottom);
  453.     DrawFocusRect(hdc, &rect);
  454.     MessageBox(NULL, (LPSTR)tmpbuff, "Debug", MB_OK);
  455.     DrawFocusRect(hdc, &rect);
  456. }
  457. #endif
  458.         ExtTextOut(hdc, rs->md[dex].xCol + 3 + offset, rect.top + 4,
  459.                 ETO_CLIPPED | ETO_OPAQUE,
  460.                 &rect, 
  461.                 rs->md[dex].szColumnName, 
  462.                 lstrlen(rs->md[dex].szColumnName), 
  463.                 NULL);
  464.       }
  465.     SelectObject(hdc,hf);                    // change font back
  466. }
  467.  
  468.  
  469.  
  470. //*------------------------------------------------------------------------
  471. //| DrawRow:
  472. //|    Call this function for each row which must be painted.
  473. //| Parms:
  474. //|    in            dw                            Draw structure
  475. //|    in            rs                            Our results set to draw
  476. //|    in            xLeftCol                    Index to left-most column displayed
  477. //|    in            xRightCol                Index to right-most column displayed
  478. //|    in            fSelect                    Is the item supposed to be selected?
  479. //| Returns:              
  480. //|    TRUE if successful,
  481. //|    FALSE otherwise
  482. //*------------------------------------------------------------------------
  483. //#define RECT_DEBUG
  484. BOOL INTFUN DrawRow(DRAWITEMSTRUCT FAR * dw, 
  485.                             RESULTSSET FAR * rs, 
  486.                             int xLeftCol, int xRightCol,
  487.                             BOOL fSelect)
  488. {
  489.    ROWDATA FAR *         rd=(ROWDATA FAR *)dw->itemData;
  490.    int                     dex;
  491.    int                    offset;
  492.    int                    cright=0;
  493.    RECT                    rect;
  494.    HFONT                    hf;
  495.  
  496.     //
  497.     // First set the font and text colors according to the user's request, then draw
  498.     //        a line at the bottom of the row for a separator.  Note that the rcItem
  499.     //        rectangle passed to us in the DRAWITEMSTRUCT is for the
  500.     //
  501.     hf = SelectObject(dw->hDC, rs->hFont);
  502.     dw->rcItem.right = min(rs->cRowWidth, dw->rcItem.right);
  503.    for (dex=xLeftCol; dex<=xRightCol; dex++) 
  504.         cright += rs->md[dex].cColWidth;
  505.     // Draw top of box
  506.     MoveTo(dw->hDC, dw->rcItem.left, dw->rcItem.top);
  507.     LineTo(dw->hDC, min(cright, dw->rcItem.right), dw->rcItem.top);
  508.  
  509.     // Draw bottom also, to take care of last line 
  510.     MoveTo(dw->hDC, dw->rcItem.left, dw->rcItem.bottom);
  511.     LineTo(dw->hDC, min(cright, dw->rcItem.right), dw->rcItem.bottom);
  512.  
  513. #ifdef RECT_DEBUG
  514. {
  515.     char tmpbuff[50];
  516.     wsprintf(tmpbuff, "dw->rcItem, left=%d, top=%d, right=%d, bottom=%d",
  517.                 dw->rcItem.left, dw->rcItem.top,
  518.                 dw->rcItem.right, dw->rcItem.bottom);
  519.     DrawFocusRect(dw->hDC, &dw->rcItem);
  520.     MessageBox(NULL, (LPSTR)tmpbuff, "Debug", MB_OK);
  521.     DrawFocusRect(dw->hDC, &dw->rcItem);
  522. }
  523. #endif
  524.  
  525.     //
  526.     // Now loop through each column in the row and draw it's contents by creating
  527.     //        a logical rectangle for each column, then filling in that rectangle with
  528.     //        the value to be displayed.
  529.     //
  530.     rect.top = dw->rcItem.top+1;
  531.     rect.bottom = dw->rcItem.bottom;
  532.     SetBkMode(dw->hDC, TRANSPARENT);
  533.      if(fSelect) {
  534.          SetBkColor(dw->hDC, GetSysColor(COLOR_HIGHLIGHT));
  535.          SetTextColor(dw->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  536.         }
  537.     else {
  538.         SetBkColor(dw->hDC, rd->bkgrnd);
  539.        SetTextColor(dw->hDC, rd->textColor);
  540.        }
  541.     offset = 0 - rs->md[xLeftCol].xCol;
  542.    for (dex=xLeftCol; dex<=xRightCol; dex++) {
  543.         rect.left = offset + rs->md[dex].xCol;
  544.         rect.right = rect.left + rs->md[dex].cColWidth;
  545.         MoveTo(dw->hDC, rect.right, rect.top);
  546.         LineTo(dw->hDC, rect.right, rect.bottom);
  547.  
  548. #ifdef RECT_DEBUG
  549. {
  550.     char tmpbuff[50];
  551.     wsprintf(tmpbuff, "Column: %d, left=%d, top=%d, right=%d, bottom=%d",
  552.                 dex,
  553.                 rect.left, rect.top,
  554.                 rect.right, rect.bottom);
  555.     DrawFocusRect(dw->hDC, &rect);
  556.     MessageBox(NULL, (LPSTR)tmpbuff, "Debug", MB_OK);
  557.     DrawFocusRect(dw->hDC, &rect);
  558. }
  559. #endif
  560.       SetTextAlign(dw->hDC, rs->md[dex].fAlign);
  561.       if(dex != xLeftCol)
  562.           ++rect.left;
  563.         ExtTextOut(dw->hDC, rs->md[dex].xCol + 3 + offset, rect.top + 4,
  564.                 ETO_CLIPPED | ETO_OPAQUE, 
  565.                 &rect, 
  566.                 rd->cd[dex].szCols, 
  567.                 lstrlen(rd->cd[dex].szCols), 
  568.                 NULL);
  569.       }
  570.     SelectObject(dw->hDC,hf);                    // change font back
  571.  
  572.     return TRUE;
  573. }
  574.  
  575.  
  576. //*------------------------------------------------------------------------
  577. //| HandleHScroll:
  578. //|    This function adds a new item to our results set.
  579. //| Parms:
  580. //|    in            wParam                    Scroll option 
  581. //|    in            rs                            Results set pointer
  582. //|    in            hwnd                        Window handle for column title
  583. //|    in            hwndHScroll                Scroll bar window handle
  584. //|    in            xLeftCol                    Left column index
  585. //|    in            xRightCol                Right column index
  586. //|    in            hwndList                    Listbox window handle
  587. //|    in            cbColumns                Number of columns
  588. //|    in            cbClient                    Width of screen available to draw in
  589. //|    in            tRect                        Bounding rectangle for client window
  590. //| Returns:
  591. //|    Index to string if successful, LB_ERRSPACE otherwise
  592. //*------------------------------------------------------------------------
  593. void HandleHScroll(WORD wParam, RESULTSSET FAR * rs,
  594.             HWND hwnd, HWND hwndHScroll, int FAR * xLeftCol, int FAR * xRightCol,
  595.             HWND hwndList, int cbColumns, int cbClient, RECT FAR * tRect)
  596. {
  597.     int        cHScrollPos;
  598.     int        fhScroll=FALSE;
  599.     
  600.     cHScrollPos = GetScrollPos(hwndHScroll, SB_CTL);
  601.     switch(wParam) {
  602.         case SB_LINEUP:                // Shift right one column
  603.             if(!*xLeftCol)
  604.                 fhScroll = FALSE;
  605.             else {
  606.                 --cHScrollPos;
  607.                 fhScroll = TRUE;
  608.                 --*xLeftCol;
  609.                 }
  610.             break;
  611.  
  612.         case SB_LINEDOWN:                // Shift left one column
  613.             if(*xLeftCol+1 == cbColumns)
  614.                 fhScroll = FALSE;                    // No change required
  615.             else {
  616.                 ++cHScrollPos;
  617.                 fhScroll = TRUE;
  618.                 ++*xLeftCol;    
  619.                 }
  620.             break;
  621.                     
  622.         case SB_PAGEUP:                // Shift right one screen
  623.             if(!*xLeftCol)
  624.                 fhScroll = FALSE;
  625.             else {
  626.                 --cHScrollPos;
  627.                 fhScroll = TRUE;
  628.                 --*xLeftCol;
  629.                 }
  630.             break;
  631.                     
  632.         case SB_PAGEDOWN:                // Shift left one screen
  633.             if(*xLeftCol+1 == cbColumns)
  634.                 fhScroll = FALSE;                    // No change required
  635.             else {
  636.                 if(*xLeftCol < *xRightCol) {
  637.                     cHScrollPos += *xRightCol - *xLeftCol;
  638.                     *xLeftCol = *xRightCol;
  639.                     fhScroll = TRUE;
  640.                     }
  641.                 else {
  642.                     ++cHScrollPos;
  643.                     ++*xLeftCol;
  644.                     fhScroll = TRUE;
  645.                     }
  646.                 }
  647.             break;
  648.                     
  649.         case SB_THUMBPOSITION:        // Specific location
  650.             break;
  651.             }
  652.  
  653.     //
  654.     // If movement is required, we will have adjusted the scroll position
  655.     //        and columns already.  Calculate what columns will fit on our current
  656.     //        display to find the rightmost column.  Next invalidate the areas
  657.     //        requiring painting and set the new scroll position.  This will cause
  658.     //        each row to be redrawn starting with the new rwi->xLeftCol.
  659.     //
  660.     if(fhScroll) {                                // Movement is required
  661.         RECT        rect;
  662.         *xRightCol = FindRightCol(rs, *xLeftCol, cbClient);
  663.         GetClientRect(hwndList, &rect);
  664.         InvalidateRect(hwndList, &rect, TRUE);
  665.         SetScrollPos(hwndHScroll, SB_CTL, cHScrollPos, TRUE);
  666.         InvalidateRect(hwnd, tRect, TRUE);
  667.         }    
  668. }
  669.  
  670.  
  671. //*------------------------------------------------------------------------
  672. //| HandleVirtualHScroll:
  673. //|    This function should be called in response to the WM_KEYDOWN
  674. //|    message. It will look for a virtual key to see if the user
  675. //|    is trying to do scrolling.  If so, we will force the scroll
  676. //|    to happen.
  677. //| Parms:
  678. //|    in            wParam                    Value of wParam for WM_KEYDOWN
  679. //|    in            hwndList                    Handle of list box
  680. //|    in            hwndOwner                Owner window of the horizontal scrollbar
  681. //| Returns:
  682. //|    Nothing.
  683. //*------------------------------------------------------------------------
  684. void HandleVirtualHScroll(WORD wParam, HWND hwndList, HWND hwndOwner)
  685. {
  686.     switch(wParam) {
  687.         case VK_HOME:
  688.             SendMessage(hwndList, WM_VSCROLL, SB_TOP, 0L);
  689.             return;
  690.  
  691.         case VK_END:
  692.             SendMessage(hwndList, WM_VSCROLL, SB_BOTTOM, 0L);
  693.             return;
  694.  
  695.         case VK_PRIOR:
  696.             SendMessage(hwndList, WM_VSCROLL, SB_PAGEUP, 0L);
  697.             return;
  698.                     
  699.         case VK_NEXT:
  700.             SendMessage(hwndList, WM_VSCROLL, SB_PAGEDOWN, 0L);
  701.             return;
  702.                     
  703.         case VK_UP:
  704.             SendMessage(hwndList, WM_VSCROLL, SB_LINEUP, 0L);
  705.             return;
  706.                     
  707.         case VK_DOWN:
  708.             SendMessage(hwndList, WM_VSCROLL, SB_LINEDOWN, 0L);
  709.             return;
  710.                     
  711.         case VK_LEFT:
  712.             SendMessage(hwndOwner, WM_HSCROLL, SB_LINEUP, 0L);
  713.             return;
  714.                     
  715.         case VK_RIGHT:
  716.             SendMessage(hwndOwner, WM_HSCROLL, SB_LINEDOWN, 0L);
  717.             return;
  718.         }
  719. }
  720.  
  721.  
  722. //*------------------------------------------------------------------------
  723. //| AddRowData:
  724. //|    This function adds a new item to our results set.
  725. //| Parms:
  726. //|    in            rs                            Pointer to results set
  727. //|    in            rd                            Pointer to row data to add
  728. //| Returns:
  729. //|    Index to string if successful, LB_ERRSPACE otherwise
  730. //*------------------------------------------------------------------------
  731. int AddRowData(RESULTSSET FAR * rs, ROWDATA FAR * rd)
  732. {
  733.     int            rtn;
  734.     DWORD            cbCnt;
  735.     rtn = (int)SendMessage(rs->hwndList, LB_ADDSTRING, 0, (LPARAM)(ROWDATA FAR *)rd);
  736.     if(rtn == LB_ERRSPACE) {
  737.         cbCnt = SendMessage(rs->hwndList, LB_GETCOUNT, 0, 0L);
  738.         wsprintf(szErrMsg, szMaxRowsFetched, cbCnt);
  739.         MessageBox(rs->hwndClient, szErrMsg, szErrTitle, MB_OK);
  740.         }
  741.     return rtn;
  742. }
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749. //*------------------------------------------------------------------------
  750. //| GetNumResultsCols:
  751. //|    Given an hstmt which has an executed statement on it, find the number
  752. //|        of results columns in it.
  753. //| Parms:
  754. //|    in            hstmt                        Statement handle with results set
  755. //| Returns:
  756. //|    Number of columns
  757. //*------------------------------------------------------------------------
  758. SWORD GetNumResultsCols(HSTMT hstmt)
  759. {
  760.     SWORD cbCols;
  761.     RETCODE retcode;
  762.     
  763.     retcode = SQLNumResultCols(hstmt, &cbCols);
  764.     if(RC_NOTSUCCESSFUL(retcode))
  765.         return -1;
  766.     else
  767.         return cbCols;
  768. }
  769.  
  770.  
  771.  
  772. //*------------------------------------------------------------------------
  773. //| GetTypeName:
  774. //|    This function will return the null-terminated character name of
  775. //|    the type passed in.
  776. //| Parms:
  777. //|    in            type                        SQL_TYPE or C_TYPE
  778. //|    in            fType                        The fCType or fSqlType
  779. //| Returns:
  780. //|    Nothing.
  781. //*------------------------------------------------------------------------
  782. LPSTR GetTypeName(int type, int fType)
  783. {
  784.     int                     dex, stopdex;
  785.     DATATYPE FAR *        dt;
  786.     
  787.     if(type == SQL_TYPE) {
  788.         stopdex = NumItems(SqlTypes);
  789.         dt = (DATATYPE FAR *)&SqlTypes;
  790.         }
  791.     else {
  792.         stopdex = NumItems(CTypes);
  793.         dt = (DATATYPE FAR *)&CTypes;
  794.         }
  795.     for(dex=0;  dex<stopdex;  dex++) 
  796.         if(dt[dex].type == fType)
  797.             return dt[dex].sztype;
  798.     return (LPSTR)szTypeNotFound;
  799. }
  800.  
  801.  
  802. //*------------------------------------------------------------------------
  803. //| ConvertSqlTypeToChar:
  804. //|    This function will convert the value passed in to it's character equivalent.
  805. //| Parms:
  806. //|    in            rs                            Pointer to results set
  807. //|    in            col                        Which column is it?
  808. //|    in            inbuff                    Input buffer
  809. //|    in            outbuff                    Output buffer
  810. //|    in            rtnd                        Returned bytes from SQLGetData
  811. //| Returns:
  812. //|    Nothing.
  813. //*------------------------------------------------------------------------
  814. void ConvertSqlTypeToChar(RESULTSSET FAR * rs, int col, LPSTR inbuff, 
  815.             LPSTR outbuff, SDWORD rtnd)
  816. {
  817.     LPSTR                            tmpstr;
  818.     SWORD FAR *                    tmpsword;
  819.     SDWORD FAR *                tmpsdword;
  820.     SFLOAT FAR *                 tmpsfloat;
  821.     SDOUBLE FAR *                 tmpsdouble;
  822.     DATE_STRUCT FAR *         tmpdate;
  823.     TIME_STRUCT FAR *         tmptime;
  824.     TIMESTAMP_STRUCT FAR *    tmptimestmp;
  825.  
  826.     *outbuff = '\0';
  827.     switch(rs->md[col].fSqlType) {
  828.         //
  829.         //    Look for any non-displayable characters and change them to periods
  830.         //
  831.         case SQL_CHAR:
  832.         case SQL_VARCHAR:
  833.         case SQL_LONGVARCHAR:
  834.             CheckDisplayMode((LPSTR)inbuff, rtnd, outbuff);
  835.             tmpstr = outbuff + rtnd;
  836.             *tmpstr = '\0';
  837.             break;
  838.  
  839.         case SQL_BINARY:
  840.         case SQL_VARBINARY:
  841.         case SQL_LONGVARBINARY:
  842.             lstrcpy(outbuff, "0x");
  843.             BinToChar(outbuff+2, (LPSTR)inbuff, rtnd);
  844.             break;
  845.  
  846.         case SQL_TINYINT:
  847.         case SQL_SMALLINT:
  848.             tmpsword = (SWORD FAR *)inbuff;
  849.             wsprintf(outbuff, "%d", *tmpsword);
  850.             break;
  851.  
  852.         case SQL_INTEGER:
  853.         case SQL_BIGINT:
  854.             tmpsdword = (SDWORD FAR *)inbuff;
  855.             wsprintf(outbuff, "%ld", *tmpsdword);
  856.             break;
  857.  
  858.         case SQL_FLOAT:
  859.         case SQL_DOUBLE:
  860.             tmpsdouble = (SDOUBLE FAR *)inbuff;
  861.             sprintf(outbuff, "%Fg", *tmpsdouble);
  862.             break;
  863.  
  864.         case SQL_REAL:
  865.             tmpsfloat = (SFLOAT FAR *)inbuff;
  866.             sprintf(outbuff, "%Fg", *tmpsfloat);
  867.             break;
  868.  
  869.         case SQL_BIT:
  870.             tmpsword = (SWORD FAR *)inbuff;
  871.             lstrcpy(outbuff, (*tmpsword) ? (LPSTR)szONE : (LPSTR)szZERO);
  872.             break;
  873.  
  874.         case SQL_DECIMAL:
  875.         case SQL_NUMERIC:
  876.             lstrcpy(outbuff, inbuff);
  877.             break;
  878.  
  879.         case SQL_DATE:
  880.             tmpdate = (DATE_STRUCT FAR *)inbuff;
  881.             wsprintf(outbuff, szdate, tmpdate->month, tmpdate->day, tmpdate->year);
  882.             break;
  883.  
  884.         case SQL_TIME:
  885.             tmptime= (TIME_STRUCT FAR *)inbuff;
  886.             wsprintf(outbuff, sztime, tmptime->hour, tmptime->minute, tmptime->second);
  887.             break;
  888.  
  889.         case SQL_TIMESTAMP:
  890.             tmptimestmp = (TIMESTAMP_STRUCT FAR *)inbuff;
  891.             wsprintf(outbuff, sztimestmp, tmptimestmp->year, tmptimestmp->month,
  892.                 tmptimestmp->day, tmptimestmp->hour, tmptimestmp->minute,
  893.                 tmptimestmp->second, tmptimestmp->fraction);
  894.             break;
  895.         }
  896.  
  897.     return;
  898. }
  899.  
  900.  
  901. //*------------------------------------------------------------------------
  902. //| CheckDisplayMode:
  903. //|    This function looks through a string for the count specified, then
  904. //|        changes any x"00" to a period so it can be displayed.
  905. //| Parms:
  906. //|    strin            - String coming in
  907. //|    cbin            - Byte count of incoming string
  908. //|    strout        - Output string
  909. //*------------------------------------------------------------------------
  910. void CheckDisplayMode(LPSTR strin, SDWORD cbin, LPSTR strout)
  911. {
  912.     SDWORD        dex,max=cbin;
  913.     LPSTR        str=strout;
  914.  
  915.     if(cbin < 0)
  916.         max = lstrlen(strin);
  917.     memcpy(strout, strin, (size_t)max);
  918.     for(dex=0; dex<cbin; dex++, str++) 
  919.         if(!*str)
  920.             *str = '.';
  921. }     
  922.  
  923.  
  924. //*------------------------------------------------------------------------
  925. //| BinToChar:
  926. //|   Takes a string and converts to its hexidecimal equivalent
  927. //*------------------------------------------------------------------------
  928. void BinToChar(LPSTR outstr, LPSTR instr, SDWORD count)
  929. {
  930.     UCHAR    uletter;
  931.     LPSTR istr=instr;
  932.     LPSTR ostr=outstr;
  933.     
  934.     while(count--) {
  935.         uletter = (*instr & 0xF0) >> 4;                    // High nibble
  936.         if(uletter <= 9)
  937.             *ostr++ = uletter + '0';
  938.         else
  939.             *ostr++ = 'A' + (uletter - 10);
  940.         uletter = *instr++ & 0x0F;
  941.         if(uletter <= 9)
  942.             *ostr++ = uletter + '0';
  943.         else
  944.             *ostr++ = 'A' + (uletter - 10);
  945.         }
  946.     *ostr = '\0';
  947. }
  948.  
  949.  
  950.