home *** CD-ROM | disk | FTP | other *** search
/ TestDrive Super Store 2.3 / TESTDRIVE_2.ISO / realizer / custctrl / cclib1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-30  |  20.2 KB  |  861 lines

  1. /*
  2.  *  Custom Control Library #1
  3.  *
  4.  *  Copyright ⌐ 1991-1992 Computer Associates International, Inc.
  5.  *  All rights reserved.
  6.  */
  7.  
  8. #include <windows.h>
  9. #include "CustCtrl.h"
  10.  
  11. /*    Globals for all copies of this DLL */
  12. HANDLE    hLibInstance;
  13. FARPROC    origSBSrv;
  14. FARPROC sbFiltSrv;
  15.  
  16. /*  Window Class Names */
  17. #define    CLOCK_CLASS        "CC_Clock"
  18. #define TIMER_CLASS        "CC_Timer"
  19. #define SBAR_CLASS        "CC_ScrollBar"
  20. #define    SIZEMSG_CLASS    "CC_SizeMsg"
  21. #define    LINES_CLASS        "CC_Lines"
  22.  
  23. /* Clock definitions */
  24. #define CLOCK_FONT    0
  25. #define    CLOCK_EXTRA    2
  26.  
  27. /* Timer definitions */
  28. #define TIMER_FONT        0        /* 2 bytes, handle to font */
  29. #define TIMER_DOWNCT    2        /* 2 bytes, current down counter (65535 max) */
  30. #define TIMER_ON        4        /* 2 bytes, non-zero if on */
  31.                                 /* bit 1 always set when on */
  32.                                 /* bit 2 toggled internally to vary display */
  33. #define TIMER_FORMAT    6        /* 2 bytes, format for display: */
  34.                                 /* 0 (default): seconds only, up to 9999 */
  35.                                 /* 1: mins:secs, up to 99:59 */
  36.                                 /* 2: hrs:mins:secs, up to 18:12:15 */
  37. #define TIMER_ENDTIC    8        /* 4 bytes, GetTickCount value at which */
  38.                                 /* TIMER_DOWNCT should hit zero */
  39. #define TIMER_EXTRA        12
  40.  
  41. /* ScrollBar definitions */
  42. #define SBAR_SBAR    0        /* 2 bytes, HWND of the SCROLLBAR child */
  43. #define SBAR_FLAGS    2        /* 2 bytes, flag bits */
  44.     #define SBF_VERT    1        /* make a vertical scroll bar */
  45.     #define SBF_ALIGN1    2        /* align to full bottom or right */
  46.     #define SBF_ALIGN2    4        /* align to full minus the other scroll bar */
  47.  
  48. #define SBAR_MIN    4        /* 2 bytes, minimum */
  49. #define SBAR_MAX    6        /* 2 bytes, maximum */
  50. #define SBAR_VAL    8        /* 2 bytes, current value */
  51. #define SBAR_PAGESZ    10        /* 2 bytes, page size */
  52. #define SBAR_HADCAP    12        /* 2 bytes, BOOL TRUE if hSBar had the capture */
  53. #define SBAR_NTFVAL    14        /* SBAR_VAL at last SETNUM or notification */
  54. #define SBAR_EXTRA    16
  55.  
  56. /* Size Message definitions */
  57. #define SIZEMSG_CLASS    "CC_SizeMsg"
  58. #define SIZEMSG_EXTRA    0
  59.  
  60. /* Lines definitions */
  61. #define LINES_CLASS        "CC_Lines"
  62. #define LINES_CX        0
  63. #define LINES_CY        2
  64. #define    LINES_FILLFORM    4
  65. #define LINES_EXTRA        6
  66.  
  67. LONG FAR PASCAL ClockSrv(HWND, unsigned, WORD, LONG);
  68. LONG FAR PASCAL TimerSrv(HWND, unsigned, WORD, LONG);
  69. LONG FAR PASCAL SSFilter(HWND, unsigned, WORD, LONG);
  70. LONG FAR PASCAL ScrollSrv(HWND, unsigned, WORD, LONG);
  71. LONG FAR PASCAL SizeMsgSrv(HWND, unsigned, WORD, LONG);
  72. LONG FAR PASCAL LinesSrv(HWND, unsigned, WORD, LONG);
  73.  
  74. /*
  75.  * Custom Control General Purpose Functions
  76.  */
  77.  
  78. void NotifyParent(HWND hWnd)
  79. {
  80.     SendMessage(
  81.         GetParent(hWnd),                    /* this is the form */
  82.         WM_COMMAND,
  83.         GetWindowWord(hWnd, GWW_ID),        /* this is the item num */
  84.         MAKELONG((int)hWnd, BN_CLICKED)        /* looks like a click */
  85.     );
  86. }
  87.  
  88.  
  89. /*********************************
  90.  *  Digital Clock Custom Control 
  91.  *********************************/
  92.  
  93. typedef struct
  94. {
  95.     int hr;
  96.     int min;
  97.     int sec;
  98. } TIME;
  99.  
  100. extern void GetTime(TIME FAR *);     /* ASM function */
  101.  
  102. LONG FAR PASCAL ClockSrv(hWnd, msg, wP, lP)
  103. HWND        hWnd;
  104. unsigned    msg;
  105. WORD        wP;
  106. LONG        lP;
  107. {
  108.     TIME        time;
  109.     char        buf[10];
  110.     RECT        cr;
  111.     HFONT        hFont;
  112.     int            height;
  113.     HDC            hDC;
  114.     PAINTSTRUCT    ps;
  115.     HBRUSH        hBackBr;
  116.  
  117.     switch (msg) {
  118.  
  119.     case WM_CREATE:
  120.         SetTimer(hWnd, 1, 1000, NULL);
  121.         break;
  122.  
  123.     case WM_DESTROY:
  124.         KillTimer(hWnd, 1);
  125.         break;
  126.  
  127.     case WM_TIMER:
  128.         InvalidateRect(hWnd, NULL, TRUE);
  129.         break;
  130.  
  131.     case WM_SETFONT:
  132.         if (wP) {
  133.             SetWindowWord(hWnd, CLOCK_FONT, wP);
  134.             InvalidateRect(hWnd, NULL, TRUE);
  135.         }
  136.         break;
  137.  
  138.     case CCM_QDEFAULTSIZE:
  139.         hDC = GetDC(hWnd);
  140.         if (hFont = GetWindowWord(hWnd, CLOCK_FONT))
  141.             SelectObject(hDC, hFont);
  142.         cr.left = cr.top = 0;
  143.         cr.right = cr.bottom = 100;
  144.         height = DrawText(hDC, "99:99:99", -1, &cr, DT_SINGLELINE | DT_CALCRECT);
  145.         ReleaseDC(hWnd, hDC);
  146.         return (MAKELONG(cr.right - cr.left + 2, height + 2));
  147.  
  148.     case CCM_GETFLAGS:
  149.         return (CCF_INITGRAY | CCF_NOENABLES);
  150.  
  151.     case CCM_FORMSIZED:
  152.     case CCM_RESETCONTENT:
  153.     case CCM_GETNUM:
  154.     case CCM_SETNUM:
  155.     case CCM_GETSTRCOUNT:
  156.     case CCM_SETSTR:
  157.         break;
  158.  
  159.     case WM_ERASEBKGND:
  160.         /* let WM_PAINT do it */
  161.         return (1L);
  162.  
  163.     case WM_PAINT:
  164.         InvalidateRect(hWnd, NULL, TRUE);
  165.         BeginPaint(hWnd, &ps);
  166.         hBackBr = (HBRUSH)SendMessage(GetParent(hWnd), WM_CTLCOLOR,
  167.                                 ps.hdc, MAKELONG(hWnd, CTLCOLOR_STATIC));
  168.         FillRect(ps.hdc, &ps.rcPaint, hBackBr);
  169.  
  170.         GetTime(&time);
  171.         wsprintf(buf, "%02d:%02d:%02d", time.hr, time.min, time.sec);
  172.         GetClientRect(hWnd, &cr);
  173.         if (hFont = GetWindowWord(hWnd, CLOCK_FONT))
  174.             SelectObject(ps.hdc, hFont);
  175.  
  176.         SetBkMode(ps.hdc, TRANSPARENT);
  177.         DrawText(ps.hdc, buf, -1, &cr, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  178.         EndPaint(hWnd, &ps);
  179.         break;
  180.  
  181.     default:
  182.         return (DefWindowProc(hWnd, msg, wP, lP));
  183.     }
  184.  
  185.     return (0L);
  186. }
  187.  
  188. /***********************************
  189.  *  Countdown Timer Custom Control 
  190.  ***********************************/
  191.  
  192. void FAR pascal
  193. FormatSecs(HWND hWnd, LPSTR buf)
  194. {
  195.     WORD        wOn, wFmt, wSecs, w1, w2, w3;
  196.     PSTR        pfmt;
  197.     int            len, i;
  198.  
  199.     wOn = GetWindowWord(hWnd, TIMER_ON);
  200.     wFmt = GetWindowWord(hWnd, TIMER_FORMAT);
  201.     wSecs = GetWindowWord(hWnd, TIMER_DOWNCT);
  202.  
  203.     switch (wFmt) {
  204.  
  205.     case 2:
  206.         w1 = wSecs / 60;
  207.         w2 = wSecs % 60;
  208.         pfmt = wOn ? (w1 < 100 ? "%02d:%02d" : "**:**") : "--:--";
  209.         break;
  210.  
  211.     case 3:
  212.         w1 = wSecs / 3600;
  213.         wSecs = wSecs % 3600;
  214.         w2 = wSecs / 60;
  215.         w3 = wSecs % 60;
  216.         pfmt =  wOn ? "%02d:%02d:%02d" : "--:--:--";
  217.         break;
  218.  
  219.     default:
  220.         w1 = wSecs;
  221.         pfmt = wOn ? (w1 < 10000 ? "%d" : "****") : "-";
  222.         break;
  223.     }
  224.  
  225.     len = wsprintf(buf, pfmt, w1, w2, w3);
  226.  
  227.     if ((wOn & 2) != 0)
  228.         for (i=0; i<len; i++)
  229.             buf[i] = ' ';
  230. }
  231.  
  232. LONG FAR PASCAL TimerSrv (hWnd, msg, wP, lP)
  233. HWND        hWnd;
  234. unsigned    msg;
  235. WORD        wP;
  236. LONG        lP;
  237. {
  238.     PAINTSTRUCT    ps;
  239.     RECT        cr;
  240.     HBRUSH        hBackBr;
  241.     HFONT        hFont;
  242.     HDC            hDC;
  243.     LPLONG        lpLong;
  244.     PSTR        pSampText;
  245.     LONG        lTick;
  246.     WORD        wOn;
  247.     int            height, wCount;
  248.     char        buf[10];
  249.  
  250.     switch (msg) {
  251.  
  252.     case WM_DESTROY:
  253.         if (GetWindowWord(hWnd, TIMER_ON))
  254.             KillTimer(hWnd, 1);
  255.         break;
  256.  
  257.     case WM_TIMER:
  258.         if (wOn = GetWindowWord(hWnd, TIMER_ON)) {
  259.             InvalidateRect(hWnd, NULL, TRUE);
  260.             if (wCount = GetWindowWord(hWnd, TIMER_DOWNCT)) {
  261.                 lTick = GetWindowLong(hWnd, TIMER_ENDTIC);
  262.                 lTick = (lTick - GetTickCount() + 500) / 1000;
  263.                 if (HIWORD(lTick))
  264.                     wCount = 0;
  265.                 else
  266.                     wCount = LOWORD(lTick);
  267.                 SetWindowWord(hWnd, TIMER_DOWNCT, wCount);
  268.             } else {
  269.                 SetWindowWord(hWnd, TIMER_ON, wOn ^ 2);
  270.             }
  271.             if (wCount == 0)
  272.                 NotifyParent(hWnd);
  273.         }
  274.         break;
  275.  
  276.     case WM_SETFONT:
  277.         if (wP) {
  278.             SetWindowWord(hWnd, TIMER_FONT, wP);
  279.             InvalidateRect(hWnd, NULL, TRUE);
  280.         }
  281.         break;
  282.  
  283.     case CCM_SETNUM:
  284.         lpLong = (LPLONG)lP;
  285.         lTick = lpLong[0];
  286.         if (lTick < -1 || lTick > 65535) 
  287.             return (0);    /* nSecs out of range */
  288.  
  289.         /* NOTE: allow 1st modifier to be -1 for no change */
  290.  
  291.         if (lTick >= 0) {
  292.             SetWindowWord(hWnd, TIMER_DOWNCT, LOWORD(lTick));
  293.             InvalidateRect(hWnd, NULL, TRUE);
  294.             KillTimer(hWnd, 1);                    /* re-synchronize */
  295.             if (lTick == 0)
  296.                 SetWindowWord(hWnd, TIMER_ON, 0);
  297.             else {
  298.                 SetWindowWord(hWnd, TIMER_ON, 1);
  299.                 if (!SetTimer(hWnd, 1, 1000, NULL))
  300.                     return(0);
  301.                 SetWindowLong(hWnd, TIMER_ENDTIC, 
  302.                                 lTick * 1000 + GetTickCount());
  303.             }
  304.         }
  305.         if (wP > 1) {
  306.             lTick = lpLong[1];
  307.             if (lTick < 1 || lTick > 3) 
  308.                 return (-1);    /* Error: format out of range */
  309.             SetWindowWord(hWnd, TIMER_FORMAT, LOWORD(lTick));
  310.             InvalidateRect(hWnd, NULL, TRUE);
  311.         }
  312.         if (wP > 2) return (-2);    /* Error: at most 2 modifiers */
  313.         return (1);                    /* OK */
  314.  
  315.     case CCM_GETNUM:
  316.         if (GetWindowWord(hWnd, TIMER_ON))
  317.             return (GetWindowWord(hWnd, TIMER_DOWNCT));
  318.         else
  319.             return (-1L);
  320.  
  321.     case CCM_QDEFAULTSIZE:
  322.         hDC = GetDC(hWnd);
  323.         if (hFont = GetWindowWord(hWnd, TIMER_FONT))
  324.             SelectObject(hDC, hFont);
  325.         cr.left = cr.top = 0;
  326.         cr.right = cr.bottom = 100;
  327.         switch (GetWindowWord(hWnd, TIMER_FORMAT)) {
  328.             case 2:        pSampText = "99:99";        break;
  329.             case 3:        pSampText = "99:99:99";        break;
  330.             default:    pSampText = "9999";            break;
  331.         }
  332.         height = DrawText(hDC, pSampText, -1, &cr, DT_SINGLELINE | DT_CALCRECT);
  333.         ReleaseDC(hWnd, hDC);
  334.         return (MAKELONG(cr.right - cr.left + 2, height + 2));
  335.  
  336.     case CCM_GETFLAGS:
  337.         return (CCF_INITGRAY | CCF_NOENABLES);
  338.  
  339.     case WM_ERASEBKGND:
  340.         /* let WM_PAINT do it */
  341.         return (1L);
  342.  
  343.     case WM_PAINT:
  344.         InvalidateRect(hWnd, NULL, TRUE);    /* always do whole clock */
  345.         BeginPaint(hWnd, &ps);
  346.         hBackBr = (HBRUSH)SendMessage(GetParent(hWnd), WM_CTLCOLOR,
  347.                                 ps.hdc, MAKELONG(hWnd, CTLCOLOR_STATIC));
  348.         FillRect(ps.hdc, &ps.rcPaint, hBackBr);
  349.  
  350.         FormatSecs(hWnd, buf);
  351.         GetClientRect(hWnd, &cr);
  352.         if (hFont = GetWindowWord(hWnd, TIMER_FONT))
  353.             SelectObject(ps.hdc, hFont);
  354.  
  355.         SetBkMode(ps.hdc, TRANSPARENT);
  356.         DrawText(ps.hdc, buf, -1, &cr, DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
  357.         EndPaint(hWnd, &ps);
  358.         break;
  359.  
  360.     case CCM_FORMSIZED:
  361.     case CCM_RESETCONTENT:
  362.     case CCM_GETSTRCOUNT:
  363.     case CCM_SETSTR:
  364.         break;
  365.  
  366.     default:
  367.         return (DefWindowProc(hWnd, msg, wP, lP));
  368.     }
  369.  
  370.     return (0L);
  371. }
  372.  
  373. /***********************************
  374.  *    Scroll Bar Custom Control 
  375.  ***********************************/
  376.  
  377. void FAR pascal RedoSbar(HWND hwT)
  378. {
  379.     HWND        hSBar;
  380.     int            minPos, maxPos, curPos, minAct, maxAct, curAct;
  381.  
  382.     if (!(hSBar = GetWindowWord(hwT, SBAR_SBAR))) return;
  383.  
  384.     minPos = GetWindowWord(hwT, SBAR_MIN);
  385.     maxPos = GetWindowWord(hwT, SBAR_MAX);
  386.     curPos = GetWindowWord(hwT, SBAR_VAL);
  387.  
  388.     GetScrollRange(hSBar, SB_CTL, &minAct, &maxAct);
  389.     curAct = GetScrollPos(hSBar, SB_CTL);
  390.  
  391.     if (minAct != minPos || maxAct != maxPos)
  392.         SetScrollRange(hSBar, SB_CTL, minPos, maxPos, curPos == curAct);
  393.  
  394.     if (curPos != curAct)
  395.         SetScrollPos(hSBar, SB_CTL, curPos, TRUE);
  396. }
  397.  
  398. void SBarMayNotify(HWND hItemW)
  399. {
  400.     int            curPos;
  401.  
  402.     curPos = GetWindowWord(hItemW, SBAR_VAL);
  403.     if (curPos != GetWindowWord(hItemW, SBAR_NTFVAL)) {
  404.         SetWindowWord(hItemW, SBAR_NTFVAL, curPos);
  405.         NotifyParent(hItemW);
  406.     }
  407. }
  408.  
  409. LONG FAR PASCAL SSFilter(hSBar, msg, wP, lP)
  410. HWND        hSBar;
  411. unsigned    msg;
  412. WORD        wP;
  413. LONG        lP;
  414. {
  415.     LONG        retVal;
  416.     BOOL        bCaptured;
  417.     HWND        hItemW;
  418.  
  419.     retVal = CallWindowProc(origSBSrv, hSBar, msg, wP, lP);
  420.  
  421.     bCaptured = GetCapture() == hSBar;
  422.     hItemW = GetParent(hSBar);
  423.  
  424.     if (bCaptured != GetWindowWord(hItemW, SBAR_HADCAP)) {
  425.         if (!bCaptured)
  426.             SBarMayNotify(hItemW);
  427.         SetWindowWord(hItemW, SBAR_HADCAP, bCaptured);
  428.     }
  429.     return (retVal);
  430. }
  431.  
  432.  
  433. LONG FAR PASCAL ScrollSrv(hWnd, msg, wP, lP)
  434. HWND        hWnd;
  435. unsigned    msg;
  436. WORD        wP;
  437. LONG        lP;
  438. {
  439.     HWND        hSBar, hParW;
  440.     RECT        cr;
  441.     DWORD        classWS;
  442.     int            defWd, defHt;
  443.     int            minPos, maxPos, curPos, delta;
  444.     int            thisM, minPosM, curPosM;
  445.     BOOL        upFlag, bb, bHorz, bAlign1, bAlign2;
  446.     WORD        sbflags;
  447.     LONG        lt;
  448.     LPLONG        lpl;
  449.  
  450.     switch (msg) {
  451.  
  452.     case WM_CREATE:
  453.         /*    make a horizontal scroll bar unless FormSetObject modifier
  454.             causes override.
  455.         */
  456.         SetWindowWord(hWnd, SBAR_MAX, 100);
  457.         SetWindowWord(hWnd, SBAR_PAGESZ, -10);    /* default to 10 pct */
  458.         break;
  459.  
  460.     case CCM_FORMSIZED:
  461.         /*    Abbreviated version of CCM_QDEFAULTSIZE code */
  462.         sbflags = GetWindowWord(hWnd, SBAR_FLAGS);
  463.         bHorz = (sbflags & SBF_VERT) == 0;
  464.         bAlign1 = (sbflags & SBF_ALIGN1) != 0;
  465.         bAlign2 = (sbflags & SBF_ALIGN2) != 0;
  466.  
  467.         if (!(bAlign1 || bAlign2)) break;
  468.  
  469.         GetClientRect(GetParent(hWnd), &cr);
  470.         InflateRect(&cr, 1, 1);        /* slip border underneath edge */
  471.         if (bHorz) {
  472.             defHt = GetSystemMetrics(SM_CYHSCROLL);
  473.             defWd = cr.right - cr.left;
  474.             if (bAlign2)
  475.                 defWd -= (GetSystemMetrics(SM_CXVSCROLL) - 1);
  476.             cr.top = cr.bottom - defHt;
  477.         } else {
  478.             defWd = GetSystemMetrics(SM_CXVSCROLL);
  479.             defHt = cr.bottom - cr.top;
  480.             if (bAlign2)
  481.                 defHt -= (GetSystemMetrics(SM_CYHSCROLL) - 1);
  482.             cr.left = cr.right - defWd;
  483.         }
  484.         MoveWindow(hWnd, cr.left, cr.top, defWd, defHt, TRUE);
  485.         break;
  486.  
  487.     case CCM_QDEFAULTSIZE:
  488.         SendMessage(hWnd, CCM_FORMSIZED, 0, 0L);
  489.             /* adjust item's client rect in case aligning */
  490.  
  491.         sbflags = GetWindowWord(hWnd, SBAR_FLAGS);
  492.         bHorz = (sbflags & SBF_VERT) == 0;
  493.  
  494.         GetClientRect(hWnd, &cr);
  495.         hSBar = CreateWindow("SCROLLBAR", "",
  496.             WS_CHILD | WS_VISIBLE | (bHorz ? SBS_HORZ : SBS_VERT),
  497.             cr.left, cr.top, cr.right - cr.left, cr.bottom - cr.top,
  498.             hWnd, 1, GetWindowWord(hWnd, GWW_HINSTANCE), 0L);
  499.         if (!hSBar) return (-1L);
  500.  
  501.         if (!sbFiltSrv) {
  502.             sbFiltSrv = MakeProcInstance((FARPROC)SSFilter, hLibInstance);
  503.             origSBSrv = (FARPROC)GetWindowLong(hSBar, GWL_WNDPROC);
  504.         }
  505.         SetWindowLong(hSBar, GWL_WNDPROC, (LONG)sbFiltSrv);
  506.     
  507.         SetWindowWord(hWnd, SBAR_SBAR, hSBar);
  508.         RedoSbar(hWnd);
  509.  
  510.         bAlign1 = (sbflags & SBF_ALIGN1) != 0;
  511.         bAlign2 = (sbflags & SBF_ALIGN2) != 0;
  512.         if (bAlign1 || bAlign2)
  513.             return (-2L);
  514.  
  515.         if (bHorz) {
  516.             defHt = GetSystemMetrics(SM_CYHSCROLL);
  517.             defWd = 100 + 2 * GetSystemMetrics(SM_CXHSCROLL);
  518.         } else {
  519.             defWd = GetSystemMetrics(SM_CXVSCROLL);
  520.             defHt = 100 + 2 * GetSystemMetrics(SM_CYVSCROLL);
  521.         }
  522.         return (MAKELONG(defWd, defHt));
  523.  
  524.     case WM_SIZE:
  525.         if (hSBar = GetWindowWord(hWnd, SBAR_SBAR))
  526.             MoveWindow(hSBar, 0, 0, LOWORD(lP), HIWORD(lP), TRUE);
  527.         break;
  528.  
  529.     case WM_HSCROLL:
  530.     case WM_VSCROLL:
  531.         if (hSBar = GetWindowWord(hWnd, SBAR_SBAR)) {
  532.             upFlag = TRUE;
  533.             minPos = GetWindowWord(hWnd, SBAR_MIN);
  534.             maxPos = GetWindowWord(hWnd, SBAR_MAX);
  535.             switch (wP) {
  536.  
  537.             case SB_LINEDOWN:
  538.                 upFlag = FALSE;
  539.             case SB_LINEUP:
  540.                 delta = 1;
  541.                 break;
  542.  
  543.             case SB_PAGEDOWN:
  544.                 upFlag = FALSE;
  545.             case SB_PAGEUP:
  546.                 delta = GetWindowWord(hWnd, SBAR_PAGESZ);
  547.                 if (delta < 0) {
  548.                     /* delta is a percentage */
  549.                     lt = maxPos - minPos;
  550.                     delta = (int)((lt * -delta) / 100);
  551.                 }
  552.                 if (delta < 1) delta = 1;
  553.                 break;
  554.  
  555.             case SB_THUMBPOSITION:
  556.                 curPos = LOWORD(lP);
  557.                 delta = 0;
  558.                 break;
  559.  
  560.             default:
  561.                 return (0L);
  562.             }
  563.  
  564.             if (delta) {
  565.                 if (upFlag) delta = -delta;
  566.                 curPos = GetWindowWord(hWnd, SBAR_VAL) + delta;
  567.             }
  568.  
  569.             if (curPos > maxPos)
  570.                 curPos = maxPos;
  571.             else if (curPos < minPos)
  572.                 curPos = minPos;
  573.  
  574.             if (curPos != GetWindowWord(hWnd, SBAR_VAL)) {
  575.                 SetWindowWord(hWnd, SBAR_VAL, curPos);
  576.                 SetScrollPos(hSBar, SB_CTL, curPos, TRUE);
  577.                 if (wP == SB_THUMBPOSITION)
  578.                     SBarMayNotify(hWnd);
  579.             }
  580.         }
  581.         break;
  582.  
  583.     case WM_ENABLE:
  584.         if (hSBar = GetWindowWord(hWnd, SBAR_SBAR))
  585.             EnableWindow(hSBar, wP);
  586.         break;
  587.  
  588.     case CCM_SETNUM:
  589.         /*    return:
  590.                 >= 1:                AOK,
  591.                 -k, 0 <= k < wP:    failed at lpl[k]
  592.         */
  593.         lpl = (LPLONG)lP;
  594.         thisM = 0;
  595.         lt = lpl[thisM];
  596.         hSBar = GetWindowWord(hWnd, SBAR_SBAR);
  597.             /* NULL if from FormSetObject */
  598.         if (!hSBar && lt >= CCSTYLE) {
  599.             SetWindowWord(hWnd, SBAR_FLAGS, LOWORD(lt));
  600.             thisM++;
  601.         }
  602.         if (thisM >= wP) return (1);
  603.  
  604.         /* set current value */
  605.         minPos = GetWindowWord(hWnd, SBAR_MIN);
  606.         maxPos = GetWindowWord(hWnd, SBAR_MAX);
  607.  
  608.         curPosM = thisM++;
  609.         lt = lpl[curPosM];
  610.         if (lt < -32767 || lt > 32767) return (-curPosM);
  611.         curPos = LOWORD(lt);
  612.  
  613.         if (thisM < wP) {
  614.             minPosM = thisM;
  615.             lt = lpl[thisM];
  616.             if (lt < -32767 || lt > 32767) return (-minPosM);
  617.             minPos = LOWORD(lt);
  618.             thisM++;
  619.             if (thisM < wP) {
  620.                 lt = lpl[thisM];
  621.                 if (lt < -32767 || lt > 32767) return (-thisM);
  622.                 maxPos = LOWORD(lt);
  623.                 thisM++;
  624.                 if (thisM < wP) {
  625.                     lt = lpl[thisM];
  626.                     if (lt < -32767 || lt > 32767) return (-thisM);
  627.                     SetWindowWord(hWnd, SBAR_PAGESZ, LOWORD(lt));
  628.                     thisM++;
  629.                 }
  630.             }
  631.         }
  632.         if (curPos < minPos || curPos > maxPos) return (-curPosM);
  633.         if ((LONG)maxPos - minPos > 32767) return (-minPosM);
  634.  
  635.         if (thisM < wP) return (-thisM);
  636.  
  637.         SetWindowWord(hWnd, SBAR_MIN, minPos);
  638.         SetWindowWord(hWnd, SBAR_MAX, maxPos);
  639.         SetWindowWord(hWnd, SBAR_VAL, curPos);
  640.         SetWindowWord(hWnd, SBAR_NTFVAL, curPos);
  641.  
  642.         RedoSbar(hWnd);
  643.  
  644.         return (1);                /* AOK */
  645.  
  646.     case CCM_GETNUM:
  647.         return ((int)GetWindowWord(hWnd, SBAR_VAL));
  648.  
  649.     case CCM_GETSTRCOUNT:
  650.     case CCM_GETSTRLEN:
  651.     case CCM_GETSTR:
  652.     case CCM_SETSTR:
  653.     case CCM_RESETCONTENT:
  654.         return (0L);
  655.  
  656.     default:
  657.         return (DefWindowProc(hWnd, msg, wP, lP));
  658.     }
  659.  
  660.     return (0L);
  661. }
  662.  
  663.  
  664. /***********************************
  665.  *    Size Message Custom Control 
  666.  ***********************************/
  667.  
  668. LONG FAR PASCAL SizeMsgSrv(hWnd, msg, wP, lP)
  669. HWND        hWnd;
  670. unsigned    msg;
  671. WORD        wP;
  672. LONG        lP;
  673. {
  674.     switch (msg) {
  675.  
  676.     case CCM_FORMSIZED:
  677.         NotifyParent(hWnd);
  678.         break;
  679.  
  680.     case CCM_QDEFAULTSIZE:
  681.         MoveWindow(hWnd, -10, -10, 3, 3, 0);
  682.         return (-2L);
  683.                 
  684.     case CCM_GETFLAGS:
  685.     case CCM_GETNUM:
  686.     case CCM_SETNUM:
  687.     case CCM_GETSTRCOUNT:
  688.     case CCM_GETSTRLEN:
  689.     case CCM_GETSTR:
  690.     case CCM_SETSTR:
  691.     case CCM_RESETCONTENT:
  692.         return (0L);
  693.  
  694.     default:
  695.         return (DefWindowProc(hWnd, msg, wP, lP));
  696.     }
  697.     return (0L);
  698. }
  699.  
  700. /***********************************
  701.  *    Lines Demo Custom Control 
  702.  ***********************************/
  703.  
  704. LONG FAR PASCAL LinesSrv (hWnd, msg, wP, lP)
  705. HWND        hWnd;
  706. unsigned    msg;
  707. WORD        wP;
  708. LONG        lP;
  709. {
  710.     HDC            hDC;
  711.     PAINTSTRUCT    ps;
  712.     HBRUSH        hBackBr;
  713.     HPEN        hOldPen;
  714.     RECT        cr;
  715.     int            x, y, cx, cy;
  716.  
  717.     switch (msg) {
  718.  
  719.     case WM_CREATE:
  720.         SetWindowWord(hWnd, LINES_CX, 1);
  721.         SetWindowWord(hWnd, LINES_CY, 1);
  722.         SetWindowWord(hWnd, LINES_FILLFORM, 0);
  723.         break;
  724.  
  725.     case CCM_QDEFAULTSIZE:
  726.         if (GetWindowWord(hWnd, LINES_FILLFORM))
  727.             return(-3L);
  728.         return (MAKELONG(200, 100));
  729.  
  730.     case CCM_GETFLAGS:
  731.     case CCM_GETNUM:
  732.     case CCM_GETSTR:
  733.     case CCM_GETSTRCOUNT:
  734.     case CCM_GETSTRLEN:
  735.         return (0);
  736.  
  737.     case CCM_SETNUM:
  738.         SetWindowWord(hWnd, LINES_FILLFORM, wP);
  739.         return(1L);
  740.  
  741.     case WM_ERASEBKGND:
  742.         /* let WM_PAINT do it */
  743.         return (1L);
  744.  
  745.     case WM_PAINT:
  746.         BeginPaint(hWnd, &ps);
  747.         hBackBr = (HBRUSH)SendMessage(GetParent(hWnd), WM_CTLCOLOR,
  748.                                 ps.hdc, MAKELONG(hWnd, CTLCOLOR_STATIC));
  749.         FillRect(ps.hdc, &ps.rcPaint, hBackBr);
  750.  
  751.         hOldPen = SelectObject(ps.hdc, 
  752.             CreatePen(PS_SOLID, 1, GetTextColor(ps.hdc)));
  753.  
  754.         GetClientRect(hWnd, &cr);
  755.         cx = GetWindowWord(hWnd, LINES_CX);
  756.         cy = GetWindowWord(hWnd, LINES_CY);
  757.         for (x = 0; x < cr.right; x+=3) {
  758.             MoveTo(ps.hdc, cx, cy);
  759.             LineTo(ps.hdc, x, 0);
  760.         }
  761.         for (y = 0; y < cr.bottom; y+=3) {
  762.             MoveTo(ps.hdc, cx, cy);
  763.             LineTo(ps.hdc, cr.right, y);
  764.         }
  765.         for (x = cr.right; x >= 0; x-=3) {
  766.             MoveTo(ps.hdc, cx, cy);
  767.             LineTo(ps.hdc, x, cr.bottom);
  768.         }
  769.         for (y = cr.bottom; y >= 0; y-=3) {
  770.             MoveTo(ps.hdc, cx, cy);
  771.             LineTo(ps.hdc, 0, y);
  772.         }
  773.         DeleteObject(SelectObject(ps.hdc, hOldPen));
  774.         EndPaint(hWnd, &ps);
  775.         break;
  776.  
  777.     case CCM_FORMSIZED:
  778.         if (GetWindowWord(hWnd, LINES_FILLFORM)) {
  779.             GetClientRect(GetParent(hWnd), &cr);
  780.             MoveWindow(hWnd, cr.left, cr.top, cr.right, cr.bottom, TRUE);    
  781.             SetWindowWord(hWnd, LINES_CX, (cr.right - cr.left)/2);
  782.             SetWindowWord(hWnd, LINES_CY, (cr.bottom - cr.top)/2);
  783.         }
  784.         break;
  785.  
  786.     case WM_LBUTTONDOWN:
  787.         SetWindowWord(hWnd, LINES_CX, LOWORD(lP));
  788.         SetWindowWord(hWnd, LINES_CY, HIWORD(lP));
  789.         InvalidateRect(hWnd, NULL, TRUE);
  790.  
  791.     default:
  792.         return (DefWindowProc(hWnd, msg, wP, lP));
  793.     }
  794.     return (0L);
  795. }
  796.  
  797. /*
  798.  *  Standard DLL Functions
  799.  */
  800.  
  801. int FAR PASCAL LibMain(hInstance, wDataSegment, wHeapSize, lpszCmdLine)
  802. HANDLE      hInstance;
  803. WORD        wDataSegment;
  804. WORD        wHeapSize;
  805. LPSTR       lpszCmdLine;
  806. {
  807.     WNDCLASS        wc;
  808.  
  809.     if (hLibInstance) return (TRUE);
  810.  
  811.     /* define class attributes */
  812.     wc.style =            CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
  813.     wc.lpfnWndProc =    ClockSrv;
  814.     wc.cbClsExtra =        0;
  815.     wc.cbWndExtra =        CLOCK_EXTRA;
  816.     wc.hInstance =        hInstance;
  817.     wc.hIcon =            NULL;
  818.     wc.hCursor =        LoadCursor(NULL, IDC_ARROW);
  819.     wc.hbrBackground =    (HBRUSH)(COLOR_WINDOW + 1);
  820.     wc.lpszMenuName =    NULL;
  821.     wc.lpszClassName =     CLOCK_CLASS;
  822.  
  823.     if (!RegisterClass(&wc)) return (FALSE);
  824.  
  825.     wc.lpfnWndProc =    TimerSrv;
  826.     wc.cbWndExtra =        TIMER_EXTRA;
  827.     wc.lpszClassName =    TIMER_CLASS;
  828.  
  829.     if (!RegisterClass(&wc)) return (FALSE);
  830.  
  831.     wc.lpfnWndProc =    ScrollSrv;
  832.     wc.cbWndExtra =        SBAR_EXTRA;
  833.     wc.lpszClassName =    SBAR_CLASS;
  834.  
  835.     if (!RegisterClass(&wc)) return (FALSE);
  836.  
  837.     wc.lpfnWndProc =    SizeMsgSrv;
  838.     wc.cbWndExtra =        SIZEMSG_EXTRA;
  839.     wc.lpszClassName =     SIZEMSG_CLASS;
  840.  
  841.     if (!RegisterClass(&wc)) return (FALSE);
  842.  
  843.     wc.lpfnWndProc =    LinesSrv;
  844.     wc.cbWndExtra =        LINES_EXTRA;
  845.     wc.lpszClassName =     LINES_CLASS;
  846.  
  847.     if (!RegisterClass(&wc)) return (FALSE);
  848.  
  849.     hLibInstance = hInstance;
  850.  
  851.     return (TRUE);
  852. }
  853.  
  854. VOID FAR pascal WEP(bSystemExit)
  855. int  bSystemExit;
  856. {
  857.     if (sbFiltSrv)
  858.         FreeProcInstance(sbFiltSrv);
  859.     return;
  860. }
  861.