home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tolkit45.zip / os2tk45 / samples / os2 / sort / sort.c next >
C/C++ Source or Header  |  1999-05-11  |  57KB  |  1,542 lines

  1. /*=========================================================================*\
  2.  *                                                                         *
  3.  * SORT.C - Multi-threaded PM sample.                                      *
  4.  *                                                                         *
  5.  *                                                                         *
  6.  *      (C) Copyright IBM Corporation 1992.                                *
  7.  *                                                                         *
  8.  *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is        *
  9.  *      sample code created by IBM Corporation. This sample code is not    *
  10.  *      part of any standard or IBM product and is provided to you solely  *
  11.  *      for  the purpose of assisting you in the development of your       *
  12.  *      applications.  The code is provided "AS IS", without               *
  13.  *      warranty of any kind.  IBM shall not be liable for any damages     *
  14.  *      arising out of your use of the sample code, even if they have      *
  15.  *      been advised of the possibility of   such damages.                 *
  16.  *-------------------------------------------------------------------------*
  17.  *
  18.  *   This program demonstrates the use of many threads by doing
  19.  *   LISTCNT simultaneous sorts.  Each sorting algorithm runs
  20.  *   from a separate thread, the routine which updates the display
  21.  *   is run from another thread, and the main thread is used to
  22.  *   handle the main window's messages.  The display thread is
  23.  *   started when the program begins and is not terminated (allows
  24.  *   default cleanup to terminate thread) as the display routine
  25.  *   is used throughout the program's life.
  26.  *   This code was written to allow easy modification.  To change
  27.  *   the number of simultaneous sorts, change the LISTCNT #define
  28.  *   and modify the global arrays which control the screen
  29.  *   drawing color, the sort each thread is to use, and the sort name.
  30.  *   Note:  This program was not intended to infer the relative
  31.  *          speeds of the various sorting algorithms.
  32.  *
  33.  *---------------------------------------------------------------
  34.  *
  35.  *   Procedures in this file:
  36.  *     main()             Sets up the PM environment and calls
  37.  *                        the main dialog procedure ClientWndProc
  38.  *     ClientWndProc()    Handles the main window messages
  39.  *     CalcThread()       Generic stub that sets up, executes, and
  40.  *                        terminates each sort in an aux. thread
  41.  *     DispThread()       Updates the display during the sorts
  42.  *     BubbleSort()       Implements a bubble sort
  43.  *     InsertionSort()    Implements an insertion sort
  44.  *     BatcherSort()      Stub that calls recursive Batcher sort
  45.  *     BatcherSortR()     Implements a Batcher sort
  46.  *     QuickSort()        Stub that calls recursive Quick sort
  47.  *     QuickSortR()       Implements a Quick sort
  48.  *     EnableMenuItem()   Activates/deactivates a menu choice
  49.  *     EntryFldDlgProc()  Handles the set number of disks dialog box
  50.  *     RandomizeData()    Randomizes the data arrays for the sorts
  51.  *     FixSysMenu()       Remove Restore, Size, Min, & Max from system menu
  52.  *
  53. \*==============================================================*/
  54. /*--------------------------------------------------------------*\
  55.  *  Include files, macros, defined constants, and externs       *
  56. \*--------------------------------------------------------------*/
  57. #define INCL_WIN
  58. #define INCL_WINHEAP
  59. #define INCL_HELP
  60. #define INCL_WINDIALOGS
  61. #define INCL_GPIPRIMITIVES
  62. #define INCL_GPIBITMAPS
  63. #define INCL_DOSPROCESS
  64. #define INCL_DOSSEMAPHORES
  65.  
  66. #include <os2.h>
  67. #include <stdio.h>
  68. #include <string.h>
  69. #include <process.h>
  70. #include <stdlib.h>
  71. #include "sort.h"
  72.  
  73. #ifdef RAND_MAX
  74.    #undef  RAND_MAX
  75.    #define RAND_MAX 32767
  76. #endif
  77.  
  78. /*--------------------------------------------------------------*\
  79.  *  Entry point declarations                                    *
  80. \*--------------------------------------------------------------*/
  81.  
  82. MRESULT EXPENTRY ClientWndProc  (HWND, ULONG, MPARAM, MPARAM);
  83. MRESULT EXPENTRY EntryFldDlgProc(HWND, ULONG, MPARAM, MPARAM);
  84. MRESULT EXPENTRY AboutDlgProc(HWND, ULONG, MPARAM, MPARAM);
  85. LONG    MessageBox(HWND, LONG, LONG, BOOL);
  86. VOID APIENTRY ExitProc(ULONG);
  87. BOOL Init(VOID);
  88.  
  89. INT main(LONG ,CHAR **);
  90. VOID _Optlink CalcThread(PVOID);
  91. VOID _Optlink DispThread(PVOID);
  92.  
  93. VOID EnableMenuItem(HWND, LONG, BOOL);
  94. VOID RandomizeData(ULONG);
  95. VOID BubbleSort(PCALCPARAM);
  96. VOID BatcherSort(PCALCPARAM);
  97. VOID BatcherSortR(PCALCPARAM, ULONG, ULONG, ULONG, BOOL);
  98. VOID QuickSort(PCALCPARAM);
  99. VOID QuickSortR(PCALCPARAM, LONG, LONG);
  100. VOID InsertionSort(PCALCPARAM);
  101. VOID FixSysMenu(HWND);
  102. VOID InitHelp(VOID);
  103. VOID HelpHelpForHelp(MPARAM);
  104. VOID HelpExtended(MPARAM);
  105. VOID HelpKeys(MPARAM);
  106. VOID HelpIndex(MPARAM);
  107. VOID HelpAbout(MPARAM);
  108. VOID DisplayHelpPanel(LONG);
  109. VOID DestroyHelpInstance(VOID);
  110. HEV  hev;
  111. RECTL  rcl;              /* Rectangle struct for painting  */
  112.  
  113. /*--------------------------------------------------------------*\
  114.  *  Global variables                                            *
  115. \*--------------------------------------------------------------*/
  116. CHAR szClientClass[40];
  117. USHORT Data[LISTCNT][MAX_ELEMS];     /* Array that contains the data to sort  */
  118.  
  119. /* Global data that defines each of the sort routines */
  120.  
  121.                               /* Color of each of the LISTCNT data lists.  */
  122. ULONG  ulColors[LISTCNT] = { CLR_RED,CLR_BLUE,CLR_DARKGREEN,CLR_CYAN };
  123.  
  124.           /* List of sorts to be executed for each of the LISTCNT threads. */
  125. VOID (*pExecSub[LISTCNT])(PCALCPARAM)={BubbleSort,BatcherSort,QuickSort,
  126.                            InsertionSort};
  127.                                                    /* Ascii names of sorts */
  128. CHAR *szSubNames[LISTCNT]={"Bubble Sort",
  129.                            "Batcher Sort",
  130.                            "Quick Sort",
  131.                            "Insertion Sort"};
  132.  
  133. HAB    hab;                              /* Anchor block for the process */
  134. HMQ    hmq;
  135. BOOL   fHelpEnabled;             /* flag to determine if help is enabled */
  136. CHAR   szUntitled[MESSAGELEN];           /* buffer for "Untitled" string */
  137. HWND   hwndFrame, hwndClient;
  138. static CHAR szLibName[HELPLIBRARYNAMELEN];
  139. static CHAR szWindowTitle[HELPLIBRARYNAMELEN];
  140. static HWND hwndHelpInstance;
  141. RECTL  rectl;
  142.  
  143. /****************************************************************\
  144.  * Function name: main(LONG sArgc,CHAR **ppArgv)
  145.  *
  146.  * Parameters:  NONE
  147.  *
  148.  * Returns: Always returns 0
  149.  *
  150.  * Purpose: Sets up the PM environment, calls the main window proc,
  151.  *          handles the window's messages then cleans up and exits.
  152.  *
  153.  * Usage:
  154. \****************************************************************/
  155. INT main(LONG sArgc,CHAR **ppArgv)
  156. {
  157.    QMSG         qmsg;
  158.    CHAR *pszName = "SORT";
  159.  
  160.    ULONG flFrameFlags = FCF_STANDARD;
  161.  
  162.    strncpy(szClientClass,pszName,strlen(pszName) );
  163.  
  164.    /* These PM calls should be error checked */
  165.    hab = WinInitialize(0);
  166.    hmq = WinCreateMsgQueue(hab, 0);
  167.  
  168.    if(!Init())
  169.    {
  170.        MessageBox(HWND_DESKTOP,
  171.                   IDMSG_INITFAILED,
  172.                   MB_OK | MB_ERROR,
  173.                   TRUE);
  174.        DosExit(EXIT_PROCESS,RETURN_ERROR);
  175.    }
  176.  
  177.  
  178.    hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
  179.                                   WS_VISIBLE,
  180.                                   &flFrameFlags,
  181.                                   szClientClass,
  182.                                   NULL,
  183.                                   0L,
  184.                                   (HMODULE)0,
  185.                                   ID_RESOURCE,
  186.                                   &hwndClient);
  187.    if(hwndFrame == NULLHANDLE)
  188.    {
  189.        MessageBox(HWND_DESKTOP,
  190.                   IDMSG_MAINWINCREATEFAILED,
  191.                   MB_OK | MB_ERROR,
  192.                   TRUE);
  193.        DosExit(EXIT_PROCESS,RETURN_ERROR);
  194.    }
  195.    InitHelp();
  196.  
  197.    while(WinGetMsg(hab,&qmsg,0,0,0))        /* Message loop */
  198.       WinDispatchMsg(hab,&qmsg);
  199.  
  200.    /* destroy the help instance */
  201.    DestroyHelpInstance();
  202.  
  203.    DosExit(EXIT_PROCESS,RETURN_SUCCESS);
  204.    return 0L;
  205. }
  206.  
  207. /****************************************************************\
  208.  *  Initialization routine
  209.  *---------------------------------------------------------------
  210.  *
  211.  *  Name:    Init()
  212.  *
  213.  *  Purpose: Performs initialization functions required before the main
  214.  *           window can be created.
  215.  *
  216.  *  Usage:   Called once before the main window is created.
  217.  *
  218.  *  Method:  - installs the routine ExitProc into the DosExitList chain
  219.  *           - registers all window classes
  220.  *           - performs any command line processing
  221.  *
  222.  *
  223.  *  Returns: TRUE - initialization is successful
  224.  *           FALSE - initialization failed
  225. \****************************************************************/
  226. BOOL Init(VOID)
  227. {
  228.  
  229.     /* Add ExitProc to the exit list to handle the exit processing. If
  230.      * there is an error, then terminate the process since there have
  231.      * not been any resources allocated yet                          */
  232.  
  233.     if(DosExitList(EXLST_ADD, ExitProc))
  234.     {
  235.         MessageBox(HWND_DESKTOP,
  236.                    IDMSG_CANNOTLOADEXITLIST,
  237.                    MB_OK | MB_ERROR,
  238.                    TRUE);
  239.         DosExit(EXIT_PROCESS, RETURN_ERROR);
  240.     }
  241.  
  242.     if(DosCreateEventSem(NULL,&hev,DC_SEM_SHARED,FALSE ) )
  243.     {
  244.         return(FALSE);
  245.     }
  246.  
  247.      /* load application name from resource file */
  248.     if(!WinLoadString(hab, 0, IDS_APPNAME, MAXNAMEL, szClientClass))
  249.         return FALSE;
  250.  
  251.     /* load "untitled" string */
  252.     if(!WinLoadString(hab, 0, IDS_UNTITLED, MESSAGELEN, szUntitled))
  253.         return FALSE;
  254.     /* register the main client window class */
  255.     if(!WinRegisterClass(hab,
  256.                         (PSZ)szClientClass,
  257.                         (PFNWP)ClientWndProc,
  258.                         CS_SIZEREDRAW | CS_CLIPCHILDREN,
  259.                         0))
  260.     {
  261.          return FALSE;
  262.     }
  263.     return( TRUE);
  264. }                                                   /* Init() */
  265.  
  266. /****************************************************************\
  267.  *  Exit list processing procedure
  268.  *--------------------------------------------------------------
  269.  *
  270.  *  Name:    ExitProc(usTermCode)
  271.  *
  272.  *  Purpose: Cleans up certain resources when the application terminates
  273.  *
  274.  *  Usage:   Routine is called by DosExitList when the application exits
  275.  *
  276.  *  Method:  Global resources, such as the main window and message queue,
  277.  *           are destroyed and any system resources used are freed.
  278.  *
  279.  *  Returns: Returns EXLST_EXIT to the DosExitList handler
  280.  *
  281. \****************************************************************/
  282. VOID APIENTRY ExitProc(ULONG usTermCode)
  283. {
  284.    /* destroy the main window if it exists */
  285.    if(WinIsWindow(hab, hwndFrame))  {
  286.        WinDestroyWindow(hwndFrame);
  287.    }
  288.  
  289.    /*--------------------------------------------------*\
  290.     *      Any other system resources used             *
  291.     *      (e.g. memory or files) should be freed here *
  292.    \*--------------------------------------------------*/
  293.  
  294.    WinDestroyMsgQueue(hmq);
  295.  
  296.    WinTerminate(hab);
  297.  
  298.    DosExitList(EXLST_EXIT, 0L);         /* termination complete */
  299.    return;
  300. }                                           /* ExitProc() */
  301.  
  302. /****************************************************************\
  303.  * Function name: ClientWndProc()
  304.  *
  305.  * Parameters:  hwnd, msg, mp1, mp2.  Standard PM Dialog Proc params.
  306.  *              No user data is expected in the WM_CREATE.
  307.  *
  308.  * Returns: Returns with WM_QUIT message
  309.  *
  310.  * Purpose: Handles all the messages associated with the main window
  311.  *          and calls the appropriate handling procedures.
  312.  *
  313.  * Usage  : Called only by main()
  314. \****************************************************************/
  315. MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  316. {
  317.    HPS    hps=0;                         /* Handle for painting            */
  318.    POINTL ptl;                           /* Point struct for painting      */
  319.    static CALCPARAM cp[LISTCNT];         /* Struct passed to sort threads  */
  320.    static TID    tidCalc[LISTCNT];       /* Sort threads IDs               */
  321.    static CALCPARAM cpDisp;              /* Struct passed to disp thread   */
  322.    static TID    tidDisplay;             /* Secondary display thread ID    */
  323.    static USHORT usWindowYCoord=1;       /* Holds current client window ht */
  324.    static BYTE   cThreadCnt = 0;         /* Count of sort threads running  */
  325.    static USHORT cSetSize=MAX_ELEMS;     /* User sort set size             */
  326.    USHORT cnt,cnt2,usID;                 /* Utility counters               */
  327.    ULONG  ulBlip;                        /* Holds the marker pos for Paint */
  328.    MRESULT sRC;
  329.  
  330.    switch(msg)
  331.    {
  332.       case WM_CREATE:
  333.          RandomizeData(cSetSize);        /* Initially randomize data set   */
  334.          /* Start display thread */
  335.          cpDisp.hwnd        = hwnd;
  336.          cpDisp.Array       = &usWindowYCoord;
  337.          cpDisp.pcThreadCnt = &cThreadCnt;
  338.          cpDisp.pcSetSize   = &cSetSize;
  339.          if((tidDisplay = _beginthread(DispThread,
  340. #if __IBMC__
  341.                                        NULL,
  342. #endif
  343.                                        STACKSIZE,
  344.                                        (PVOID) &cpDisp)) == (USHORT)-1)
  345.          {
  346.             WinAlarm(HWND_DESKTOP, WA_ERROR);  /* can't start display thread */
  347.             DosExit(EXIT_PROCESS,1);
  348.          }
  349.          /* Up the display priority an arbitrary amount to cause it to
  350.             update more rapidly and to give it a higher priority than
  351.             the sort threads.*/
  352.          DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 5, tidDisplay);
  353.  
  354.          return (MRESULT)0L;
  355.  
  356.       case WM_SIZE:
  357.          WinInvalidateRect(hwnd,NULL,FALSE);     /* Force a redraw */
  358.          sRC = WinDefWindowProc(hwnd, msg, mp1, mp2);
  359.          return sRC;
  360.  
  361.       case WM_PAINT:
  362.          hps = WinBeginPaint(hwnd,0,0);   /* Get paint handle      */
  363.          WinQueryWindowRect(hwnd,&rcl);
  364.          if(NELEMS < MAX_ELEMS )
  365.          {
  366.                cSetSize = NELEMS;
  367.          }
  368.          else
  369.          {
  370.                cSetSize = MAX_ELEMS;
  371.          }
  372.          RandomizeData(cSetSize);        /* Initially randomize data set   */
  373.          usWindowYCoord = rcl.yTop;
  374.           /* Draw if screen */
  375.           /* is big enough  */
  376.          if( (XOFFSET + (2 * COLUMNOFFSET))< (rcl.xRight-rcl.xLeft) &&
  377.             (YOFFSET * ROWCNT) < (rcl.yTop-rcl.yBottom ) )
  378.          {
  379.             DrawRect(rcl.xLeft,rcl.yBottom,         /* White out the screen  */
  380.                      rcl.xRight,rcl.yTop,CLR_WHITE);
  381.  
  382.             DrawLine(XOFFSET, YOFFSET,              /* Draw baseline         */
  383.                      rcl.xRight,YOFFSET,CLR_BLACK);
  384.  
  385.             DrawLine(XOFFSET, YOFFSET,              /* Draw vertical line    */
  386.                      XOFFSET,rcl.yTop,CLR_BLACK);
  387.  
  388.             for(cnt=0;cnt<LISTCNT;cnt++)            /* Draw data points      */
  389.             {
  390.                for(cnt2=0;cnt2<cSetSize;cnt2++)
  391.                {
  392.                   ulBlip = (rcl.yTop-YOFFSET-5) * Data[cnt][cnt2] / RAND_MAX
  393.                            + YOFFSET+1;
  394.  
  395.                   Draw2Pel(XOFFSET+1 + cnt2, ulBlip, ulColors[cnt]);
  396.                }
  397.             }
  398.             for(cnt=0,cnt2= 0;cnt<COLUMNCNT;cnt++)          /* Do bottom legend      */
  399.             {
  400.                if(cnt2 >= ROWCNT )
  401.                {
  402.                     cnt2 = 0;
  403.                }
  404.                ptl.x = XOFFSET + cnt2++ *COLUMNOFFSET;
  405.                /*
  406.                 *next row after the last column
  407.                 */
  408.                if(cnt >=  (COLUMNCNT / ROWCNT ) )
  409.                {
  410.                     ptl.y = YOFFSET - ( 2 * ROWOFFSET);
  411.                }
  412.                else
  413.                {
  414.                     ptl.y = YOFFSET - ROWOFFSET;
  415.                }
  416.                GpiSetColor(hps,ulColors[cnt]);
  417.                GpiCharStringAt(hps,&ptl,
  418.                                (LONG) strlen(szSubNames[cnt]),
  419.                                szSubNames[cnt]);
  420.             }
  421.          }
  422.  
  423.          WinEndPaint(hps);
  424.          return (MRESULT)0L;
  425.  
  426.       case WM_COMMAND:
  427.          switch(SHORT1FROMMP(mp1))
  428.          {
  429.             case IDM_START:
  430.  
  431.                /*
  432.                 *clear the drawing semaphore
  433.                 */
  434.                DosPostEventSem(hev);
  435.                /* Try to get stack space */
  436.                for(cnt=0;cnt<LISTCNT;cnt++)
  437.                {
  438.                   cp[cnt].hwnd          = hwnd;  /* Set the static struct  */
  439.                   cp[cnt].fContinueCalc = TRUE;
  440.                   cp[cnt].pFunc         = pExecSub[cnt];
  441.                   cp[cnt].usID          = cnt;
  442.                   cp[cnt].Array         = Data[cnt];
  443.                   cp[cnt].cArray        = cSetSize;
  444.  
  445.                   /* Try to start the thread */
  446.                   if( (tidCalc[cnt] = _beginthread(CalcThread,
  447. #if __IBMC__
  448.                                               NULL,
  449. #endif
  450.                                               STACKSIZE,
  451.                                               (PVOID)&cp[cnt])) == (USHORT)-1)
  452.                   {
  453.                      WinAlarm(HWND_DESKTOP, WA_ERROR);
  454.                      return (MRESULT)0L;
  455.                   }
  456.                   if(cThreadCnt++ == 0)  /* When the first thread starts */
  457.                   {
  458.                      /* Disable Start, Set, and Randomize, enable Stop */
  459.                      EnableMenuItem(hwnd,IDM_START,FALSE);
  460.                      EnableMenuItem(hwnd,IDM_SET,FALSE);
  461.                      EnableMenuItem(hwnd,IDM_RANDOM,FALSE);
  462.                      EnableMenuItem(hwnd,IDM_STOP,TRUE);
  463.                   }
  464.                }
  465.                return (MRESULT)0L;
  466.  
  467.             case IDM_STOP:
  468.                for(cnt=0;cnt<LISTCNT;cnt++)
  469.                   cp[cnt].fContinueCalc = FALSE;  /* Notify thread to quit  */
  470.                return (MRESULT)0L;
  471.  
  472.             case IDM_RANDOM:
  473.                RandomizeData(cSetSize);                /* Randomize data */
  474.                WinInvalidateRect(hwnd,NULL,FALSE);     /* Force a redraw */
  475.                return (MRESULT)0L;
  476.  
  477.             case IDM_SET:
  478.                if(WinDlgBox(HWND_DESKTOP, hwnd, /* Pop up the query/set box */
  479.                             EntryFldDlgProc,(HMODULE)0,IDD_SETCOUNT,
  480.                             (VOID FAR *) &cSetSize))
  481.                {
  482.                   WinInvalidateRect(hwnd,NULL,FALSE);     /* Force a redraw */
  483.                }
  484.                return (MRESULT)0L;
  485.  
  486.             case IDM_GENERALHELP:
  487.                HelpExtended(mp2);
  488.                return (MRESULT)0L;
  489.  
  490.             case IDM_USINGHELP:
  491.                HelpHelpForHelp(mp2);
  492.                return (MRESULT)0L;
  493.  
  494.             case IDM_TUTORIAL:
  495.                HelpKeys(mp2);
  496.                return (MRESULT)0L;
  497.  
  498.             case IDM_HELPINDEX:
  499.                HelpIndex(mp2);
  500.                return (MRESULT)0L;
  501.  
  502.             case IDM_HELPPRODUCTINFO:
  503.                HelpAbout(mp2);
  504.                return (MRESULT)0L;
  505.  
  506.             default:
  507.                sRC = WinDefWindowProc(hwnd, msg, mp1, mp2);
  508.                return sRC;
  509.          }
  510.          break;
  511.  
  512.       case IDM_DONE:
  513.          usID = SHORT1FROMMP(mp1);  /* Get ID of quit thread     */
  514.  
  515.          if(--cThreadCnt == 0)              /* If all quit, enable menus */
  516.          {
  517.             EnableMenuItem(hwnd,IDM_START,TRUE);
  518.             EnableMenuItem(hwnd,IDM_SET,TRUE);
  519.             EnableMenuItem(hwnd,IDM_RANDOM,TRUE);
  520.             EnableMenuItem(hwnd,IDM_STOP,FALSE);
  521.          }
  522.          return (MRESULT)0L;
  523.  
  524.       case HM_QUERY_KEYS_HELP:
  525.          return ((MRESULT)PANEL_KEYSHELP);
  526.  
  527.       case WM_CLOSE:
  528.  
  529.          DosCloseEventSem(hev);
  530.          for(cnt=0;cnt<LISTCNT;cnt++)
  531.          {
  532.             DosKillThread(tidCalc[cnt]);
  533.          }
  534.          DosKillThread(tidDisplay);
  535.          WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  536.          return 0L;
  537.  
  538.       default:
  539.          sRC = WinDefWindowProc(hwnd, msg, mp1, mp2);
  540.          return sRC;
  541.    }
  542.  
  543.    return (MRESULT)0L;
  544. }
  545.  
  546. /****************************************************************\
  547.  * Function name: CalcThread()
  548.  *
  549.  * Parameters:  pcp is a struct which contains the hwnd handle, the
  550.  *              continue flag which is initially set to TRUE, the ID
  551.  *              which is the
  552.  *
  553.  * Returns: VOID
  554.  *
  555.  * Purpose: This generic stub calls the passed "sort" function with a pointer
  556.  *          to the data and an item count, then when the sort terminates, it
  557.  *          cleans up by Posting a done message, then terminating the thread.
  558.  *
  559.  * Usage  : No DosExitCritSec() is called since _endthread()
  560.  *                 clears the critical section when the thread is
  561.  *                 terminated.
  562.  *
  563. \****************************************************************/
  564. VOID CalcThread(PVOID pcp)
  565. {
  566.    (*((PCALCPARAM)pcp)->pFunc)(pcp);         /* Execute recurs routine */
  567.                            /* Set Crit so the IDM_DONE isn't processed */
  568.                         /* until this thread has completely terminated */
  569.    DosEnterCritSec();
  570.  
  571.    WinPostMsg(((PCALCPARAM)pcp)->hwnd,IDM_DONE,
  572.               MPFROMSHORT(((PCALCPARAM)pcp)->usID),NULL);/* Post done */
  573.  
  574.    /*
  575.     *set the post count for each thread
  576.     *that goes through
  577.     */
  578.    DosPostEventSem(hev);
  579.  
  580.    _endthread();                /* Terminate thread and exit crit sec */
  581.    return;
  582. }
  583.  
  584. /****************************************************************\
  585.  * Function name: DispThread()
  586.  *
  587.  * Parameters:  pcp is a struct which contains the hwnd handle, the
  588.  *              count of active threads, the ->Array element points to
  589.  *              the current height of the window which can be dynamically
  590.  *              resized by the user, the pcSetSize points to the current
  591.  *              set size which can be changed by the user only when the
  592.  *              sort is stopped.
  593.  *              None of the other pcp members are used.
  594.  *
  595.  * Returns: VOID
  596.  *
  597.  * Purpose: This routine is run as a secondary thread to update the screen
  598.  *          when the sort threads are running.  It works by making passes
  599.  *          through the data lists and redrawing them.  A DosSleep(0) is
  600.  *          called at the end of each pass to help sychronize things a bit.
  601.  *
  602.  * Usage  : Note that this thread is started when the program is
  603.  *                 initialized, and is never terminated.  Note that
  604.  *                 fDoUpdate is used in such a way that the screen is
  605.  *                 ALWAYS updated once after all threads have terminated.
  606.  *                 This avoids the possibility of the display not being
  607.  *                 fully accurate when the sorts terminate.
  608.  *
  609. \****************************************************************/
  610. VOID DispThread(PVOID pvData )
  611. {
  612.    USHORT cnt,cnt2;      /* Utility counters                            */
  613.    HPS hps;              /* Presentation space handle                   */
  614.    POINTL ptl;           /* Used for various drawing macros             */
  615.    ULONG  ulBlip;        /* Holds the Y offset for a given data point   */
  616.    PCALCPARAM pcp;       /* after all sort threads terminate            */
  617.    USHORT *pusYCoord;
  618.    ULONG  ulPostCount;
  619.  
  620.    pcp = (PCALCPARAM) pvData;
  621.    pusYCoord = pcp->Array;
  622.    /* Points to location that always    */
  623.    /* contains current client wind hgt  */
  624.  
  625.    hps = WinGetPS( pcp->hwnd);
  626.  
  627.    while(TRUE)
  628.    {
  629.       /*
  630.        *sit and wait on the clearing of the semaphore
  631.        */
  632.       DosWaitEventSem(hev,SEM_INDEFINITE_WAIT);
  633.       DosQueryEventSem(hev,&ulPostCount);
  634.       /*
  635.        *wait on all 4 threads + the post used to start
  636.        *to post
  637.        */
  638.       if(ulPostCount == 5)
  639.       {
  640.           ulPostCount = 0;
  641.           DosResetEventSem(hev,&ulPostCount);
  642.       }
  643.       for(cnt=0;cnt<*((PCALCPARAM)pcp)->pcSetSize;cnt++)/* Update data set */
  644.       {
  645.          DrawLine(XOFFSET+1 + cnt,YOFFSET+1,      /* Erase vertical column */
  646.                   XOFFSET+1 + cnt,*pusYCoord, CLR_WHITE);
  647.  
  648.          for(cnt2=0;cnt2<LISTCNT;cnt2++)          /* Draw each point       */
  649.          {
  650.             ulBlip = (ULONG) (*pusYCoord-YOFFSET-5)*Data[cnt2][cnt] / RAND_MAX
  651.                       + YOFFSET+1;
  652.             Draw2Pel(XOFFSET+1 + cnt, ulBlip, ulColors[cnt2]);
  653.          }
  654.       }
  655.  
  656.    }
  657.  
  658.    /* Note that these 3 lines NEVER get executed, but should the program be
  659.       modified to end the thread, this is the appropriate termination code. */
  660.    WinReleasePS(hps);
  661.    _endthread();
  662.    return;
  663. }
  664.  
  665. /****************************************************************\
  666.  * Function name: BubbleSort()
  667.  *
  668.  * Parameters:  pcp is a struct which contains the hwnd handle, a
  669.  *              pointer to the data array, and a count of the items in
  670.  *              the data array.
  671.  *              None of the other pcp members are used.
  672.  *
  673.  * Returns: VOID
  674.  *
  675.  * Purpose:  Implements a bubble sort which is an O(n^2) algorithm.  It
  676.  *           works by repeatedly going through the data and comparing
  677.  *           consecutive elements and swapping them if they aren't in
  678.  *           the correct order.  This guarantees that each pass will
  679.  *           place at least one additional item in its appropriate
  680.  *           place.
  681.  *
  682.  * Usage:
  683. \****************************************************************/
  684. VOID BubbleSort(PCALCPARAM pcp)
  685. {
  686.    BOOL fModified = FALSE; /* Set whenever a swap is done, if an entire */
  687.                            /* pass doesn't set the flag, the we're done */
  688.    INT    cnt;
  689.    INT    cnt2;            /* Counters used for the 2-level loops       */
  690.    USHORT usTemp;          /* Used to hold a data item during a swap    */
  691.  
  692.    for(cnt=(ULONG)(pcp->cArray-1);cnt>=0;cnt--) /*Set the max no. of passes*/
  693.    {
  694.       for(cnt2=0;cnt2<cnt;cnt2++) /* Only sort thru current cnt pass    */
  695.       {
  696.          if(!pcp->fContinueCalc)  /* User wishes to terminate the sort  */
  697.             return;
  698.  
  699.          if(pcp->Array[cnt2]>pcp->Array[cnt2+1]) /* Items need to swap  */
  700.          {
  701.             fModified = TRUE;
  702.  
  703.             usTemp = pcp->Array[cnt2];
  704.             pcp->Array[cnt2] = pcp->Array[cnt2+1];
  705.             pcp->Array[cnt2+1]= usTemp;
  706.          }
  707.       }
  708.       if(!fModified)          /* Nothing changed during the entire pass */
  709.          break;
  710.       fModified = FALSE;                       /* Reset the modify flag */
  711.    }
  712.    return;
  713. }
  714.  
  715. /****************************************************************\
  716.  * Function name: InsertionSort()
  717.  *
  718.  * Parameters:  pcp is a struct which contains the hwnd handle, a
  719.  *              pointer to the data array, and a count of the items in
  720.  *              the data array.
  721.  *              None of the other pcp members are used.
  722.  *
  723.  * Returns: VOID
  724.  *
  725.  * Purpose:  Implements an insertion sort which is an O(n^2) algorithm.
  726.  *           This sort works much faster and does not require that much
  727.  *           additional code to implement.  It works by setting a sorted
  728.  *           list to be just the first element, the working each
  729.  *           successive item into the already sorted list.
  730.  *
  731.  * Usage:
  732. \****************************************************************/
  733. VOID InsertionSort(PCALCPARAM pcp)
  734. {
  735.    SHORT cnt,cnt2;            /* Counters used for the 2-level loops    */
  736.    USHORT usTemp;             /* Used to hold a data item during a swap */
  737.  
  738.    for(cnt=1;cnt<(LONG)pcp->cArray;cnt++)  /* Insert each item in turn */
  739.    {
  740.       if(!pcp->fContinueCalc)      /* User wishes to terminate the sort */
  741.          return;
  742.       usTemp=pcp->Array[cnt];                   /* Hold value to insert */
  743.       cnt2=(LONG)(cnt-1);
  744.       while(pcp->Array[cnt2]>usTemp)    /* Move items down to make room */
  745.       {
  746.          pcp->Array[cnt2+1]=pcp->Array[cnt2];
  747.          cnt2--;
  748.          if(cnt2<0)
  749.             break;
  750.       }
  751.       pcp->Array[cnt2+1] = usTemp;                   /* Insert the item */
  752.    }
  753.    return;
  754. }
  755.  
  756. /****************************************************************\
  757.  * Function name: BatcherSort()
  758.  *
  759.  * Parameters:  pcp is a struct which contains the continue flag,
  760.  *              a pointer to the data array, and a count of the items in
  761.  *              the data array.
  762.  *              None of the other pcp members are used.
  763.  *
  764.  * Returns: VOID
  765.  *
  766.  * Purpose:  This routine is a stub that calls the recursive Batcher sort
  767.  *           with the proper initial arguments.
  768.  *
  769.  * Usage:  It passes the pcp, the size of the array to be sorted,
  770.  *                  the offset to start sorting at(0), the number number
  771.  *                  of elements each item is from neighboring elements (1),
  772.  *                  and Half flag to sort the halves (1=YES).
  773. \****************************************************************/
  774. VOID BatcherSort(PCALCPARAM pcp)
  775. {
  776.    BatcherSortR(pcp,pcp->cArray,0,1,1);
  777.    return;
  778. }
  779.  
  780. /****************************************************************\
  781.  * Function name: BatcherSortR()
  782.  *
  783.  * Parameters:  pcp is a struct which contains the continue flag,
  784.  *              a pointer to the data array.
  785.  *              None of the other pcp members are used.
  786.  *              usArrSize is the number of elements in the current sort set.
  787.  *              usStart is the offset to the 1st element in the set.
  788.  *              usSkip is the spacing between consecutive elements.
  789.  *              fHalves sorts the 2 halves when set, otherwise skips the
  790.  *                      1st 2 of the 4 sub-sorts.
  791.  *
  792.  * Returns: VOID
  793.  *
  794.  * Purpose:  Implements Batcher sort which is O(n lg n).  The advantage
  795.  *           of the batcher sort is that the comparisons made do NOT
  796.  *           depend upon the outcome of previous comparisons.  This makes
  797.  *           it a good algorithm for parallelism.  The algorithm works as
  798.  *           follows:  Sort the first half, sort the second half, sort the
  799.  *           odd elements, sort the even elements, then compare swap
  800.  *           elements 2/3, 4/5, ...
  801.  *
  802.  * Usage  :  There are several adaptations to the algorithm to
  803.  *                  allow it to work with arbitrary sized data sets
  804.  *                  (the original required a power of 2 sized data
  805.  *                  set):  if the set size is less than 2, the routine
  806.  *                  returns, the first "half" is always the largest
  807.  *                  possible power of two, and the top value for the
  808.  *                  final compare/swap is adjusted to round up in
  809.  *                  case of an odd data set.
  810.  *                  Another optimization is that involving the fHalves
  811.  *                  flag.  This stems from the observation that when
  812.  *                  the odd/even sort recurses, the first and second
  813.  *                  halves are already sorted, thus the first 2
  814.  *                  recursive calls are unnecessary in this case.
  815.  *
  816. \****************************************************************/
  817. VOID BatcherSortR(PCALCPARAM pcp, ULONG usArrSize, ULONG usStart,
  818.                   ULONG usSkip, BOOL fHalves)
  819. {
  820.    USHORT cnt,usUpper,usTemp; /* Utility variables */
  821.  
  822.    if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
  823.       return;
  824.  
  825.    if(usArrSize<2) /* No sorting needed if <2 items in the set */
  826.       return;
  827.  
  828.    if(usArrSize==2) /* Do simple compare/swap if there are 2 elements */
  829.    {
  830.       if(pcp->Array[usStart]>pcp->Array[usStart+usSkip])
  831.       {
  832.          usTemp = pcp->Array[usStart];
  833.          pcp->Array[usStart] = pcp->Array[usStart+usSkip];
  834.          pcp->Array[usStart+usSkip]= usTemp;
  835.       }
  836.       return;
  837.    }
  838.  
  839.    usTemp=1;                  /* usTemp ends up holding the smallest power */
  840.    while(usTemp < usArrSize)  /* of 2 that is at least as big as usArrSize */
  841.       usTemp *= 2;
  842.  
  843.    if(fHalves)  /* If the sort was NOT called by the odd/even recurses */
  844.    {
  845.       BatcherSortR(pcp,(ULONG)(usTemp/2),usStart,usSkip,(BOOL)1);    /* Sort 1st half */
  846.       BatcherSortR(pcp,(ULONG)(usArrSize-usTemp/2),       /* Sort 2nd half */
  847.                    (ULONG)(usStart+usTemp/2*usSkip),usSkip,(BOOL)1);
  848.    }
  849.    BatcherSortR(pcp,(ULONG)(usArrSize-usArrSize/2),usStart,(ULONG)(usSkip*2),(BOOL)0); /* Sort evens */
  850.    BatcherSortR(pcp,(ULONG)(usArrSize/2),(ULONG)(usStart+usSkip),(ULONG)(usSkip*2),(BOOL)0);    /* Sort odds  */
  851.  
  852.    if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
  853.       return;
  854.  
  855.    usUpper=(ULONG)(usStart+usSkip+(usArrSize-usArrSize/2-1)*2*usSkip);
  856.    for(cnt=usStart+usSkip;cnt<usUpper;cnt+=usSkip*2) /* Do final compares */
  857.    {
  858.       if(pcp->Array[cnt]>pcp->Array[cnt+usSkip])
  859.       {
  860.          usTemp = pcp->Array[cnt];
  861.          pcp->Array[cnt] = pcp->Array[cnt+usSkip];
  862.          pcp->Array[cnt+usSkip]= usTemp;
  863.       }
  864.       if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
  865.          return;
  866.    }
  867.    return;
  868. }
  869.  
  870.  
  871. /****************************************************************\
  872.  * Function name: QuickSort()
  873.  *
  874.  * Parameters:  pcp is a struct which contains the continue flag,
  875.  *              a pointer to the data array, and a count of the items in
  876.  *              the data array.
  877.  *              None of the other pcp members are used.
  878.  *
  879.  * Returns: VOID
  880.  *
  881.  * Purpose:  This routine is a stub that calls the recursive Quick sort
  882.  *           with the proper initial arguments.
  883.  *
  884.  * Usage  :  It passes the pcp (Which contains the array ptr),
  885.  *                  the offset to start sorting at(0), and the offset to
  886.  *                  finish sorting at (Array size-1).
  887.  *
  888. \****************************************************************/
  889. VOID QuickSort(PCALCPARAM pcp)
  890. {
  891.    QuickSortR(pcp,0,(pcp->cArray-1));
  892.    return;
  893. }
  894.  
  895.  
  896. /****************************************************************\
  897.  * Function name: QuickSortR()
  898.  *
  899.  * Parameters:  pcp is a struct which contains the continue flag,
  900.  *              a pointer to the data array.
  901.  *              None of the other pcp members are used.
  902.  *              sLeft is the offset of the leftmost sort element (smallest).
  903.  *              sRight is the offset of rightmost sort element (largest).
  904.  *
  905.  * Returns: VOID
  906.  *
  907.  * Purpose:  Implements Quick sort which is O(n lg n).  Quick sort is a
  908.  *           good all-purpose sorting algorithm and is widely used.  This
  909.  *           implementation works by placing the first element in the list
  910.  *           into its correct place, by moving all elements smaller to its
  911.  *           left, and all numbers larger to its right.  The Quick sort
  912.  *           recurses on the smaller side of the properly placed element,
  913.  *           and loops back through the same routine for the larger side.
  914.  *
  915.  *           NOTE: This routine does not recurse on both sides of the
  916.  *                 partition element.  It only recurses on the smaller
  917.  *                 of the two sides.  This was done in order to eliminate
  918.  *                 the stack overrun when it tries to sort an already
  919.  *                 sorted list.
  920.  *
  921.  * Usage:
  922.  *
  923. \****************************************************************/
  924. VOID QuickSortR(PCALCPARAM pcp, LONG sLeft, LONG sRight)
  925. {
  926.    SHORT sTempLeft  = sLeft;    /* Holds lower bound on split position      */
  927.    SHORT sTempRight = sRight;   /* Holds upper bound on split position      */
  928.    SHORT sSplit;                /* Used to hold offset of positioned elem   */
  929.    USHORT usTemp;               /* Holds temp element during positioning    */
  930.  
  931.    while(TRUE)
  932.    {
  933.       if(sLeft >= sRight)          /* If there is <=1 element, return */
  934.          return;
  935.  
  936.       if(!pcp->fContinueCalc)      /* User wishes to terminate the sort */
  937.          return;
  938.  
  939.       /* Split list, sSplit will contain the split element */
  940.       usTemp = pcp->Array[sTempLeft];
  941.  
  942.       while(TRUE)    /* Loop thru 2 cases until the split position is found */
  943.       {
  944.          while(pcp->Array[sTempRight] > usTemp && /* Skip elems on right side  */
  945.                            sTempRight > sLeft)    /* that are > the split elem */
  946.             sTempRight--;
  947.  
  948.          if(sTempRight<=sTempLeft)  /* Left and Right have met, split is found */
  949.          {
  950.             pcp->Array[sTempLeft]=usTemp;  /* Place split elem at proper place */
  951.             sSplit = sTempLeft;
  952.             break;
  953.          }
  954.          pcp->Array[sTempLeft++] =
  955.                        pcp->Array[sTempRight];    /* Move small element to LHS */
  956.  
  957.          while(pcp->Array[sTempLeft] < usTemp &&  /* Skip elems on left side   */
  958.                            sTempLeft < sRight)    /* that are < the split elem */
  959.             sTempLeft++;
  960.  
  961.          if(sTempRight<=sTempLeft)  /* Left and Right have met, split is found */
  962.          {
  963.             pcp->Array[sTempRight]=usTemp; /* Place split elem at proper place */
  964.             sSplit = sTempRight;
  965.             break;
  966.          }
  967.          pcp->Array[sTempRight--] =
  968.                        pcp->Array[sTempLeft];     /* Move large element to RHS */
  969.       }
  970.  
  971.       if ((sSplit - sLeft) > (sRight - sSplit)) {
  972.          /* left half is larger than right half */
  973.          QuickSortR(pcp, sSplit+1, sRight);   /* Sort the 2nd half of the list */
  974.          if(!pcp->fContinueCalc)            /* User wishes to terminate sort */
  975.            return;
  976.          sTempLeft = sLeft;                 /* Set up to sort the 1st half */
  977.          sTempRight = sRight = sSplit - 1;
  978.       }
  979.       else {
  980.          /* right half is larger than left half */
  981.          QuickSortR(pcp, sLeft, sSplit-1);    /* Sort the 1st half of the list */
  982.          if(!pcp->fContinueCalc)            /* User wishes to terminate sort */
  983.            return;
  984.          sTempRight = sRight;               /* Set up to sort the 2nd half */
  985.          sTempLeft = sLeft = sSplit + 1;
  986.       }
  987.    }
  988.    return;
  989. }
  990.  
  991. /****************************************************************\
  992.  * Function name: EnableMenuItem()
  993.  *
  994.  * Parameters:  hwnd is a handle of the current window.
  995.  *              sMenuItem is the ID of the item to Enable/Disable.
  996.  *              fEnable will enable item if TRUE, otherwise disables it.
  997.  *
  998.  * Returns: VOID
  999.  *
  1000.  * Purpose: This routine handles enabling/disabling of menu items.  This
  1001.  *          is done by getting Parent and Menu hwnd handles then sending
  1002.  *          the appropriate message.
  1003.  *
  1004.  * Usage:
  1005.  *
  1006. \****************************************************************/
  1007. VOID EnableMenuItem(HWND hwnd, LONG sMenuItem, BOOL fEnable)
  1008. {
  1009.    HWND hwndParent = WinQueryWindow(hwnd, QW_PARENT);
  1010.    HWND hwndMenu   = WinWindowFromID(hwndParent, FID_MENU);
  1011.  
  1012.    WinSendMsg(hwndMenu, MM_SETITEMATTR,
  1013.               MPFROM2SHORT(sMenuItem, TRUE),
  1014.               MPFROM2SHORT(MIA_DISABLED, fEnable ? 0 : MIA_DISABLED));
  1015.    return;
  1016. }
  1017.  
  1018. /****************************************************************\
  1019.  * Function name: EntryFldDlgProc()
  1020.  *
  1021.  * Parameters:  hwnd, msg, mp1, mp2.  Standard PM Dialog Proc params.
  1022.  *              A pointer to the current set size is passed in WM_INITDLG.
  1023.  *
  1024.  * Returns: Terminates with a TRUE iff a new valid data set size is entered.
  1025.  *
  1026.  * Purpose: Handles all the messages associated with the set entry field
  1027.  *          and calls the appropriate handling procedures.  The purpose
  1028.  *          of this dialog box is to get a new data set size for the
  1029.  *          sort routines.
  1030.  *
  1031.  *
  1032.  * Usage  : If the value entered is valid, the proc will set the
  1033.  *                 variable passed in through the WM_INITDLG to the value.
  1034. \****************************************************************/
  1035. MRESULT EXPENTRY EntryFldDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1036. {
  1037.    SHORT   sNewSize=0;                                /* Holds new set set */
  1038.    static  SHORT *pcSetSize;  /* Set to point to user-passed set size */
  1039.    MRESULT sRC;
  1040.  
  1041.    switch(msg)
  1042.    {
  1043.       case WM_INITDLG:
  1044.          FixSysMenu(hwnd);
  1045.          pcSetSize=PVOIDFROMMP(mp2);
  1046.          WinSendDlgItemMsg(hwnd, IDD_ENTRYFLD,EM_SETTEXTLIMIT,  /* Limit len */
  1047.                                  MPFROM2SHORT(4,0),NULL);
  1048.          WinSetDlgItemShort(hwnd, IDD_ENTRYFLD,
  1049.                               *pcSetSize,TRUE);
  1050.          return (MRESULT)0L;                           /* Allow normal focus setting */
  1051.  
  1052.       case WM_COMMAND:
  1053.          switch(SHORT1FROMMP(mp1))
  1054.          {
  1055.             case DID_OK:
  1056.                WinQueryDlgItemShort(hwnd, IDD_ENTRYFLD,
  1057.                                     &sNewSize, TRUE); /* Get the short      */
  1058.                if(sNewSize>0 && sNewSize<=MAX_ELEMS)  /* Set new data set size */
  1059.                {
  1060.                   *pcSetSize =  sNewSize;
  1061.                   WinDismissDlg(hwnd,TRUE);
  1062.                }
  1063.                else                                   /* Invalid value      */
  1064.                {
  1065.                   MessageBox(hwnd, IDMSG_ERRORSIZE,
  1066.                                      MB_OK | MB_ERROR, TRUE);
  1067.                   return (MRESULT)FALSE;
  1068.                }
  1069.                return (MRESULT)0L;
  1070.  
  1071.             case DID_CANCEL:
  1072.                WinDismissDlg(hwnd,FALSE);
  1073.                return (MRESULT)0L;
  1074.  
  1075.             default:
  1076.                sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
  1077.                return sRC;
  1078.          }
  1079.          break;
  1080.  
  1081.       default:
  1082.          sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
  1083.          return sRC;
  1084.    }
  1085.    return (MRESULT)0L;
  1086. }
  1087.  
  1088. /****************************************************************\
  1089.  * Function name: AboutDlgProc()
  1090.  *
  1091.  * Parameters:  hwnd, msg, mp1, mp2.  Standard PM Dialog Proc params.
  1092.  *
  1093.  * Returns:
  1094.  *
  1095.  * Purpose: Handles all the messages associated with the About dialog.
  1096.  *
  1097.  * Usage:
  1098.  *
  1099. \****************************************************************/
  1100. MRESULT EXPENTRY AboutDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1101. {
  1102.    MRESULT sRC;
  1103.  
  1104.    switch(msg)
  1105.    {
  1106.       case WM_INITDLG:
  1107.          FixSysMenu(hwnd);
  1108.          return (MRESULT)0L;
  1109.  
  1110.       case WM_COMMAND:
  1111.          WinDismissDlg(hwnd, TRUE);
  1112.          return (MRESULT)0L;
  1113.  
  1114.       default:
  1115.          sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
  1116.          return sRC;
  1117.    }
  1118.    return (MRESULT)0L;
  1119. }
  1120.  
  1121. /****************************************************************\
  1122.  * Function name: RandomizeData()
  1123.  *
  1124.  * Parameters:  cSetSize is the current size of the data set
  1125.  *
  1126.  * Returns: VOID
  1127.  *
  1128.  * Purpose: This routine randomizes the data arrays.
  1129.  *
  1130.  * Usage  : This routine assumes that LISTCNT and NELEMS define
  1131.  *                 the dimensions of the global Data array which is
  1132.  *                 randomized.
  1133. \****************************************************************/
  1134. VOID RandomizeData(ULONG cSetSize)
  1135. {
  1136.    USHORT cnt,cnt2;
  1137.  
  1138.    for(cnt=0;cnt<LISTCNT;cnt++)
  1139.    {
  1140.       for(cnt2=0;cnt2<cSetSize;cnt2++)
  1141.          Data[cnt][cnt2] = rand();
  1142.    }
  1143.    return;
  1144. }
  1145.  
  1146. /****************************************************************\
  1147.  * Function name: FixSysMenu()
  1148.  *
  1149.  * Parameters:  hwndDlg - handle to calling dialog
  1150.  *
  1151.  * Returns: VOID
  1152.  *
  1153.  * Purpose: This routine removes the Restore, Size, Minimize, and
  1154.  *          Maximize options from the system menu of a dialog.
  1155.  *
  1156.  * Usage  : Called during the WM_INITDLG of a dialog procedure.
  1157.  *
  1158. \****************************************************************/
  1159. VOID FixSysMenu(HWND hwndDlg)
  1160. {
  1161.    HWND hwndMenu;                                   /* handle to system menu */
  1162.  
  1163.    hwndMenu = WinWindowFromID(hwndDlg, FID_SYSMENU);
  1164.  
  1165.    WinSendMsg(hwndMenu,               /* delete Restore from the system menu */
  1166.               MM_DELETEITEM,
  1167.               MPFROM2SHORT(SC_RESTORE, TRUE),
  1168.               MPFROMP(NULL));
  1169.  
  1170.    WinSendMsg(hwndMenu,                  /* delete Size from the system menu */
  1171.               MM_DELETEITEM,
  1172.               MPFROM2SHORT(SC_SIZE, TRUE),
  1173.               MPFROMP(NULL));
  1174.  
  1175.    WinSendMsg(hwndMenu,              /* delete Minimize from the system menu */
  1176.               MM_DELETEITEM,
  1177.               MPFROM2SHORT(SC_MINIMIZE, TRUE),
  1178.               MPFROMP(NULL));
  1179.  
  1180.    WinSendMsg(hwndMenu,              /* delete Maximize from the system menu */
  1181.               MM_DELETEITEM,
  1182.               MPFROM2SHORT(SC_MAXIMIZE, TRUE),
  1183.               MPFROMP(NULL));
  1184.    return;
  1185. }
  1186.  
  1187. /****************************************************************\
  1188.  *  Routine for initializing the help manager
  1189.  *--------------------------------------------------------------
  1190.  *
  1191.  *  Name:    InitHelp()
  1192.  *
  1193.  *  Purpose: Initializes the IPF help facility
  1194.  *
  1195.  *  Usage:   Called once during initialization of the program
  1196.  *
  1197.  *  Method:  Initializes the HELPINIT structure and creates the help
  1198.  *           instance. If successful, the help instance is associated
  1199.  *           with the main window
  1200.  *
  1201.  *  Returns: VOID
  1202.  *
  1203. \****************************************************************/
  1204. VOID InitHelp(VOID)
  1205. {
  1206.    HELPINIT hini;
  1207.  
  1208.     /* If we return because of an error, Help will be disabled */
  1209.    fHelpEnabled = FALSE;
  1210.                              /* Initialize help init structure */
  1211.    hini.cb = sizeof(HELPINIT);
  1212.    hini.ulReturnCode = 0;
  1213.                            /* If tutorial added, add name here */
  1214.    hini.pszTutorialName = (PSZ)NULL;
  1215.  
  1216.    hini.phtHelpTable = (PHELPTABLE)MAKELONG(SORT_HELP_TABLE, 0xFFFF);
  1217.    hini.hmodHelpTableModule = 0;
  1218.    hini.hmodAccelActionBarModule = 0;
  1219.    hini.idAccelTable = 0;
  1220.    hini.idActionBar = 0;
  1221.  
  1222.    if(!WinLoadString(hab,
  1223.                      0,
  1224.                      IDS_HELPWINDOWTITLE,
  1225.                      HELPLIBRARYNAMELEN,
  1226.                      (PSZ)szWindowTitle))
  1227.    {
  1228.        MessageBox(hwndClient, IDMSG_CANNOTLOADSTRING,
  1229.                              MB_OK | MB_ERROR, FALSE);
  1230.        return;
  1231.    }
  1232.    hini.pszHelpWindowTitle = (PSZ)szWindowTitle;
  1233.  
  1234.                     /* If debugging, show panel ids, else don't */
  1235. #ifdef DEBUG
  1236.    hini.fShowPanelId = CMIC_SHOW_PANEL_ID;
  1237. #else
  1238.    hini.fShowPanelId = CMIC_HIDE_PANEL_ID;
  1239. #endif
  1240.  
  1241.    if(!WinLoadString(hab,
  1242.                      0,
  1243.                      IDS_HELPLIBRARYNAME,
  1244.                      HELPLIBRARYNAMELEN,
  1245.                      (PSZ)szLibName))
  1246.    {
  1247.        MessageBox(hwndClient, IDMSG_CANNOTLOADSTRING,
  1248.                              MB_OK | MB_ERROR, FALSE);
  1249.        return;
  1250.    }
  1251.    hini.pszHelpLibraryName = (PSZ)szLibName;
  1252.                                      /* Creating help instance */
  1253.    hwndHelpInstance = WinCreateHelpInstance(hab, &hini);
  1254.  
  1255.    if(hwndHelpInstance == 0 || hini.ulReturnCode)
  1256.    {
  1257.        MessageBox(hwndFrame, IDMSG_HELPLOADERROR, MB_OK | MB_ERROR, TRUE);
  1258.        return;
  1259.    }
  1260.                     /* Associate help instance with main frame */
  1261.    if(!WinAssociateHelpInstance(hwndHelpInstance, hwndFrame))
  1262.    {
  1263.        MessageBox(hwndFrame, IDMSG_HELPLOADERROR,
  1264.                                  MB_OK | MB_ERROR, TRUE);
  1265.        return;
  1266.    }
  1267. /* Help manager is successfully initialized so set flag to TRUE */
  1268.    fHelpEnabled = TRUE;
  1269.    return;
  1270. }                                                 /* InitHelp() */
  1271.  
  1272. /****************************************************************\
  1273.  *  Processes the Help for Help command from the menu bar
  1274.  *--------------------------------------------------------------
  1275.  *
  1276.  *  Name:    HelpHelpForHelp(mp2)
  1277.  *
  1278.  *  Purpose: Processes the WM_COMMAND message posted by the Help for
  1279.  *           Help item of the Help menu
  1280.  *
  1281.  *  Usage:   Called from MainCommand when the Help for Help menu item
  1282.  *           is selected
  1283.  *
  1284.  *  Method:  Sends an HM_DISPLAY_HELP message to the help instance so
  1285.  *           that the default Help For Help is displayed.
  1286.  *
  1287.  *  Returns: VOID
  1288.  *
  1289. \****************************************************************/
  1290. VOID HelpHelpForHelp(MPARAM mp2)
  1291. {
  1292.            /* This just displays the system help for help panel */
  1293.    if(fHelpEnabled)
  1294.        if(WinSendMsg(hwndHelpInstance, HM_DISPLAY_HELP, NULL, NULL))
  1295.            MessageBox(hwndClient,
  1296.                       IDMSG_HELPDISPLAYERROR,
  1297.                       MB_OK | MB_ERROR,
  1298.                       FALSE);
  1299.  
  1300.    /* This routine currently doesn't use the mp2 parameter but     *\
  1301.     *  it is referenced here to prevent an 'Unreferenced Parameter'
  1302.    \*  warning at compile time.                                    */
  1303.    return;
  1304. }                                          /* HelpHelpForHelp() */
  1305.  
  1306. /****************************************************************\
  1307.  *  Processes the Extended Help command from the menu bar
  1308.  *--------------------------------------------------------------
  1309.  *
  1310.  *  Name:    HelpExtended(mp2)
  1311.  *
  1312.  *  Purpose: Processes the WM_COMMAND message posted by the Extended
  1313.  *           Help item of the Help menu.
  1314.  *
  1315.  *  Usage:   Called from MainCommand when the Extended Help menu item
  1316.  *           is selected.
  1317.  *
  1318.  *  Method:  Sends an HM_EXT_HELP message to the help instance so that
  1319.  *           the default Extended Help is displayed.
  1320.  *
  1321.  *  Returns: VOID
  1322.  *
  1323. \****************************************************************/
  1324. VOID HelpExtended(MPARAM mp2)
  1325. {
  1326.            /* This just displays the system extended help panel */
  1327.    if(fHelpEnabled)
  1328.        if(WinSendMsg(hwndHelpInstance, HM_EXT_HELP, NULL, NULL))
  1329.            MessageBox(hwndClient,
  1330.                       IDMSG_HELPDISPLAYERROR,
  1331.                       MB_OK | MB_ERROR,
  1332.                       FALSE);
  1333.  
  1334.    /* This routine currently doesn't use the mp2 parameter but     *\
  1335.     *  it is referenced here to prevent an 'Unreferenced Parameter'
  1336.    \*  warning at compile time.                                    */
  1337.    return;
  1338. }                                             /* HelpExtended() */
  1339.  
  1340. /****************************************************************\
  1341.  *  Processes the Keys Help command from the menu bar
  1342.  *--------------------------------------------------------------
  1343.  *
  1344.  *  Name:    HelpKeys(mp2)
  1345.  *
  1346.  *  Purpose: Processes the WM_COMMAND message posted by the Keys Help
  1347.  *           item of the Help menu.
  1348.  *
  1349.  *  Usage:   Called from MainCommand when the Keys Help menu item is
  1350.  *           selected
  1351.  *
  1352.  *  Method:  Sends an HM_KEYS_HELP message to the help instance so that
  1353.  *           the default Keys Help is displayed.
  1354.  *
  1355.  *  Returns: VOID
  1356.  *
  1357. \****************************************************************/
  1358. VOID HelpKeys(MPARAM mp2)
  1359. {
  1360.                /* This just displays the system keys help panel */
  1361.    if(fHelpEnabled)
  1362.        if(WinSendMsg(hwndHelpInstance, HM_KEYS_HELP, NULL, NULL))
  1363.            MessageBox(hwndClient,
  1364.                       IDMSG_HELPDISPLAYERROR,
  1365.                       MB_OK | MB_ERROR,
  1366.                       FALSE);
  1367.  
  1368.    /* This routine currently doesn't use the mp2 parameter but     *\
  1369.     *  it is referenced here to prevent an 'Unreferenced Parameter'
  1370.    \*  warning at compile time.                                    */
  1371.    return;
  1372. }                                                 /* HelpKeys() */
  1373.  
  1374. /****************************************************************\
  1375.  *  Processes the Index Help command from the menu bar
  1376.  *--------------------------------------------------------------
  1377.  *
  1378.  *  Name:    HelpIndex(mp2)
  1379.  *
  1380.  *  Purpose: Processes the WM_COMMAND message posted by the Index Help
  1381.  *           item of the Help menu
  1382.  *
  1383.  *  Usage:   Called from MainCommand when the Index Help menu item
  1384.  *           is selected
  1385.  *
  1386.  *  Method:  Sends an HM_INDEX_HELP message to the help instance so
  1387.  *           that the default Index Help is displayed.
  1388.  *
  1389.  *
  1390.  *  Returns: VOID
  1391.  *
  1392. \****************************************************************/
  1393. VOID HelpIndex(MPARAM mp2)
  1394. {
  1395.               /* This just displays the system help index panel */
  1396.    if(fHelpEnabled)
  1397.        if(WinSendMsg(hwndHelpInstance, HM_HELP_INDEX, NULL, NULL))
  1398.            MessageBox(hwndClient,
  1399.                       IDMSG_HELPDISPLAYERROR,
  1400.                       MB_OK | MB_ERROR,
  1401.                       FALSE);
  1402.  
  1403.    /* This routine currently doesn't use the mp2 parameter but     *\
  1404.     *  it is referenced here to prevent an 'Unreferenced Parameter'
  1405.    \*  warning at compile time.                                    */
  1406.    return;
  1407. }                                                /* HelpIndex() */
  1408.  
  1409. /****************************************************************\
  1410.  *  Processes the About command from the Help menu
  1411.  *--------------------------------------------------------------
  1412.  *
  1413.  *  Name:    HelpAbout(mp2)
  1414.  *
  1415.  *  Purpose: Processes the WM_COMMAND message posted by the About item
  1416.  *           of the Help menu
  1417.  *
  1418.  *  Usage:   Called from MainCommand when the About menu item is selected
  1419.  *
  1420.  *  Method:  Calls WinDlgBox to display the about box dialog.
  1421.  *
  1422.  *  Returns: VOID
  1423.  *
  1424. \****************************************************************/
  1425. VOID HelpAbout(MPARAM mp2)
  1426. {
  1427.                                  /* Display the AboutBox dialog */
  1428.    WinDlgBox(HWND_DESKTOP,
  1429.                 hwndClient,
  1430.                 AboutDlgProc,
  1431.                 (HMODULE)0,
  1432.                 IDD_PRODUCTINFO,
  1433.                 NULL);
  1434.  
  1435.    /* This routine currently doesn't use the mp2 parameter but     *\
  1436.     *  it is referenced here to prevent an 'Unreferenced Parameter'
  1437.    \*  warning at compile time.                                    */
  1438.    return;
  1439. }                                                /* HelpAbout() */
  1440.  
  1441. /****************************************************************\
  1442.  *  Displays the help panel indicated
  1443.  *--------------------------------------------------------------
  1444.  *
  1445.  *  Name:    DisplayHelpPanel(idPanel)
  1446.  *
  1447.  *  Purpose: Displays the help panel whose id is given
  1448.  *
  1449.  *  Usage:   Called whenever a help panel is desired to be displayed,
  1450.  *           usually from the WM_HELP processing of the dialog boxes
  1451.  *
  1452.  *  Method:  Sends HM_DISPLAY_HELP message to the help instance
  1453.  *
  1454.  *  Returns: VOID
  1455.  *
  1456. \****************************************************************/
  1457. VOID DisplayHelpPanel(LONG idPanel)
  1458. {
  1459.    if(fHelpEnabled)
  1460.        if(WinSendMsg(hwndHelpInstance,
  1461.                      HM_DISPLAY_HELP,
  1462.                      MPFROMLONG(MAKELONG(idPanel, NULL)),
  1463.                      MPFROMSHORT(HM_RESOURCEID)))
  1464.  
  1465.            MessageBox(hwndFrame,
  1466.                       IDMSG_HELPDISPLAYERROR,
  1467.                       MB_OK | MB_ERROR,
  1468.                       TRUE);
  1469.    return;
  1470. }                                         /* DisplayHelpPanel() */
  1471.  
  1472. /****************************************************************\
  1473.  *  Destroys the help instance
  1474.  *--------------------------------------------------------------
  1475.  *
  1476.  *  Name:    DestroyHelpInstance(VOID)
  1477.  *
  1478.  *  Purpose: Destroys the help instance for the application
  1479.  *
  1480.  *  Usage:   Called after exit from message loop
  1481.  *
  1482.  *  Method:  Calls WinDestroyHelpInstance() to destroy the help instance
  1483.  *
  1484.  *  Returns: VOID
  1485.  *
  1486. \****************************************************************/
  1487. VOID DestroyHelpInstance(VOID)
  1488. {
  1489.    if(hwndHelpInstance != 0)
  1490.    {
  1491.        WinDestroyHelpInstance(hwndHelpInstance);
  1492.    }
  1493.    return;
  1494. }                                      /* DestroyHelpInstance() */
  1495.  
  1496. /****************************************************************\
  1497.  *  Message Box procedure
  1498.  *--------------------------------------------------------------
  1499.  *
  1500.  *  Name:    MessageBox(hwndOwner, nIdMsg, fsStyle, fBeep)
  1501.  *
  1502.  *  Purpose: Displays the message box with the message given in idMsg
  1503.  *           retrieved from the message table and using the style
  1504.  *           flags in fsStyle
  1505.  *
  1506.  *  Usage:   Called whenever a MessageBox is to be displayed
  1507.  *
  1508.  *  Method:  - Message string is loaded from the process' message table
  1509.  *           - Alarm beep is sounded if desired
  1510.  *           - Message box with the message is displayed
  1511.  *           - WinMessageBox return value is returned
  1512.  *
  1513.  *  Returns: Return value from WinMessageBox()
  1514.  *
  1515. \****************************************************************/
  1516. LONG MessageBox(HWND hwndOwner, LONG idMsg, LONG fsStyle, BOOL fBeep)
  1517. {
  1518.     CHAR szText[MESSAGELEN];
  1519.     LONG sRC;
  1520.  
  1521.     if(!WinLoadMessage(hab,
  1522.                       (HMODULE)NULL,
  1523.                       idMsg,
  1524.                       MESSAGELEN,
  1525.                       (PSZ)szText))
  1526.     {
  1527.         WinAlarm(HWND_DESKTOP, WA_ERROR);
  1528.         return RETURN_ERROR;
  1529.     }
  1530.  
  1531.     if(fBeep)
  1532.         WinAlarm(HWND_DESKTOP, WA_ERROR);
  1533.  
  1534.     sRC = WinMessageBox(HWND_DESKTOP,
  1535.                         hwndOwner,
  1536.                         szText,
  1537.                         (PSZ)NULL,
  1538.                         IDD_MSGBOX,
  1539.                         fsStyle);
  1540.     return sRC;
  1541. }                                      /* MessageBox() */
  1542.