home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / primcuts.zip / DebugTerminal / TerminalWindow.c < prev    next >
Text File  |  2000-08-26  |  33KB  |  1,161 lines

  1. #pragma strings(readonly)
  2. /*---------------------------------------------------------------------------*\
  3.  *    Title: Kernel Debugger Terminal Window Procedure                       *
  4.  * Filename: TerminalWindow.c                                                *
  5.  *     Date: 2000-02-26                                                      *
  6.  *   Author: Jan M. Danielsson                                               *
  7.  *           Note: This source is heavily based on the PM Terminal written   *
  8.  *           by Peter Fitzsimmons.                                           *
  9.  *                                                                           *
  10.  *  Notes: This source is - apart from being based on pmtermsr.zip - also    *
  11.  *         ripped out from a kernel debugging terminal I'm working on.       *
  12.  *         Expect odd comments in odd places.                                *
  13. \*---------------------------------------------------------------------------*/
  14. #define INCL_WINWINDOWMGR
  15. #define INCL_WINSYS
  16. #define INCL_WINSHELLDATA
  17. #define INCL_WINFRAMEMGR
  18. #define INCL_WINSCROLLBARS
  19. #define INCL_WINTRACKRECT
  20. #define INCL_WININPUT                    /* WM_CHAR */
  21. #define INCL_WINENTRYFIELDS
  22. #define INCL_WINDIALOGS
  23. #define INCL_WINSTDSPIN
  24. #define INCL_WINLISTBOXES
  25. #define INCL_WINBUTTONS
  26. #define INCL_WINMENUS
  27. #define INCL_GPILCIDS
  28. #define INCL_DOSSEMAPHORES
  29. #define INCL_DOSPROCESS
  30. #define INCL_DOSDEVICES
  31. #define INCL_DOSDEVIOCTL
  32. #define INCL_DOSERRORS
  33.  
  34. #include <os2.h>
  35.  
  36. #ifdef DEBUG
  37. #include <stdio.h>
  38. #endif
  39.  
  40. #include <malloc.h>
  41. #include <memory.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44.  
  45. #include <res.h>
  46.  
  47. #include <TerminalWindow.h>
  48.  
  49.  
  50. #ifdef USE_UNDOC
  51. /* Undocumented event semaphore flags */
  52. #define DCE_POSTONE                      0x0800   /* Post only to one waiting thread (in case there are multiple) */
  53. #define DCE_AUTORESET                    0x1000   /* Automatically reset semaphore after a post.                  */
  54. #endif
  55.  
  56.  
  57.  
  58.  
  59. /*
  60.  * Internal structures
  61.  */
  62. typedef struct _TERMLINE
  63. {
  64.    USHORT cbChars;                       /* Characters used in line */
  65.    PBYTE buf;
  66.    BOOL fEOL;                            /* Line has recieved a valid EOL */
  67.    LONG lTextColor;
  68. }TERMLINE, *PTERMLINE;
  69.  
  70. typedef struct _TERMINFO
  71. {
  72.    HWND hWnd;
  73.    HFILE hPipe;                          /* Pipe handle */
  74.    LONG rows;                            /* Terminal height */
  75.    LONG columns;                         /* Terminal width  */
  76.    POINTL cursor;
  77.    BOOL fLogFile;
  78.    HFILE hfLogFile;
  79.    PTERMLINE lines;
  80. }TERMINFO, *PTERMINFO;
  81.  
  82. typedef struct _SCROLLBARVAL
  83. {
  84.    LONG h;
  85.    LONG v;
  86. }SCROLLBARVAL, *PSCROLLBARVAL;
  87.  
  88. typedef struct _WINDOWDATA
  89. {
  90.    SIZEL sizlClient;                     /* Client size in pels                          */
  91.    SIZEL sizlChar;                       /* Size of characters in pels                   */
  92.    SIZEL sizlChars;                      /* Characters visible on screen (client/char)   */
  93.    LONG yDesc;
  94.    FONTMETRICS fm;
  95.    SCROLLBARVAL scrollMax;
  96.    SCROLLBARVAL scrollPos;
  97.    TERMINFO ti;
  98.    HWND hwndHorzScroll;
  99.    HWND hwndVertScroll;
  100. }WINDOWDATA, *PWINDOWDATA;
  101.  
  102.  
  103.  
  104.  
  105. /*
  106.  * Structure stored at QWL_USER in framewindow dataarea for mapwindow frame
  107.  */
  108. typedef struct _FRAMEWINDOWUSERDATA
  109. {
  110.    PFNWP pfnOldProc;
  111.    ULONG ulMaxWidth;                     /* Maximum width of frame */
  112.    ULONG ulMaxHeight;                    /* Maximum height of frame */
  113.    HWND hwndClient;
  114. }FRAMEWINDOWUSERDATA, *PFRAMEWINDOWUSERDATA;
  115.  
  116.  
  117.  
  118.  
  119. #define QWP_WINDOWDATA                   0
  120. #define QW_EXTRA                         QWP_WINDOWDATA+sizeof(PWINDOWDATA)
  121.  
  122.  
  123. /* Client user messages */
  124. #define WMU_CLEAR                        WM_USER+1
  125. #define WMU_PAINTLINES                   WM_USER+2
  126. #define WMU_PRESCROLL                    WM_USER+3
  127.  
  128.  
  129. /* Frame user messages */
  130. #define WMU_RECALCMAXSIZE                WM_USER+1
  131.  
  132. /*
  133.  * Function prototypes - Local functions
  134.  */
  135. static MRESULT EXPENTRY WindowProcedure(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  136. static MRESULT _Optlink processCreateMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  137. static void _Optlink processAdjustWindowPosMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  138. static void _Optlink processSizeMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  139. static void _Optlink processPaintMessage(HWND hWnd);
  140. static void _Optlink processHScrollMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  141. static void _Optlink processVScrollMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  142. static void _Optlink processPresParamsChangedMessage(HWND hWnd, MPARAM mp1);
  143. static void _Optlink processDestroyMessage(HWND hWnd);
  144.  
  145. static void _Optlink processClearMessage(HWND hWnd);
  146.  
  147. static void _Optlink processPaintLinesMessage(HWND hWnd, LONG startline, LONG endline);
  148. static void _Optlink processPreScrollMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  149.  
  150.  
  151. static BOOL _Optlink init_terminfo(PTERMINFO ti);
  152. static BOOL _Optlink term_terminfo(PTERMINFO ti);
  153.  
  154. static void _Optlink term_print(HWND hWnd, char *pchBuf, ULONG cbBuf);
  155.  
  156.  
  157. static BOOL _Optlink vScrollParms(HWND hWnd, ULONG row, ULONG rows);
  158. static BOOL _Optlink hScrollParms(HWND hWnd, ULONG col, ULONG cols);
  159.  
  160. static void Adjust(HWND hWnd, LONG line1, LONG line2);
  161.  
  162.  
  163. /* Frame window subclassing functions */
  164. static BOOL _Optlink subclassFrameProc(HWND hwndClient);
  165. static MRESULT EXPENTRY FrameSubProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  166. static void _Optlink processFrameAdjustWindowPosMessage(HWND hWnd, MPARAM mp1, MPARAM mp2);
  167. static MRESULT _Optlink processFrameQueryTrackInfo(HWND hWnd, MPARAM mp1, MPARAM mp2);
  168. static void _Optlink processFrameRecalcMaxSize(HWND hwndFrame);
  169.  
  170.  
  171. static void _Optlink rcvthread(void *param);
  172.  
  173.  
  174.  
  175.  
  176. static MRESULT EXPENTRY TerminalSettingsDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  177. static MRESULT EXPENTRY AboutDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  178.  
  179.  
  180.  
  181.  
  182. BOOL _Optlink registerTerminalWindow(HAB hAB)
  183. {
  184.    BOOL fSuccess = FALSE;
  185.  
  186.    fSuccess = WinRegisterClass(hAB, WC_TERMINALWINDOW, WindowProcedure, CS_SIZEREDRAW, QW_EXTRA);
  187.  
  188.    return fSuccess;
  189. }
  190.  
  191.  
  192.  
  193.  
  194.  
  195. static MRESULT EXPENTRY WindowProcedure(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  196. {
  197.    MRESULT mReturn = NULL;
  198.    BOOL fHandled = TRUE;
  199.  
  200.    switch(msg)
  201.    {
  202.       case WM_CREATE:
  203.          mReturn = processCreateMessage(hWnd, mp1, mp2);
  204.          break;
  205.  
  206.       case WM_ADJUSTWINDOWPOS:
  207.          processAdjustWindowPosMessage(hWnd, mp1, mp2);
  208.          break;
  209.  
  210.       case WM_SIZE:
  211.          processSizeMessage(hWnd, mp1, mp2);
  212.          break;
  213.  
  214.       case WM_PAINT:
  215.          processPaintMessage(hWnd);
  216.          break;
  217.  
  218.       case WM_COMMAND:
  219.          switch(SHORT1FROMMP(mp1))
  220.          {
  221.             case IDM_TERMINAL_ABOUT:
  222.                WinDlgBox(HWND_DESKTOP, hWnd, AboutDlgProc, (HMODULE)NULLHANDLE, DLG_ABOUT, NULL);
  223.                break;
  224.  
  225.             case IDM_TERMINAL_CLEAR:
  226.                WinPostMsg(hWnd, WMU_CLEAR, MPVOID, MPVOID);
  227.                break;
  228.  
  229.             case IDM_TERMINAL_EXIT:
  230.                WinPostMsg(hWnd, WM_CLOSE, MPVOID, MPVOID);
  231.                break;
  232.  
  233.             case IDM_OPTIONS_SAVEWINPOS:
  234.                {
  235.                   SWP swp = { 0 };
  236.                   WinQueryWindowPos(WinQueryWindow(hWnd, QW_PARENT), &swp);
  237.                   PrfWriteProfileData(HINI_USERPROFILE, "PMDebugTerminal", "Window Position", &swp, sizeof(swp));
  238.                }
  239.                break;
  240.  
  241.             default:
  242.                fHandled = FALSE;
  243.                break;
  244.          }
  245.          break;
  246.  
  247.       case WM_HSCROLL:
  248.          processHScrollMessage(hWnd, mp1, mp2);
  249.          break;
  250.  
  251.       case WM_VSCROLL:
  252.          processVScrollMessage(hWnd, mp1, mp2);
  253.          break;
  254.  
  255.       case WM_PRESPARAMCHANGED:
  256.          processPresParamsChangedMessage(hWnd, mp1);
  257.          break;
  258.  
  259.       case WM_DESTROY:
  260.          processDestroyMessage(hWnd);
  261.          break;
  262.  
  263.       case WM_ERASEBACKGROUND:
  264.          mReturn = (MRESULT)TRUE;
  265.          break;
  266.  
  267.       case WMU_CLEAR:
  268.          processClearMessage(hWnd);
  269.          break;
  270.  
  271.       case WMU_PAINTLINES:
  272.          processPaintLinesMessage(hWnd, LONGFROMMP(mp1), LONGFROMMP(mp2));
  273.          break;
  274.  
  275.       case WMU_PRESCROLL:
  276.          processPreScrollMessage(hWnd, mp1, mp2);
  277.          break;
  278.  
  279.       default:
  280.          fHandled = FALSE;
  281.          break;
  282.    }
  283.    if(!fHandled)
  284.    {
  285.       mReturn = WinDefWindowProc(hWnd, msg, mp1, mp2);
  286.    }
  287.    return mReturn;
  288. }
  289.  
  290.  
  291. static MRESULT _Optlink processCreateMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  292. {
  293.    APIRET rc = NO_ERROR;
  294.    BOOL fAbort = TRUE;
  295.    PWINDOWDATA pWindowData = NULL;
  296.    PTERMCDATA ctldata = (PTERMCDATA)mp1;
  297.    PCREATESTRUCT pCREATE = (PCREATESTRUCT)mp2;
  298.  
  299.    pWindowData = (PWINDOWDATA)malloc(sizeof(WINDOWDATA));
  300.    if(pWindowData)
  301.    {
  302.       char font[100] = "10.System VIO";
  303.       HPS hPS = NULLHANDLE;
  304.       ULONG ulAction = 0;
  305.       ULONG ulLength = 0;
  306.  
  307.       memset(pWindowData, 0, sizeof(WINDOWDATA));
  308.  
  309.       WinSetWindowPtr(hWnd, QWP_WINDOWDATA, pWindowData);
  310.  
  311.       pWindowData->ti.hPipe = ctldata->hDebugPipe;
  312.  
  313.       pWindowData->ti.fLogFile = ctldata->fLogFile;
  314.       pWindowData->ti.hfLogFile = ctldata->hfLogFile;
  315.  
  316.  
  317.       /*
  318.        * Setup window data
  319.        */
  320.       pWindowData->ti.rows = ctldata->rows;
  321.       pWindowData->ti.columns = ctldata->columns;
  322.       pWindowData->ti.hWnd = hWnd;
  323.  
  324.       ulLength = PrfQueryProfileString(HINI_USERPROFILE, "PMDebugTerminal", "Font", "10.System VIO", font, sizeof(font));
  325.  
  326.       WinSetPresParam(hWnd, PP_FONTNAMESIZE, ulLength, font);
  327.  
  328.       hPS = WinGetPS(hWnd);
  329.       GpiQueryFontMetrics(hPS, sizeof(pWindowData->fm), &pWindowData->fm);
  330.       WinReleasePS(hPS);
  331.  
  332.       pWindowData->sizlChar.cx = pWindowData->fm.lAveCharWidth;
  333.       pWindowData->sizlChar.cy = pWindowData->fm.lMaxBaselineExt;
  334.       pWindowData->yDesc = pWindowData->fm.lMaxDescender;
  335.  
  336.       vScrollParms(hWnd, 0, pWindowData->ti.rows);
  337.       hScrollParms(hWnd, 0, pWindowData->ti.columns);
  338.  
  339.       subclassFrameProc(hWnd);
  340.  
  341.       init_terminfo(&pWindowData->ti);
  342.  
  343.       _beginthread(rcvthread, NULL, 16384, &pWindowData->ti);
  344.  
  345.       fAbort = FALSE;
  346.    }
  347.  
  348.    return (MRESULT)fAbort;
  349. }
  350.  
  351.  
  352. static void _Optlink processAdjustWindowPosMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  353. {
  354.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  355.    PSWP swp = (PSWP)mp1;
  356.  
  357.    if(swp->fl & SWP_SIZE)
  358.    {
  359.       swp->cx += (swp->cx % pWindowData->sizlChar.cx);
  360.       swp->cy += (swp->cy % pWindowData->sizlChar.cy);
  361.    }
  362. }
  363.  
  364.  
  365. static void _Optlink processSizeMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  366. {
  367.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  368.    SHORT scxold = SHORT1FROMMP(mp1);
  369.    SHORT scyold = SHORT2FROMMP(mp1);
  370.    SHORT scxnew = SHORT1FROMMP(mp2);
  371.    SHORT scynew = SHORT2FROMMP(mp2);
  372.  
  373.    if(scxold != scxnew)
  374.    {
  375.       pWindowData->sizlClient.cx = scxnew;
  376.       pWindowData->sizlChars.cx = pWindowData->sizlClient.cx / pWindowData->sizlChar.cx;
  377.       hScrollParms(hWnd, pWindowData->scrollPos.h, pWindowData->ti.columns);
  378.    }
  379.  
  380.    if(scyold != scynew)
  381.    {
  382.       pWindowData->sizlClient.cy = scynew;
  383.       pWindowData->sizlChars.cy = pWindowData->sizlClient.cy / pWindowData->sizlChar.cy;
  384.       vScrollParms(hWnd, pWindowData->scrollPos.v, pWindowData->ti.rows);
  385.    }
  386. }
  387.  
  388. static void _Optlink processPaintMessage(HWND hWnd)
  389. {
  390.    RECTL rect = { 0L, 0L, 0L, 0L };
  391.    HPS hPS = WinBeginPaint(hWnd, NULLHANDLE, &rect);
  392.  
  393.    if(hPS)
  394.    {
  395.       POINTL pt = { 0, 0 };
  396.       LONG paintFirst = 0, paintLast = 0;
  397.       LONG ofs;
  398.       PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  399.       ULONG i = 0;
  400.  
  401.       GpiErase(hPS);
  402.  
  403.       paintFirst = max(0, pWindowData->scrollPos.v + (pWindowData->sizlClient.cy - (SHORT)rect.yTop) / pWindowData->sizlChar.cy);
  404.       paintLast = min(pWindowData->ti.rows, pWindowData->scrollPos.v + (pWindowData->sizlClient.cy - (SHORT)rect.yBottom) / pWindowData->sizlChar.cy + 1);
  405.  
  406.       ofs = pWindowData->scrollPos.h;
  407.  
  408.       for(i = paintFirst; i < paintLast; i++)
  409.       {
  410.          char *str = pWindowData->ti.lines[i].buf;
  411.          LONG len = pWindowData->ti.lines[i].cbChars;
  412.  
  413.          pt.y = pWindowData->sizlClient.cy - pWindowData->sizlChar.cy * (i+1 - pWindowData->scrollPos.v) + pWindowData->yDesc;
  414.          if(len > ofs)
  415.          {
  416.             LONG cols = len - ofs;
  417.             if(cols)
  418.             {
  419.                GpiSetColor(hPS, pWindowData->ti.lines[i].lTextColor);
  420.                GpiCharStringAt(hPS, &pt, (ULONG)cols, str + ofs);
  421.             }
  422.          }
  423.       }
  424.  
  425.       WinEndPaint(hPS);
  426.    }
  427. }
  428.  
  429.  
  430. static void _Optlink processHScrollMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  431. {
  432.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  433.    USHORT cmd = SHORT2FROMMP(mp2);
  434.    BOOL fSetpos = TRUE;
  435.    LONG lScroll = 0;
  436.  
  437.    switch(cmd)
  438.    {
  439.       case SB_LINELEFT:
  440.          lScroll = -1;
  441.          break;
  442.  
  443.       case SB_LINERIGHT:
  444.          lScroll = 1;
  445.          break;
  446.  
  447.       case SB_PAGELEFT:
  448.          lScroll = -max(8, pWindowData->scrollMax.h / 10);
  449.          break;
  450.  
  451.       case SB_PAGERIGHT:
  452.          lScroll = max(8, pWindowData->scrollMax.h / 10);
  453.          break;
  454.  
  455.       case SB_SLIDERTRACK:
  456.          lScroll = SHORT1FROMMP(mp2) - pWindowData->scrollPos.h;
  457.          fSetpos = FALSE;
  458.          break;
  459.  
  460.       case SB_SLIDERPOSITION:
  461.          lScroll = SHORT1FROMMP(mp2) - pWindowData->scrollPos.h;
  462.          break;
  463.  
  464.       case SB_ENDSCROLL:
  465.          lScroll = 0;
  466.          break;
  467.  
  468.       default:
  469.          lScroll = 0;
  470.          fSetpos = FALSE;
  471.          break;
  472.    }
  473.    if(0 != (lScroll = max(-pWindowData->scrollPos.h, min(lScroll, pWindowData->scrollMax.h - pWindowData->scrollPos.h))))
  474.    {
  475.       pWindowData->scrollPos.h += lScroll;
  476.       WinScrollWindow(hWnd, -pWindowData->sizlChar.cx * lScroll, 0, NULL, NULL, NULLHANDLE, NULL, SW_INVALIDATERGN);
  477.    }
  478.  
  479.    WinUpdateWindow(hWnd);
  480.  
  481.    if(fSetpos)
  482.    {
  483.       HWND hwndBar = WinWindowFromID(WinQueryWindow(hWnd, QW_PARENT), SHORT1FROMMP(mp2));
  484.  
  485.       WinSendMsg(hwndBar, SBM_SETPOS, MPFROMSHORT(pWindowData->scrollPos.h), 0L);
  486.    }
  487. }
  488.  
  489.  
  490. static void _Optlink processVScrollMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  491. {
  492.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  493.    USHORT cmd = SHORT2FROMMP(mp2);
  494.    BOOL fSetpos = TRUE;
  495.    LONG lScroll = 0;
  496.  
  497.    switch(cmd)
  498.    {
  499.       case SB_LINEUP:
  500.          lScroll = -1;
  501.          break;
  502.  
  503.       case SB_LINEDOWN:
  504.          lScroll = 1;
  505.          break;
  506.  
  507.       case SB_PAGEUP:
  508.          lScroll = -pWindowData->sizlChars.cy;
  509.          break;
  510.  
  511.       case SB_PAGEDOWN:
  512.          lScroll = pWindowData->sizlChars.cy;
  513.          break;
  514.  
  515.       case SB_SLIDERTRACK:
  516.          lScroll = SHORT1FROMMP(mp2) - pWindowData->scrollPos.v;
  517.          fSetpos = FALSE;
  518.          break;
  519.  
  520.       case SB_ENDSCROLL:
  521.          lScroll = 0;
  522.          break;
  523.  
  524.       case SB_SLIDERPOSITION:
  525.          lScroll = SHORT1FROMMP(mp2) - pWindowData->scrollPos.v;
  526.          break;
  527.  
  528.       default:
  529.          lScroll = 0;
  530.          fSetpos = FALSE;
  531.          break;
  532.    }
  533.    if(0 != (lScroll = max(-pWindowData->scrollPos.v, min(lScroll, pWindowData->scrollMax.v - pWindowData->scrollPos.v))))
  534.    {
  535.       pWindowData->scrollPos.v += lScroll;
  536.       WinScrollWindow(hWnd, 0, pWindowData->sizlChar.cy * lScroll, NULL, NULL, NULLHANDLE, NULL, SW_INVALIDATERGN);
  537.       WinUpdateWindow(hWnd);
  538.    }
  539.    if(fSetpos)
  540.    {
  541.       HWND hwndBar = WinWindowFromID(WinQueryWindow(hWnd, QW_PARENT), FID_VERTSCROLL);
  542.  
  543.       WinSendMsg(hwndBar, SBM_SETPOS, MPFROMSHORT(pWindowData->scrollPos.v), MPVOID);
  544.    }
  545. }
  546.  
  547.  
  548.  
  549. static void _Optlink processPresParamsChangedMessage(HWND hWnd, MPARAM mp1)
  550. {
  551.    ULONG idAttrType = LONGFROMMP(mp1);
  552.  
  553.    if(idAttrType == PP_FONTNAMESIZE)
  554.    {
  555.       PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  556.       char tmp[100];
  557.  
  558.       HPS hPS = WinGetPS(hWnd);
  559.  
  560.       GpiQueryFontMetrics(hPS, sizeof(pWindowData->fm), &pWindowData->fm);
  561.  
  562.       if(WinQueryPresParam(hWnd, PP_FONTNAMESIZE, 0UL, NULL, sizeof(tmp), tmp, QPF_NOINHERIT))
  563.       {
  564.          PrfWriteProfileString(HINI_USERPROFILE, "PMDebugTerminal", "Font", tmp);
  565.       }
  566.  
  567.  
  568.       WinReleasePS(hPS);
  569.  
  570.       pWindowData->sizlChar.cx = pWindowData->fm.lAveCharWidth;
  571.       pWindowData->sizlChar.cy = pWindowData->fm.lMaxBaselineExt;
  572.       pWindowData->yDesc = pWindowData->fm.lMaxDescender;
  573.  
  574.       pWindowData->sizlChars.cx = pWindowData->sizlClient.cx / pWindowData->sizlChar.cx;
  575.       pWindowData->sizlChars.cy = pWindowData->sizlClient.cy / pWindowData->sizlChar.cy;
  576.  
  577.       vScrollParms(hWnd, pWindowData->scrollPos.v, pWindowData->ti.rows);
  578.       hScrollParms(hWnd, pWindowData->scrollPos.h, pWindowData->ti.columns);
  579.  
  580.       WinPostMsg(WinQueryWindow(hWnd, QW_PARENT), WMU_RECALCMAXSIZE, MPVOID, MPVOID);
  581.  
  582.       WinInvalidateRect(WinQueryWindow(hWnd, QW_PARENT), NULL, TRUE);
  583.    }
  584. }
  585.  
  586.  
  587.  
  588. static void _Optlink processDestroyMessage(HWND hWnd)
  589. {
  590.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  591.  
  592.    if(pWindowData)
  593.    {
  594.       free(pWindowData);
  595.    }
  596. }
  597.  
  598.  
  599. static void _Optlink processClearMessage(HWND hWnd)
  600. {
  601.    ULONG i = 0;
  602.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  603.  
  604.    for(i = 0; i < pWindowData->ti.rows; i++)
  605.    {
  606.       pWindowData->ti.lines[i].cbChars = 0;
  607.       pWindowData->ti.lines[i].fEOL = 0;
  608.       pWindowData->ti.lines[i].buf[0] = '\0';
  609.    }
  610.    pWindowData->ti.cursor.x = pWindowData->ti.cursor.y = 0;
  611.  
  612.    WinInvalidateRect(hWnd, NULL, FALSE);
  613. }
  614.  
  615.  
  616.  
  617.  
  618. static void _Optlink processPaintLinesMessage(HWND hWnd, LONG startline, LONG endline)
  619. {
  620.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  621.    POINTL pt = { 0, 0 };
  622.    LONG ofs = 0;
  623.    HPS hPS = WinGetPS(hWnd);
  624.  
  625.    if(startline < 0)
  626.    {
  627.       startline = 0;
  628.    }
  629.    Adjust(hWnd, startline, endline);
  630.  
  631.    if(hPS)
  632.    {
  633.       POINTL pt = { 0, 0 };
  634.       PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  635.       ULONG i = 0;
  636.  
  637.       ofs = pWindowData->scrollPos.h;
  638.  
  639.       for(i = startline; i <= endline; i++)
  640.       {
  641.          char *str = pWindowData->ti.lines[i].buf;
  642.          LONG len = pWindowData->ti.lines[i].cbChars;
  643.  
  644.          pt.y = pWindowData->sizlClient.cy - pWindowData->sizlChar.cy * (i+1 - pWindowData->scrollPos.v) + pWindowData->yDesc;
  645.          if(len > ofs)
  646.          {
  647.             LONG cols = len - ofs;
  648.             if(cols)
  649.             {
  650.                GpiSetColor(hPS, pWindowData->ti.lines[i].lTextColor);
  651.                GpiCharStringAt(hPS, &pt, (ULONG)cols, str + ofs);
  652.             }
  653.          }
  654.       }
  655.       WinReleasePS(hPS);
  656.    }
  657. }
  658.  
  659. static void _Optlink processPreScrollMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  660. {
  661.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  662.  
  663.    WinScrollWindow(hWnd, 0, pWindowData->sizlChar.cy * LONGFROMMP(mp1), NULL, NULL, NULLHANDLE, NULL, SW_INVALIDATERGN);
  664. }
  665.  
  666.  
  667.  
  668.  
  669. static BOOL _Optlink init_terminfo(PTERMINFO ti)
  670. {
  671.    ULONG i = 0;
  672.    PTERMLINE termlines = NULL;
  673.    BOOL fSuccess = FALSE;
  674.  
  675.    termlines = (PTERMLINE)calloc(ti->rows, sizeof(TERMLINE));
  676.    if(termlines)
  677.    {
  678.       ti->lines = termlines;
  679.  
  680.       for(i = 0; i < ti->rows; i++)
  681.       {
  682.  
  683.          ti->lines[i].cbChars = 0UL;
  684.          ti->lines[i].fEOL = FALSE;
  685.          ti->lines[i].lTextColor = CLR_BLACK;
  686.          ti->lines[i].buf = malloc(ti->columns);
  687.  
  688.          if(ti->lines[i].buf == NULL)
  689.          {
  690.             break;
  691.          }
  692.       }
  693.  
  694.       if(i < ti->rows)
  695.       {
  696.          term_terminfo(ti);
  697.       }
  698.       else
  699.       {
  700.          fSuccess = TRUE;
  701.       }
  702.    }
  703.  
  704.    return fSuccess;
  705. }
  706.  
  707. static BOOL _Optlink term_terminfo(PTERMINFO ti)
  708. {
  709.    ULONG i = 0;
  710.  
  711.    for(i = 0; i < ti->rows; i++)
  712.    {
  713.       if(ti->lines[i].buf)
  714.       {
  715.          free(ti->lines[i].buf);
  716.       }
  717.    }
  718.    free(ti->lines);
  719.  
  720.    return TRUE;
  721. }
  722.  
  723. void shift1(PTERMINFO ti)
  724. {
  725.    TERMLINE tl;
  726.    memcpy(&tl, ti->lines, sizeof(TERMLINE));
  727.    memmove(ti->lines, &ti->lines[1], sizeof(TERMLINE)*(ti->rows-1));
  728.    memcpy(&ti->lines[ti->rows-1], &tl, sizeof(tl));
  729.    ti->lines[ti->rows-1].cbChars = 0;
  730.    ti->lines[ti->rows-1].fEOL = FALSE;
  731. }
  732.  
  733. static void _Optlink term_print(HWND hWnd, char *pchBuf, ULONG cbBuf)
  734. {
  735.    ULONG i = 0;
  736.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  737.    PTERMINFO ti = &pWindowData->ti;
  738.    LONG pre_scroll = 0;
  739.    LONG startline = ti->cursor.y;
  740.  
  741.    for(i = 0; i < cbBuf; i++)
  742.    {
  743.       switch(pchBuf[i])
  744.       {
  745.          case '\r':
  746.             ti->cursor.x = 0;
  747.             break;
  748.  
  749.          case '\f':
  750.             while(!WinPostMsg(hWnd, WMU_CLEAR, MPVOID, MPVOID))
  751.             {
  752.                DosSleep(0);
  753.             }
  754.             break;
  755.  
  756.          case '\b':
  757.             #ifdef DEBUG
  758.             puts("Backspace!");
  759.             #endif
  760.             if(ti->lines[ti->cursor.y].cbChars)
  761.             {
  762.                ti->lines[ti->cursor.y].cbChars--;
  763.                ti->lines[ti->cursor.y].buf[--ti->cursor.x] = ' ';
  764.             }
  765.             break;
  766.  
  767.          case '\n':
  768.             ti->lines[ti->cursor.y].fEOL = TRUE;
  769.             ti->cursor.y++;
  770.             if(ti->cursor.y == ti->rows)
  771.             {
  772.                shift1(ti);
  773.                ti->cursor.y--;
  774.                pre_scroll++;
  775.             }
  776.             ti->lines[ti->cursor.y].fEOL = FALSE;
  777.             ti->lines[ti->cursor.y].cbChars = 0;
  778.             ti->lines[ti->cursor.y].lTextColor = CLR_BLACK;
  779.             break;
  780.  
  781.          case ' ':
  782.             if(ti->cursor.x == 1)
  783.             {
  784.                switch(ti->lines[ti->cursor.y].buf[0])
  785.                {
  786.                   case 'i':              /* 'Infromational' */
  787.                      ti->lines[ti->cursor.y].lTextColor = CLR_BLACK;
  788.                      break;
  789.  
  790.                   case 'w':              /* 'Warning' */
  791.                      ti->lines[ti->cursor.y].lTextColor = CLR_BLUE;
  792.                      break;
  793.  
  794.                   case 'e':              /* 'Error' */
  795.                      ti->lines[ti->cursor.y].lTextColor = CLR_RED;
  796.                      break;
  797.  
  798.                   default:               /* Anything else */
  799.                      ti->lines[ti->cursor.y].lTextColor = CLR_BLACK;
  800.                      break;
  801.                }
  802.             }
  803.          default:
  804.             ti->lines[ti->cursor.y].fEOL = FALSE;
  805.             ti->lines[ti->cursor.y].buf[ti->cursor.x++] = pchBuf[i];
  806.             if(ti->cursor.x >= ti->lines[ti->cursor.y].cbChars)
  807.             {
  808.                ti->lines[ti->cursor.y].cbChars++;
  809.                if(ti->lines[ti->cursor.y].cbChars < ti->cursor.x)
  810.                {
  811.                   memset(ti->lines[ti->cursor.y].buf + ti->cursor.x, ' ', ti->cursor.x-ti->lines[ti->cursor.y].cbChars);
  812.                   ti->lines[ti->cursor.y].cbChars = ti->cursor.x;
  813.                }
  814.             }
  815.             if(ti->cursor.x == ti->columns)
  816.             {
  817.                ti->cursor.x = 0;
  818.                ti->cursor.y++;
  819.                if(ti->cursor.y == ti->rows)
  820.                {
  821.                   shift1(ti);
  822.                   ti->cursor.y--;
  823.                   pre_scroll++;
  824.                }
  825.                ti->lines[ti->cursor.y].fEOL = FALSE;
  826.                ti->lines[ti->cursor.y].cbChars = 0;
  827.             }
  828.             break;
  829.       }
  830.    }
  831.    if(pre_scroll)
  832.    {
  833.       while(!WinPostMsg(hWnd, WMU_PRESCROLL, (MPARAM)pre_scroll, MPVOID))
  834.       {
  835.          DosSleep(0);
  836.       }
  837.    }
  838.    while(!WinPostMsg(hWnd, WMU_PAINTLINES, (MPARAM)(startline-pre_scroll), (MPARAM)ti->cursor.y))
  839.    {
  840.       DosSleep(0);
  841.    }
  842. }
  843.  
  844.  
  845. static BOOL _Optlink vScrollParms(HWND hWnd, ULONG row, ULONG rows)
  846. {
  847.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  848.    HWND hwndFrame = WinQueryWindow(hWnd, QW_PARENT);
  849.    HWND hwndBar = WinWindowFromID(hwndFrame, FID_VERTSCROLL);
  850.  
  851.    if(row >= rows)
  852.    {
  853.       return FALSE;
  854.    }
  855.  
  856.    pWindowData->scrollMax.v = max(0, pWindowData->ti.rows - pWindowData->sizlChars.cy);
  857.    pWindowData->scrollPos.v = min(row, pWindowData->scrollMax.v);
  858.  
  859.    WinSendMsg(hwndBar, SBM_SETSCROLLBAR, MPFROMSHORT(pWindowData->scrollPos.v), MPFROM2SHORT(0, pWindowData->scrollMax.v));
  860.    WinSendMsg(hwndBar, SBM_SETTHUMBSIZE, MPFROM2SHORT(pWindowData->sizlChars.cy, pWindowData->ti.rows), 0);
  861.  
  862.    WinEnableWindow(hwndBar, pWindowData->scrollMax.v ? TRUE : FALSE);
  863.  
  864.    return TRUE;
  865. }
  866.  
  867. static BOOL _Optlink hScrollParms(HWND hWnd, ULONG col, ULONG cols)
  868. {
  869.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  870.    HWND hwndFrame = WinQueryWindow(hWnd, QW_PARENT);
  871.    HWND hwndBar = WinWindowFromID(hwndFrame, FID_HORZSCROLL);
  872.  
  873.    if(col >= cols)
  874.    {
  875.       return FALSE;
  876.    }
  877.  
  878.    pWindowData->scrollMax.h = max(0, pWindowData->ti.columns - pWindowData->sizlChars.cx);
  879.    pWindowData->scrollPos.h = min(col, pWindowData->scrollMax.h);
  880.  
  881.    WinSendMsg(hwndBar, SBM_SETSCROLLBAR, MPFROMSHORT(pWindowData->scrollPos.h), MPFROM2SHORT(0, pWindowData->scrollMax.h));
  882.    WinSendMsg(hwndBar, SBM_SETTHUMBSIZE, MPFROM2SHORT(pWindowData->sizlChars.cx, pWindowData->ti.columns), 0);
  883.  
  884.    WinEnableWindow(hwndBar, pWindowData->scrollMax.h ? TRUE : FALSE);
  885. }
  886.  
  887.  
  888.  
  889. static void Adjust(HWND hWnd, LONG line1, LONG line2)
  890. {
  891.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hWnd, QWP_WINDOWDATA);
  892.    LONG y = 0;
  893.  
  894.    y = pWindowData->sizlClient.cy - pWindowData->sizlChar.cy * (line2 + 1 - pWindowData->scrollPos.v) + pWindowData->yDesc;
  895.    if(y < 0)
  896.    {
  897.       LONG n = y/pWindowData->sizlChar.cy - 1;
  898.       WinSendMsg(hWnd, WM_VSCROLL, (MPARAM)FID_VERTSCROLL, MPFROM2SHORT(pWindowData->scrollPos.v - n, SB_SLIDERPOSITION));
  899.    }
  900.    else
  901.    {
  902.       y = pWindowData->sizlClient.cy - pWindowData->sizlChar.cy * (line1 + 1 - pWindowData->scrollPos.v) + pWindowData->yDesc;
  903.       if(y > pWindowData->sizlClient.cy)
  904.       {
  905.          LONG n = 1 + (y - pWindowData->sizlClient.cy) / pWindowData->sizlChar.cy;
  906.          WinSendMsg(hWnd, WM_VSCROLL, (MPARAM)FID_VERTSCROLL, MPFROM2SHORT(pWindowData->scrollPos.v - n, SB_SLIDERPOSITION));
  907.       }
  908.    }
  909. }
  910.  
  911.  
  912.  
  913.  
  914.  
  915.  
  916.  
  917.  
  918.  
  919. static BOOL _Optlink subclassFrameProc(HWND hwndClient)
  920. {
  921.    HWND hwndFrame = WinQueryWindow(hwndClient, QW_PARENT);
  922.    PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(hwndClient, QWP_WINDOWDATA);
  923.    PFRAMEWINDOWUSERDATA fwud = NULL;
  924.    RECTL rect = { 0, 0, 0, 0 };
  925.    BOOL fSuccess = FALSE;
  926.  
  927.    /*
  928.     * Maximum size of client
  929.     */
  930.    rect.xLeft = 0;
  931.    rect.xRight = pWindowData->ti.columns*pWindowData->sizlChar.cx;
  932.    rect.yBottom = 0;
  933.    rect.yTop = pWindowData->ti.rows*pWindowData->sizlChar.cy;
  934.  
  935.    /*
  936.     * Calculate the size of the frame when the client is at its maximum size
  937.     */
  938.    WinCalcFrameRect(hwndFrame, &rect, FALSE);
  939.  
  940.    fwud = (PFRAMEWINDOWUSERDATA)malloc(sizeof(FRAMEWINDOWUSERDATA));
  941.    if(fwud)
  942.    {
  943.       WinSetWindowULong(hwndFrame, QWL_USER, (ULONG)fwud);
  944.       fwud->ulMaxWidth = rect.xRight-rect.xLeft;
  945.       fwud->ulMaxHeight = rect.yTop-rect.yBottom;
  946.       fwud->hwndClient = hwndClient;
  947.       fwud->pfnOldProc = WinSubclassWindow(hwndFrame, FrameSubProc);
  948.       if(fwud->pfnOldProc)
  949.       {
  950.          fSuccess = TRUE;
  951.       }
  952.       else
  953.       {
  954.          free(fwud);
  955.          WinSetWindowULong(hwndFrame, QWL_USER, (ULONG)NULL);
  956.       }
  957.    }
  958.    else
  959.    {
  960.       /* Failed to allocate buffer for windowdata */
  961.       fSuccess = FALSE;
  962.    }
  963.  
  964.    return fSuccess;
  965. }
  966.  
  967. static MRESULT EXPENTRY FrameSubProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  968. {
  969.    MRESULT mReturn = 0;
  970.    BOOL fHandled = TRUE;
  971.    PFRAMEWINDOWUSERDATA pParams = (PFRAMEWINDOWUSERDATA)(ULONG)WinQueryWindowULong(hWnd, QWL_USER);
  972.  
  973.    switch(msg)
  974.    {
  975. /*
  976.       case WM_ADJUSTWINDOWPOS:
  977.          processFrameAdjustWindowPosMessage(hWnd, mp1, mp2);
  978.          break;
  979. */
  980.       case WM_QUERYTRACKINFO:
  981.          mReturn = processFrameQueryTrackInfo(hWnd, mp1, mp2);
  982.          break;
  983.  
  984.       case WM_DESTROY:
  985.          free(pParams);
  986.          break;
  987.  
  988.       case WMU_RECALCMAXSIZE:
  989.          processFrameRecalcMaxSize(hWnd);
  990.          break;
  991.  
  992.       default:
  993.          fHandled = FALSE;
  994.          break;
  995.    }
  996.    if(!fHandled)
  997.       mReturn = (*pParams->pfnOldProc)(hWnd, msg, mp1, mp2);
  998.  
  999.    return mReturn;
  1000. }
  1001.  
  1002. static void _Optlink processFrameAdjustWindowPosMessage(HWND hWnd, MPARAM mp1, MPARAM mp2)
  1003. {
  1004.    PFRAMEWINDOWUSERDATA pFrameData = (PFRAMEWINDOWUSERDATA)(ULONG)WinQueryWindowULong(hWnd, QWL_USER);
  1005.    PSWP swp = (PSWP)mp1;
  1006.  
  1007. /*
  1008.    if(swp->cx > pFrameData->ulMaxWidth)
  1009.    {
  1010.       swp->cx = pFrameData->ulMaxWidth;
  1011.    }
  1012.  
  1013.    if(swp->cy > pFrameData->ulMaxHeight)
  1014.    {
  1015.       swp->cy = pFrameData->ulMaxHeight;
  1016.    }
  1017. */
  1018. }
  1019.  
  1020. static MRESULT _Optlink processFrameQueryTrackInfo(HWND hWnd, MPARAM mp1, MPARAM mp2)
  1021. {
  1022.    MRESULT mReturn = 0;
  1023.    PTRACKINFO pti = (PTRACKINFO)mp2;
  1024.    PFRAMEWINDOWUSERDATA pParams = NULL;
  1025.  
  1026.    pParams = (PFRAMEWINDOWUSERDATA)(ULONG)WinQueryWindowULong(hWnd, QWL_USER);
  1027.  
  1028.    /*
  1029.     * Let PM initialize the structure
  1030.     */
  1031.    mReturn = (*pParams->pfnOldProc)(hWnd, WM_QUERYTRACKINFO, mp1, mp2);
  1032.  
  1033.    /*
  1034.     * Store the maximum size in TRACKINFO structure
  1035.     */
  1036.    pti->ptlMaxTrackSize.x = pParams->ulMaxWidth;
  1037.    pti->ptlMaxTrackSize.y = pParams->ulMaxHeight;
  1038.  
  1039.    return mReturn;
  1040. }
  1041.  
  1042.  
  1043. static void _Optlink processFrameRecalcMaxSize(HWND hwndFrame)
  1044. {
  1045.    PFRAMEWINDOWUSERDATA pFrameData = (PFRAMEWINDOWUSERDATA)WinQueryWindowULong(hwndFrame, QWL_USER);
  1046.    PWINDOWDATA pClientData = (PWINDOWDATA)WinQueryWindowPtr(pFrameData->hwndClient, QWP_WINDOWDATA);
  1047.    RECTL rect = { 0, 0, 0, 0 };
  1048.    BOOL fSuccess = FALSE;
  1049.  
  1050.    /*
  1051.     * Maximum size of client
  1052.     */
  1053.    rect.xLeft = 0;
  1054.    rect.xRight = pClientData->ti.columns*pClientData->sizlChar.cx;
  1055.    rect.yBottom = 0;
  1056.    rect.yTop = pClientData->ti.rows*pClientData->sizlChar.cy;
  1057.  
  1058.    /*
  1059.     * Calculate the size of the frame when the client is at its maximum size
  1060.     */
  1061.    fSuccess = WinCalcFrameRect(hwndFrame, &rect, FALSE);
  1062.  
  1063.    /*
  1064.     * Store the maximum size
  1065.     */
  1066.    if(fSuccess)
  1067.    {
  1068.       SWP swp = { 0 };
  1069.  
  1070.       pFrameData->ulMaxWidth = rect.xRight-rect.xLeft;
  1071.       pFrameData->ulMaxHeight = rect.yTop-rect.yBottom;
  1072.  
  1073.       WinQueryWindowPos(hwndFrame, &swp);
  1074.  
  1075.       WinSetWindowPos(hwndFrame, swp.hwndInsertBehind, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE);
  1076.    }
  1077. }
  1078.  
  1079.  
  1080.  
  1081.  
  1082.  
  1083.  
  1084. static void _Optlink rcvthread(void *param)
  1085. {
  1086.    PTERMINFO ti = (PTERMINFO)param;
  1087.    char buf[512] = "";
  1088.    ULONG cbRead = 0;
  1089.    APIRET rc = NO_ERROR;
  1090.  
  1091.    #ifdef DEBUG
  1092.    puts("rcvthread running..");
  1093.    #endif
  1094.  
  1095.    while(1)
  1096.    {
  1097.       rc = DosRead(ti->hPipe, buf, sizeof(buf), &cbRead);
  1098.       if(rc)
  1099.       {
  1100.          break;
  1101.       }
  1102.       if(cbRead)
  1103.       {
  1104.          term_print(ti->hWnd, buf, cbRead);
  1105.          if(ti->fLogFile)
  1106.          {
  1107.             ULONG cbWritten = 0;
  1108.             DosWrite(ti->hfLogFile, buf, cbRead, &cbWritten);
  1109.          }
  1110.       }
  1111.       else
  1112.       {
  1113.          PWINDOWDATA pWindowData = (PWINDOWDATA)WinQueryWindowPtr(ti->hWnd, QWP_WINDOWDATA);
  1114.  
  1115.          /* Can't remember what I was planning to do here. Probably something paramount
  1116.             that would end all suffering throughout the world. Too bad I can't remember what. */
  1117.  
  1118.          DosSleep(0);
  1119.       }
  1120.    }
  1121.  
  1122.    #ifdef DEBUG
  1123.    puts("rcvthread terminated!");
  1124.    #endif
  1125.  
  1126.    _endthread();
  1127. }
  1128.  
  1129.  
  1130.  
  1131. static MRESULT EXPENTRY AboutDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1132. {
  1133.    MRESULT mReturn = 0;
  1134.    BOOL fHandled = TRUE;
  1135.  
  1136.  
  1137.    switch(msg)
  1138.    {
  1139.       case WM_COMMAND:
  1140.          switch(SHORT1FROMMP(mp1))
  1141.          {
  1142.             case DID_OK:
  1143.                WinDismissDlg(hWnd, SHORT1FROMMP(mp1));
  1144.                break;
  1145.  
  1146.             default:
  1147.                fHandled = FALSE;
  1148.                break;
  1149.          }
  1150.          break;
  1151.  
  1152.       default:
  1153.          fHandled = FALSE;
  1154.    }
  1155.    if(!fHandled)
  1156.    {
  1157.       mReturn = WinDefDlgProc(hWnd, msg, mp1, mp2);
  1158.    }
  1159.    return mReturn;
  1160. }
  1161.