RESULTS.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:32k
源码类别:

Windows编程

开发平台:

Visual C++

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