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