home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / runnable / mmos2 / mmtoolkt / samples / clock / clock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  92.8 KB  |  2,390 lines

  1. /*******************************************************************************
  2.  * File Name   : CLOCK.C
  3.  *
  4.  * Description : This file contains the C source code required for the clock
  5.  *               sample program.  This sample draws a clock in a dialog
  6.  *               window and chimes for the user at every hour, quarter hour,
  7.  *               half hour, and three-quarter hour.  The user can also play
  8.  *               the next hour's chime by pushing a button.
  9.  *
  10.  * Concepts    : This program illustrates how to create and use a Memory
  11.  *               Playlist.  The sample also shows how to use MMIO API's
  12.  *               used in opening, reading, and closing files.
  13.  *
  14.  * MMPM/2 API's: List of all MMPM/2 API's that are used in this module.
  15.  *
  16.  *               mciQuerySysValue
  17.  *               mciSendCommand
  18.  *               mciGetErrorString
  19.  *               mmioOpen
  20.  *               mmioGetHeader
  21.  *               mmioRead
  22.  *               mmioClose
  23.  *
  24.  * Required
  25.  *    Files    : clock.c         Source Code.
  26.  *               clockdrw.c      Source Code.
  27.  *               clock.h         Include file.
  28.  *               clock.dlg       Dialog definition.
  29.  *               clock.rc        Resources.
  30.  *               clock.ipf       Help text.
  31.  *               makefile        Make file.
  32.  *               clock.def       Linker definition file.
  33.  *               clock.lrf       Linker response file.
  34.  *               clock.ico       Clock icon.
  35.  *               bellc.bm        Center bell bitmap.
  36.  *               belllt.bmp      Left bell bitmap.
  37.  *               bellfrlt.bmp    Far left bell bitmap.
  38.  *               bellrt.bmp      Right bell bitmap.
  39.  *               bellfrrt.bmp    Far right bell bitmap.
  40.  *               clock1.wav      Quarter hour chime file.
  41.  *               clock2.wav      Half hour chime file.
  42.  *               clock3.wav      Hour chime file.
  43.  *
  44.  * Copyright (C) IBM October 1991
  45.  ******************************************************************************/
  46.  
  47. #define  INCL_WIN                        /* Required to use Win APIs.         */
  48. #define  INCL_PM                         /* Required to use PM APIs.          */
  49. #define  INCL_GPIPRIMATIVES              /* Required to use GPI OS/2 APIs.    */
  50. #define  INCL_DOSSEMAPHORES              /* Required to use Semaphores.       */
  51. #define  INCL_DOSDATETIME                /* Required for get date time info.  */
  52. #define  INCL_DOSPROCESS                 /* Required for OS/2 process APIs.   */
  53. #define  INCL_WINHELP                    /* Required to use IPF.              */
  54. #define  INCL_DOSMEMMGR                  /* Required to use memory API's.     */
  55. #define  INCL_MMIO                       /* Required for MMIO information.    */
  56. #define  INCL_SECONDARYWINDOW            /* required for secondary window     */
  57.  
  58. #include <os2.h>
  59. #include <os2me.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <math.h>
  64. #include <bsememf.h>
  65.  
  66. #include <sw.h>
  67.  
  68. #include "clock.h"
  69.  
  70. /************************* Procedure/Function Prototypes **********************/
  71. /*
  72.  * This definition is required to use the sample program with the IBM
  73.  * C compiler.
  74.  */
  75. #pragma linkage( MainDialogProc, system )
  76. #pragma linkage( IncludeDialogProc, system )
  77. #pragma linkage( DisplayDialogProc, system )
  78. #pragma linkage( DisplayListBoxProc, system )
  79.  
  80. MRESULT EXPENTRY MainDialogProc( HWND hwnd,
  81.                                  ULONG msg,
  82.                                  MPARAM mp1,
  83.                                  MPARAM mp2 );
  84. USHORT           ShowAMessage( CHAR   *pcMessageTitle,
  85.                                USHORT usMessageId,
  86.                                ULONG  ulMessageBoxStyle );
  87. ULONG            HowBigIsTheChimeFile( USHORT usChimeFileId );
  88. VOID             InitializeDialog( VOID );
  89. VOID             TerminateDialog( VOID );
  90. VOID             CopyWaveformIntoMemory( LONG   *pulBaseAddress,
  91.                                          ULONG  ulSizeOfBuffer,
  92.                                          USHORT usChimeFile );
  93. VOID             FindAndPlayTheCorrectChime( CHIME_TIME_VALUE_T ctvChimeTime,
  94.                                              USHORT usHour );
  95. VOID             FindTheNearestChimeTimeAndPlayIt( VOID );
  96. VOID             SetupChimeFileInformation( VOID );
  97. VOID             InitializeHelp( VOID );
  98. VOID             LoadBellBitmaps( VOID );
  99. VOID             SetupPlayList( VOID );
  100. VOID             DealWithChiming( VOID );
  101. VOID             SwingTheBell( VOID );
  102. VOID             OpenPlaylistChimeDevice( ULONG  ulOpenFlags,
  103.                                          USHORT usChimeFileToPlay );
  104. BOOL             IsItChimeTime( CHIME_TIME_VALUE_T *ctvChimeTime,
  105.                                 USHORT             *pusNowHour );
  106. MRESULT EXPENTRY DrawTheHourHand( HPS     hps,
  107.                                   PPOINTL pptlCircleCenter,
  108.                                   USHORT  usHour,
  109.                                   USHORT  usMinute);
  110. VOID             DrawTheClockFace( HPS     hps,
  111.                                    PPOINTL pptlCircleCenter );
  112. MRESULT EXPENTRY DrawTheMinuteHand( HPS     hps,
  113.                                     PPOINTL pptlCircleCenter,
  114.                                     USHORT  usMinute);
  115. VOID             UpdateTheClock( VOID);
  116. /*************** End of Procedure/Function Prototypes *************************/
  117.  
  118.  
  119. /****************************** Global Variables. *****************************/
  120.  
  121. /*
  122.  * This double array holds the playlists that will be used to play the chimes
  123.  * for the clock.  Each array has four fields within the structure, one for
  124.  * the playlist command( 32 bit value ) and three operands( 32 bit values ).
  125.  * The DATA_OPERATION's first operand will contain the address to the
  126.  * respective waveform buffers.  Once the playlist has been played, the
  127.  * CHIME_PLAYING_HAS_STOPPED message will be sent so that the application
  128.  * knows that the audio is finished.
  129.  *
  130.  * The clock will have a unique chime for each quarter hour.
  131.  * There are three chime files that are used in different combinations to
  132.  * create all of the chimes used for the clock.  These three files are
  133.  * clock1.wav, clock2.wav, and clock3.wav.
  134.  *
  135.  * The first playlist will play quarter hour chime.  This is simply
  136.  * clock1.wav.
  137.  *
  138.  * The second playlist will play the half hour chime.  This
  139.  * consists of clock1.wav + clock2.wav.
  140.  *
  141.  * The third playlist will play the three quarter hour chime.  This consists
  142.  * of clock1.wav + clock2.wav + clock1.wav.
  143.  *
  144.  * The fouth playlist plays the hour chime.  This consists of clock1.wav +
  145.  * clock2.wav + clock1.wav + clock2.wav + (HOUR * clock3.wav)
  146.  * The Number of loops to perform for the hour value
  147.  * is kept in the high order 16 bits of the first operand.  This will be set
  148.  * in a later procedure when the hour of the chime time is known.
  149.  */
  150. PLAY_LIST_STRUCTURE_T apltPlayList[ NUMBER_OF_PLAYLISTS ]
  151.                                   [ NUMBER_OF_COMMANDS ] =
  152. {
  153.    /*
  154.     * Quarter Hour Chime.
  155.     */
  156.    {
  157.       DATA_OPERATION,    0, 0, 0,      /* Chime file 1.                       */
  158.       MESSAGE_OPERATION, 0, CHIME_PLAYING_HAS_STOPPED, 0,
  159.       EXIT_OPERATION,    0, 0, 0
  160.    },
  161.  
  162.    /*
  163.     * Half Hour Chime.
  164.     */
  165.    {
  166.       DATA_OPERATION,    0, 0, 0,      /* Chime file 1.                       */
  167.       DATA_OPERATION,    0, 0, 0,      /* Chime file 2.                       */
  168.       MESSAGE_OPERATION, 0, CHIME_PLAYING_HAS_STOPPED, 0,
  169.       EXIT_OPERATION,    0, 0, 0
  170.    },
  171.  
  172.    /*
  173.     * Three Quarter Hour Chime.
  174.     */
  175.    {
  176.       DATA_OPERATION,    0, 0, 0,      /* Chime file 1.                       */
  177.       DATA_OPERATION,    0, 0, 0,      /* Chime file 2.                       */
  178.       DATA_OPERATION,    0, 0, 0,      /* Chime file 1.                       */
  179.       MESSAGE_OPERATION, 0, CHIME_PLAYING_HAS_STOPPED, 0,
  180.       EXIT_OPERATION,    0, 0, 0
  181.    },
  182.  
  183.    /*
  184.     * Hour Chime.
  185.     */
  186.    {
  187.       DATA_OPERATION,    0, 0, 0,      /* Chime file 1.             < Line 0 >*/
  188.       DATA_OPERATION,    0, 0, 0,      /* Chime file 2.             < Line 1 >*/
  189.       DATA_OPERATION,    0, 0, 0,      /* Chime file 1.             < Line 2 >*/
  190.       DATA_OPERATION,    0, 0, 0,      /* Chime file 2.             < Line 3 >*/
  191.       LOOP_OPERATION,    0, 7, 0,      /* Which line to end on      < Line 4 >*/
  192.       DATA_OPERATION,    0, 0, 0,      /* Chime file 3.             < Line 5 >*/
  193.       BRANCH_OPERATION,  0, 4, 0,      /* Branch back to Loop       < Line 6 >*/
  194.       MESSAGE_OPERATION, 0, CHIME_PLAYING_HAS_STOPPED, 0,
  195.       EXIT_OPERATION,    0, 0, 0
  196.    }
  197. };
  198.  
  199. /*
  200.  * This array holds the ID's that are used to retrieve the strings from
  201.  * the string table and placed into the global double array acStringBuffer.
  202.  * The defines that are used for the string table is used to create the
  203.  * index into the global buffer.  Since the string table starts at 1 and
  204.  * the global buffer starts at 0, the index is decremented by 1 when used.
  205.  * This means when the acStringBuffer is accessed after the strings have
  206.  * been loaded into the buffer, all indexes will be n-1, i.e.,
  207.  * IDS_HELP_WINDOW_TITLE - 1, to get the proper string.  This is done
  208.  * simply to keep down the number of #defines.
  209.  */
  210. USHORT ausMessageId[] = { IDS_MAIN_WINDOW_TITLE,
  211.                           IDS_HELP_CREATION_ERROR,
  212.                           IDS_HELP_LIBRARY_FILE,
  213.                           IDS_HELP_WINDOW_TITLE,
  214.                           IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT,
  215.                           IDS_SWING_THREAD_NOT_STARTED,
  216.                           IDS_CHIME_FILE_A,
  217.                           IDS_CHIME_FILE_B,
  218.                           IDS_CHIME_FILE_C };
  219.  
  220. /*
  221.  * This shows the order in which the bell bitmaps will be drawn so that the
  222.  * visible 'ringing' of the bell can be seen.  The bell will start at the
  223.  * center position, move to the right, move back to center, as it moves to the
  224.  * left, and finally back to the center position where it started.
  225.  */
  226. USHORT ausBellSwingOrder[ NUMBER_OF_BELLS_IN_A_SWING ] =
  227.      {
  228.         IX_CENTER_BELL,
  229.         IX_RIGHT_BELL,
  230.         IX_FAR_RIGHT_BELL,
  231.         IX_RIGHT_BELL,
  232.         IX_CENTER_BELL,
  233.         IX_LEFT_BELL,
  234.         IX_FAR_LEFT_BELL,
  235.         IX_LEFT_BELL,
  236.      };
  237.  
  238. /*
  239.  * This array holds program required text that is pulled from the string
  240.  * table.
  241.  */
  242. CHAR  acStringBuffer[ NUMBER_OF_PROGRAM_STRINGS ][ STRING_SIZE ];
  243.  
  244. BYTE  bThreadStackSize[ THREAD_STACK_SIZE ];         /* Thread stack size.    */
  245. HWND  hwndHelpInstance;                              /* Handle to Help window.*/
  246. HAB   hab;                                           /* Handle to anchor blk. */
  247. HPS   hps;                                           /* Handle to pres space. */
  248. QMSG  qmsg;                                          /* Message queue.        */
  249. HMQ   hmq;                                           /* Handle to the msg q.  */
  250. HWND  hwndMainDialogBox;                             /* Handle to the dlg win.*/
  251. HWND  hwndPlayChimePB;                               /* Handle to the Play PB */
  252. HWND  hwndFrame;                                     /* Handle to Frame win.  */
  253. RECTL rctClockFaceRectangle;                         /* Area of the clk face. */
  254. RECTL rctBitMapRectangle;                            /* Area of the bitmap.   */
  255. ULONG ulThreadId   = 1;                              /* Swing thread id.      */
  256. HEV                hevContinueToSwingTheBell;        /* When to swing bell.   */
  257. STOP_GO_READY_T    yngContinueToSwingTheBell = STOP, /* When to swing bell.   */
  258.                    yngAreChimeFilesLoaded    = READY;/* Have files been loaded*/
  259. MCI_OPEN_PARMS     mciOpenParameters;                /* Open structure.       */
  260. HELPINIT           hmiHelpStructure;                 /* Help init. structure. */
  261. HBITMAP ahbmBellBitMaps[ NUMBER_OF_BELL_BITMAPS ],   /* Holds the handles to  */
  262.         hbmBitmapToShow;                             /* the bell bitmaps.     */
  263. POINTL  ptlBitMapPoint;                              /* Place Bitmaps.        */
  264. BOOL    fThreadIsAlive              = FALSE,         /* Has thread started.   */
  265.         fPassed                     = FALSE;         /* device  ownership     */
  266. MMAUDIOHEADER mmAudioHeader;                         /* Contains info for SET */
  267. BOOL    fInitHeader = TRUE;                          /* Should we init header?*/
  268. USHORT  usLastHour   = 99, /* The last hour when in the Draw Hands proc.      */
  269.         usLastMinute = 0,  /* The last minute when in the Draw Minute proc.   */
  270.         usHour       = 25, /* Contains current hour given by UpdateTheClock.  */
  271.         usMinute     = 61; /* Contains current minute given by UpdateTheCock. */
  272.                            /* The 3 in the usHour is required so that the     */
  273.                            /* hands do not start in the same overlapping      */
  274.                            /* position.                                       */
  275.  
  276. /************************** End of Globle Variables ***************************/
  277.  
  278.  
  279. /*******************************************************************************
  280.  * Name         : main
  281.  *
  282.  * Description  : This function calls the InitializeDialog and TerminateDialog
  283.  *                procedures.  The message loop is also in this routine.
  284.  *
  285.  * Concepts     : None.
  286.  *
  287.  * MMPM/2 API's : None.
  288.  *
  289.  * Parameters   : None.
  290.  *
  291.  * Return       : TRUE is returned to the operating system.
  292.  *
  293.  ******************************************************************************/
  294. INT main( VOID )
  295. {
  296.  
  297.    InitializeDialog();
  298.  
  299.    while ( WinGetMsg( hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0) )
  300.       WinDispatchMsg( hab, (PQMSG) &qmsg );
  301.  
  302.    TerminateDialog();
  303.  
  304.    return( TRUE );
  305.  
  306. } /* End of main */
  307.  
  308.  
  309. /*******************************************************************************
  310.  * Name         : InitializeDialog
  311.  *
  312.  * Description  : This function performs the necessary initializations and
  313.  *                setups that are required to show/run a dialog box as a
  314.  *                main window.  The message queue will be created, as well as
  315.  *                the dialog box.  Finally the message passing loop will be
  316.  *                started to give messages to the dialog box.
  317.  *
  318.  * Concepts     : None.
  319.  *
  320.  * MMPM/2 API's : None.
  321.  *
  322.  * Parameters   : None.
  323.  *
  324.  * Return       : None.
  325.  *
  326.  ******************************************************************************/
  327. VOID InitializeDialog( VOID )
  328. {
  329.  
  330.    USHORT   usCounter  = 0;              /* Generic counter.                  */
  331.    ULONG    ulThreadId = 1;              /* Thread swing id.                  */
  332.  
  333.    DosCreateEventSem(
  334.       (PSZ) NULL,                         /* No semaphore Name. Do not share. */
  335.       &hevContinueToSwingTheBell,         /* Semaphore Handle.                */
  336.       (ULONG) NULL,                       /* Creation attributes.             */
  337.       (BOOL32) FALSE );                   /* State of semaphore.              */
  338.  
  339.    /*
  340.     * Create the thread that will animate the bell bitmaps.
  341.     */
  342.    if ( DosCreateThread(
  343.            &ulThreadId,                   /* Thread id.                       */
  344.            (PFNTHREAD) SwingTheBell,      /* Routine to run in the thread.    */
  345.            (ULONG) NULL,                  /* What parameters to pass.         */
  346.            (ULONG) 0,                     /* Start the thread.                */
  347.            (ULONG) (bThreadStackSize +
  348.                        sizeof( bThreadStackSize )) )  /* Thread stack size.   */
  349.         != 0 )
  350.    {
  351.       fThreadIsAlive = FALSE;
  352.    }
  353.    else
  354.    {
  355.       fThreadIsAlive = TRUE;
  356.    }
  357.  
  358.    /*
  359.     * Load the various strings that are required by the program.
  360.     */
  361.    for( usCounter=0; usCounter<NUMBER_OF_PROGRAM_STRINGS; usCounter++)
  362.    {
  363.       WinLoadString(
  364.          hab,                                  /* HAB for this dialog box.    */
  365.          (HMODULE) NULL,                       /* Get string from .exe file.  */
  366.          ausMessageId[ usCounter ],            /* Which string to get.        */
  367.          (SHORT) STRING_SIZE,                  /* The size of the buffer.     */
  368.          (PSZ) &acStringBuffer[ usCounter ] ); /* Buffer to place string.     */
  369.    }
  370.  
  371.    /*
  372.     * Setup and initialize the dialog window.
  373.     */
  374.    hab = WinInitialize( (USHORT) 0 );
  375.  
  376.    hmq = WinCreateMsgQueue( hab, 0 );
  377.  
  378.    hwndFrame =                  /* Returns the handle to the frame.           */
  379.       WinLoadSecondaryWindow(
  380.          HWND_DESKTOP,          /* Parent of the dialog box.                  */
  381.          HWND_DESKTOP,          /* Owner of the dialog box.                   */
  382.          (PFNWP) MainDialogProc,/* 'Window' procedure for the dialog box.     */
  383.          (HMODULE) NULL,        /* Where is the dialog.  Null is EXE file..   */
  384.          ID_CLOCK_DIALOG_BOX,   /* Dialog ID.                                 */
  385.          (PVOID) NULL );        /* Creation Parameters for the dialog.        */
  386.  
  387.    /*
  388.     * Retrieve the handle to the dialog box by specifying the QS_DIALOG flag.
  389.     */
  390.    hwndMainDialogBox = WinQuerySecondaryHWND(hwndFrame, QS_DIALOG);
  391.  
  392.    /*
  393.     * Set the name of the sample program in the title bar of the dialog
  394.     * window.  This is done so that the program name will show up in
  395.     * the Task List window, via the FCF_TASKLIST flag AND will NOT
  396.     * show the .exe file name of the program.  If the FCF_TASKLIST flag
  397.     * is used the .exe file name AND the dialog title will show up
  398.     * in the title bar.  This is not wanted.
  399.     */
  400.    WinSetWindowText(hwndFrame, acStringBuffer[IDS_MAIN_WINDOW_TITLE-1]);
  401.  
  402.    /*
  403.     * Initialize the help structure and associate the help instance to this
  404.     * dialog via it's handle to anchor block.
  405.     */
  406.    InitializeHelp();
  407.  
  408. } /* End of InitializeDialog */
  409.  
  410.  
  411. /*******************************************************************************
  412.  * Name         : TerminateDialog
  413.  *
  414.  * Description  : This routine is called after the message dispatch loop has
  415.  *                ended because of a WM_QUIT message.  The code will destroy
  416.  *                the help instance, messages queue, window, and bitmaps.
  417.  *
  418.  * Concepts     : None.
  419.  *
  420.  * MMPM/2 API's : None.
  421.  *
  422.  * Parameters   : None.
  423.  *
  424.  * Return       : None.
  425.  *
  426.  ******************************************************************************/
  427. VOID TerminateDialog( VOID )
  428. {
  429.    USHORT usCounter = 0;                        /* Generic counter.           */
  430.  
  431.    /*
  432.     * Destroy the Help Instance for this dialog window.
  433.     */
  434.    if ( hwndHelpInstance != (HWND) NULL )
  435.    {
  436.       WinDestroyHelpInstance( hwndHelpInstance );
  437.    }
  438.  
  439.    WinDestroySecondaryWindow( hwndFrame);
  440.    WinDestroyMsgQueue( hmq );
  441.    WinTerminate( hab );
  442.  
  443.    /*
  444.     * Get rid of the clock bitmaps.
  445.     */
  446.    for( usCounter=0; usCounter<NUMBER_OF_BELL_BITMAPS; usCounter++)
  447.    {
  448.       GpiDeleteBitmap( ahbmBellBitMaps[ usCounter ] );
  449.    }
  450.  
  451.    /*
  452.     * Get rid of the space that was malloc to hold the clock waveform
  453.     * files.
  454.     */
  455.    for( usCounter=0; usCounter<NUMBER_OF_AUDIO_CHIMES; usCounter++ )
  456.    {
  457.       free( (VOID *) apltPlayList[ usCounter ][ 0 ].ulOperandOne );
  458.    }
  459.  
  460. }  /* End of TerminateDialog */
  461.  
  462.  
  463. /*******************************************************************************
  464.  * Name        : MainDialogProc
  465.  *
  466.  * Description : This function controls the main dialog box.  It will handle
  467.  *               received messages such as pushbutton notifications, timing
  468.  *               events, etc.
  469.  *
  470.  *               The following messages are handled specifically by this
  471.  *               routine.
  472.  *
  473.  *                  WM_INITDLG
  474.  *                  WM_CLOSE
  475.  *                  WM_PAINT
  476.  *                  WM_TIMER
  477.  *                  WM_HELP
  478.  *                  WM_COMMAND
  479.  *                  WM_MINMAXFRAME
  480.  *                  MM_MCINOTIFY
  481.  *
  482.  * Concepts    : The MM_MCINOTIFY message is used to indicate when to turn
  483.  *               off the swinging of the Bells when the playlist is finished
  484.  *               processing.
  485.  *
  486.  *               In order to update the clock hands when the time has changed,
  487.  *               an OS/2 timer is used to call this window procedure when a
  488.  *               period of time has passed.  When the WM_TIMER message is
  489.  *               received the current time will be compared with the last time
  490.  *               that the clock hands were updated.  If the time is different
  491.  *               then the clock hands will be drawn in positions reflecting
  492.  *               the new time.
  493.  *
  494.  *               The WM_TIMER message will cause the UpdateTheClock routine to
  495.  *               be called which will check the time values and if necessary
  496.  *               invalidate the clock face.  This will cause the clock hands
  497.  *               to be drawn via the WM_PAINT message.
  498.  *
  499.  *               Another routine DealWithChiming is also called to see if it
  500.  *               is time to chime and if the Closed Caption flag is set in
  501.  *               the system.  If it is a Chime Time then the audio chime for
  502.  *               the particular time will be played and if the Closed Caption
  503.  *               flag is set the Bell bitmap will be swung back and forth to
  504.  *               indicate that a chime time has been reached.
  505.  *
  506.  *               Below is a diagram of the the routines called by
  507.  *               DealWithChiming.
  508.  *
  509.  *                                      DealWithChiming()
  510.  *                                              │
  511.  *                                              │
  512.  *                               FindAndPlayTheCorrectChime(...)
  513.  *                                              │
  514.  *                             ┌────────────────┴────────┐
  515.  *                     IsItChimeTime(...)                │
  516.  *                                                       │
  517.  *                                            OpenPlaylistChimeDevice(...)
  518.  *
  519.  *
  520.  * MMPM/2 API's : mciSendCommand
  521.  *
  522.  *
  523.  * Parameters   : hwnd - Handle for the Main dialog box.
  524.  *                msg  - Message received by the dialog box.
  525.  *                mp1  - Parameter 1 for the just recieved message.
  526.  *                mp2  - Parameter 2 for the just recieved message.
  527.  *
  528.  * Return       :
  529.  *
  530.  *
  531.  ******************************************************************************/
  532. MRESULT EXPENTRY MainDialogProc( HWND   hwnd,
  533.                                  ULONG  msg,
  534.                                  MPARAM mp1,
  535.                                  MPARAM mp2 )
  536. {
  537.    static PSWP pswpWindowActionMP    = (PSWP) NULL; /* State of window.       */
  538.    static BOOL fIsTheWindowMinimized = FALSE;   /* Flag for the window state. */
  539.    MCI_GENERIC_PARMS mciGenericParms;/* generic parms for MCI_ACQUIRE         */
  540.    HPOINTER hpProgramIcon;          /* Pointer to the program icon.           */
  541.    POINTL   ptlCircleCenter;        /* Point of the center of the circle.     */
  542.    USHORT   usReceivedMessage,      /* MCI message that was received.         */
  543.             usNotifyCode,           /* Notify code from the MCI Notify msg.   */
  544.             usMCIUserParameter;     /* User parameter.                        */
  545.    ULONG    ulBorderXSize,          /* Size of X border.                      */
  546.             ulBorderYSize,          /* Size of Y border.                      */
  547.             ulPostCount;            /* Count of number of Posts for the Sem.  */
  548.    RECTL    rctWindowRectangle;     /* The area rectangle of the window.      */
  549.    DWORD    dwError;                /* RC for acquire device.                 */
  550.  
  551.    switch( msg )
  552.    {
  553.  
  554.       /*
  555.        * The WM_INITDLG is called when the dialog is first being created
  556.        * by the system.
  557.        */
  558.       case WM_INITDLG :
  559.          /*
  560.           * Since the startup of this program can take more than a second,
  561.           * the hourglass icon will be shown to the user.  The main reason
  562.           * for the delay in startup is the chime files that are read in
  563.           * when the program is started.
  564.           */
  565.          WinSetPointer(
  566.             HWND_DESKTOP,        /* Desktop window handle.                    */
  567.             WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  568.                HWND_DESKTOP,     /* Desktop window handle.                    */
  569.                SPTR_WAIT,        /* The Hourglass icon.                       */
  570.                FALSE ) );        /* Return the system pointer's handle.       */
  571.  
  572.          /*
  573.           * Get the sample programs minimize icon.
  574.           */
  575.          hpProgramIcon =
  576.             WinLoadPointer(
  577.                HWND_DESKTOP,
  578.                (HMODULE) NULL, /* Where the resource is kept. (Exe file)      */
  579.                ID_ICON );      /* Which icon to use.                          */
  580.  
  581.          WinDefSecondaryWindowProc(
  582.             hwnd,              /* Dialog window handle.                       */
  583.             WM_SETICON,        /* Message to the dialog.  Set it's icon.      */
  584.             (MPARAM) hpProgramIcon,
  585.             (MPARAM) 0 );      /* mp2 no value.                               */
  586.  
  587.          /*
  588.           * Set up the position of the bitmaps.  The rctBitMapRectangle is
  589.           * used to invalidate the region of the Presentation Space that
  590.           * contains the Bell bitmap.  The ptlBitMapPoint is used to place
  591.           * the bitmaps.
  592.           */
  593.          WinQueryWindowRect(
  594.             hwnd,                            /* Handle to the window.         */
  595.             (PRECTL) &rctWindowRectangle );  /* Size of the window.           */
  596.  
  597.          rctBitMapRectangle.xLeft   =
  598.             rctWindowRectangle.xRight  - BELL_BITMAP_X_SIZE - 25;
  599.          rctBitMapRectangle.yBottom =
  600.             rctWindowRectangle.yBottom + Y_BITMAP_POSITION;
  601.          rctBitMapRectangle.xRight  =
  602.             rctBitMapRectangle.xLeft   + BELL_BITMAP_X_SIZE;
  603.          rctBitMapRectangle.yTop    =
  604.             rctWindowRectangle.yBottom + BELL_BITMAP_Y_SIZE + 10;
  605.  
  606.          ptlBitMapPoint.x = rctBitMapRectangle.xLeft;
  607.          ptlBitMapPoint.y = rctBitMapRectangle.yBottom;
  608.  
  609.  
  610.          /*
  611.           * Get the presentation space for the window so that the bell
  612.           * bitmaps can be loaded.  Once the bitmaps have been loaded the
  613.           * presentation space can be released.
  614.           */
  615.          hps = WinGetPS( hwnd );
  616.  
  617.          LoadBellBitmaps();
  618.  
  619.          WinReleasePS( hps );
  620.  
  621.          /*
  622.           * Load the playlist waveform files into memory and set the
  623.           * DATA_OPERATION's first operand to the address of the buffer
  624.           * containing the files.
  625.           */
  626.          SetupPlayList();
  627.  
  628.          /*
  629.           * Place the clock hands in position based on the time.
  630.           */
  631.          UpdateTheClock();
  632.  
  633.          /*
  634.           * Start the timer so that we know to check to see when the time
  635.           * has changed so that we can move the clock hands.
  636.           */
  637.          WinStartTimer(
  638.             hab,                    /* Anchor Block for the window.           */
  639.             hwnd,                   /* Handle for the window.                 */
  640.             CLOCK_TIMER_ID,         /* Id for this particular Timer.          */
  641.             CLOCK_TIMER_TIMEOUT );  /* Number of seconds that the timer waits.*/
  642.  
  643.          /*
  644.           * Now that the startup processing is over, remove the Hourglass
  645.           * icon and replace it with the normal arrow icon.
  646.           */
  647.          WinSetPointer(
  648.             HWND_DESKTOP,        /* Desktop window handle.                    */
  649.             WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  650.                HWND_DESKTOP,     /* Desktop window handle.                    */
  651.                SPTR_ARROW,       /* The Arrow icon.                           */
  652.                FALSE ) );        /* Return the system pointer's handle.       */
  653.  
  654.          hwndPlayChimePB =
  655.             WinWindowFromID(
  656.                hwnd,                /* Handle to the window.                  */
  657.                ID_PLAY_CHIME_PB );  /* Id of the control.                     */
  658.  
  659.          return( 0 );
  660.  
  661.       case WM_CLOSE :
  662.          if ( mciOpenParameters.wDeviceID > 0 )
  663.          {
  664.             mciSendCommand(
  665.                mciOpenParameters.wDeviceID,  /* Device to play the chimes.    */
  666.                MCI_CLOSE,                    /* MCI message.                  */
  667.                MCI_WAIT,                     /* Flags for the MCI message.    */
  668.                (DWORD) NULL,                 /* Parameters for the message.   */
  669.                (DWORD) NULL );               /* Parameter for notify message. */
  670.          }
  671.  
  672.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  673.  
  674.       case WM_TIMER :
  675.          /*
  676.           * A period of time has passed so check the time and see if the
  677.           * clock hands need to be repositioned.  Also see if Chiming should
  678.           * take place.
  679.           */
  680.          UpdateTheClock();
  681.          DealWithChiming();
  682.          return( 0 );
  683.  
  684.       case WM_HELP :
  685.          /*
  686.           * The dialog window has recieved a request for help from the user,
  687.           * i.e., the Help pushbutton was pressed.  Send the HM_DISPLAY_HELP
  688.           * message to the Help Instance with the IPF resource identifier
  689.           * for the correct HM panel.  This will show the help panel for this
  690.           * sample program.
  691.           */
  692.          WinSendMsg(
  693.             hwndHelpInstance,
  694.             HM_DISPLAY_HELP,
  695.             MPFROMSHORT( 1 ),
  696.             MPFROMSHORT( HM_RESOURCEID ) );
  697.          return( 0 );
  698.  
  699.       case MM_MCINOTIFY :
  700.          /*
  701.           * A MCI Notify message has been recieved as a result of an MCI_PLAY.
  702.           * Process as required.
  703.           */
  704.          usNotifyCode       = SHORT1FROMMP( mp1 );
  705.          usReceivedMessage  = SHORT2FROMMP( mp2 );
  706.          usMCIUserParameter = SHORT2FROMMP( mp1 );
  707.  
  708.          /*
  709.           * If for some reason the Notify code is not successful then the
  710.           * file will be closed OR if the User parameter indicates that the
  711.           * Playlist sent a message indicating that the file has been played.
  712.           */
  713.          if ( ( usNotifyCode != MCI_NOTIFY_SUPERSEDED &&
  714.                 usNotifyCode != MCI_NOTIFY_ABORTED &&
  715.                 usNotifyCode != MCI_NOTIFY_SUCCESSFUL ) ||
  716.               usNotifyCode == MCI_NOTIFY_SUPERSEDED ||
  717.               usNotifyCode == MCI_NOTIFY_ABORTED ||
  718.               (usNotifyCode == MCI_NOTIFY_SUCCESSFUL &&
  719.                  usReceivedMessage == MCI_PLAY ) ||
  720.               usMCIUserParameter == CHIME_PLAYING_HAS_STOPPED )
  721.          {
  722.             /*
  723.              * Turn off the swinging of the visual bells and clean up the
  724.              * audio device.
  725.              */
  726.             yngContinueToSwingTheBell = STOP;
  727.             DosResetEventSem(
  728.                hevContinueToSwingTheBell,    /* Semaphore Handle.             */
  729.                &ulPostCount );               /* How many times Posted.        */
  730.  
  731.             mciSendCommand(
  732.                mciOpenParameters.wDeviceID,  /* Device to play the chimes.    */
  733.                MCI_CLOSE,                    /* MCI message.                  */
  734.                MCI_WAIT,                     /* Flags for the MCI message.    */
  735.                (DWORD) NULL,                 /* Parameters for the message.   */
  736.                (DWORD) NULL );               /* Parameter for notify message. */
  737.  
  738.             WinEnableWindow(
  739.                hwndPlayChimePB,     /* Handle to the Play Chime push button.  */
  740.                TRUE );              /* Enable the push button.                */
  741.  
  742.          }
  743.  
  744.          return( 0 );
  745.  
  746.       case WM_COMMAND :
  747.          /*
  748.           * To get which pushbutton was pressed the SHORT1FROMMP macro
  749.           * is used.
  750.           */
  751.          switch( SHORT1FROMMP( mp1 ) )
  752.          {
  753.             case ID_PLAY_CHIME_PB :
  754.                /*
  755.                 * Since the user want to play the next hour chime, the next
  756.                 * procedure call will get the current hour and increase it
  757.                 * to the next hour.  However this will only occur if all of
  758.                 * the chime files have been loaded correctly.
  759.                 */
  760.                if ( yngAreChimeFilesLoaded == STOP )
  761.                {
  762.                   ShowAMessage(
  763.                      acStringBuffer[
  764.                         IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  765.                      IDS_CHIME_FILE_ERROR,
  766.                      MB_CANCEL | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  767.                         MB_MOVEABLE );
  768.                }
  769.                else
  770.                {
  771.                   FindTheNearestChimeTimeAndPlayIt();
  772.                }
  773.  
  774.                return( 0 );
  775.  
  776.             case DID_CANCEL:                      /* Handle ESC key */
  777.             case ID_CANCEL_PB :
  778.                WinSendMsg(
  779.                   hwnd,
  780.                   WM_CLOSE,
  781.                   (MPARAM) NULL,
  782.                   (MPARAM) NULL );
  783.  
  784.                return( 0 );
  785.  
  786.          }  /* End of Command Switch */
  787.  
  788.          return( 0 );
  789.  
  790.       case WM_MINMAXFRAME :
  791.  
  792.          hwndPlayChimePB =
  793.             WinWindowFromID(
  794.                hwnd,                /* Handle of this dialog window.          */
  795.                ID_PLAY_CHIME_PB );  /* ID of the left most PM control.        */
  796.  
  797.          pswpWindowActionMP = (PSWP) LONGFROMMP( mp1 );
  798.  
  799.          if ( pswpWindowActionMP->fl & SWP_MINIMIZE )
  800.          {
  801.             fIsTheWindowMinimized = TRUE;
  802.             WinSetWindowPos(
  803.                hwndPlayChimePB,        /* Handle to the control.              */
  804.                HWND_BOTTOM,            /* Place the control behind siblings.  */
  805.                X_PLAY_CHIME_POSITION,  /* X position of the control.          */
  806.                Y_PLAY_CHIME_POSITION,  /* Y position of the control.          */
  807.                X_SIZE_OF_THE_BUTTONS,  /* X size of the control.              */
  808.                Y_SIZE_OF_THE_BUTTONS,  /* Y size of the control.              */
  809.                SWP_HIDE | SWP_ACTIVATE ); /* Positioning options.             */
  810.          }
  811.          else
  812.          {
  813.             fIsTheWindowMinimized = FALSE;
  814.             WinSetWindowPos(
  815.                hwndPlayChimePB,        /* Handle to the control.              */
  816.                HWND_BOTTOM,            /* Place the control behind siblings.  */
  817.                X_PLAY_CHIME_POSITION,  /* X position of the control.          */
  818.                Y_PLAY_CHIME_POSITION,  /* Y position of the control.          */
  819.                X_SIZE_OF_THE_BUTTONS,  /* X size of the control.              */
  820.                Y_SIZE_OF_THE_BUTTONS,  /* Y size of the control.              */
  821.                SWP_SHOW | SWP_ACTIVATE ); /* Positioning options.             */
  822.          }
  823.  
  824.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  825.  
  826.       case WM_PAINT :
  827.       {
  828.          if ( fIsTheWindowMinimized == FALSE )
  829.          {
  830.             hps =
  831.                WinBeginPaint(
  832.                   hwnd,             /* Window that wants PS.                  */
  833.                   (HPS) NULL,       /* Get a Cache Pres. Space.               */
  834.                   (PRECTL) NULL );
  835.  
  836.             GpiSetLineWidth(
  837.                hps,
  838.                LINEWIDTH_NORMAL * 3 );
  839.  
  840.             /*
  841.              * The bell is ready to be swung if needed and the thread that will
  842.              * swing the bell is running so allow the bell to go.
  843.              */
  844.             if ( yngContinueToSwingTheBell == READY &&
  845.                   fThreadIsAlive == TRUE )
  846.             {
  847.                yngContinueToSwingTheBell = GO;
  848.                DosPostEventSem(
  849.                   hevContinueToSwingTheBell );  /* Semaphore Handle.          */
  850.             }
  851.             else
  852.             if ( fThreadIsAlive == FALSE )
  853.             {
  854.                ShowAMessage(
  855.                   acStringBuffer[
  856.                      IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT -  1 ],
  857.                   IDS_SWING_THREAD_NOT_STARTED,   /* ID of the message.       */
  858.                   MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  859.                      MB_MOVEABLE );                /* Message box style.      */
  860.             }
  861.  
  862.             /*
  863.              * Get the size of the window.
  864.              */
  865.             WinQueryWindowRect(
  866.                hwnd,                            /* Handle to the window.      */
  867.                (PRECTL) &rctWindowRectangle );  /* Size of the window.        */
  868.  
  869.             /*
  870.              * Fill the presentation space.
  871.              */
  872.             WinFillRect(
  873.                hps,                             /* Presentation Space.        */
  874.                (PRECTL) &rctWindowRectangle,    /* Size of the window.        */
  875.                SYSCLR_FIELDBACKGROUND);         /* The background color.      */
  876.  
  877.             /*
  878.              * Calculate the center of the window.
  879.              */
  880.             ptlCircleCenter.x =
  881.                ( ( rctWindowRectangle.xRight - rctWindowRectangle.xLeft ) / 2 );
  882.             ptlCircleCenter.y =
  883.                ( ( rctWindowRectangle.yTop - Y_ADJUSTMENT_SIZE_OF_BUTTONS -
  884.                   rctWindowRectangle.yBottom ) / 2 );
  885.  
  886.             /*
  887.              * Calculate the rectangular area of the clock face by using the
  888.              * center point of the window and the macros that discribe its
  889.              * size.  The values calculated below are used to invalidate the
  890.              * portions of the window so that the clock hands can be re-drawn
  891.              * when the time changes.  The area that is invalidated is a
  892.              * square that is the two minute hand lengths from side to side.
  893.              */
  894.             rctClockFaceRectangle.xLeft   =
  895.                ptlCircleCenter.x - (LONG)
  896.                   (MARKER_POSITION_FROM_CENTER - 25 );
  897.             rctClockFaceRectangle.yBottom =
  898.                ptlCircleCenter.y - (LONG)
  899.                   (MARKER_POSITION_FROM_CENTER - 25 );
  900.  
  901.             rctClockFaceRectangle.xRight  =
  902.                ptlCircleCenter.x + (LONG)
  903.                   (MARKER_POSITION_FROM_CENTER - 25 );
  904.             rctClockFaceRectangle.yTop    =
  905.                ptlCircleCenter.y + (LONG)
  906.                   (MARKER_POSITION_FROM_CENTER - 25 );
  907.  
  908.             /*
  909.              * Draw the clock face, the hour, minute hands, and center circle.
  910.              *   Order is important when drawing the hour and minute hands.
  911.              *   Since the minute hand is longer than the hour, the minute
  912.              *   hand should be drawn first followed by the hour hand.
  913.              */
  914.             DrawTheClockFace(
  915.                hps,                 /* Presentation Space.                    */
  916.                &ptlCircleCenter );  /* Point to the center of the clock face. */
  917.  
  918.             DrawTheMinuteHand(
  919.                hps,                 /* Presentation Space.                    */
  920.                &ptlCircleCenter,    /* Point to the center of the clock face. */
  921.                usMinute);           /* Minute value for the clock hand.       */
  922.  
  923.             DrawTheHourHand(
  924.                hps,                 /* Presentation Space.                    */
  925.                &ptlCircleCenter,    /* Point to the center of the clock face. */
  926.                usHour,              /* Hour value for the clock hand.         */
  927.                usMinute);           /* Minute value for the clock hand.       */
  928.  
  929.             DrawClockCircles(
  930.                hps,                 /* Handle to the Presentation space.      */
  931.                &ptlCircleCenter,    /* Position to place the Marker.          */
  932.                CLOCK_HAND_COLOR,    /* Color to make the end dot.             */
  933.                (USHORT) 5 );        /* Size of the time marker circle.        */
  934.  
  935.             if ( yngContinueToSwingTheBell == GO )
  936.             {
  937.                WinDrawBitmap(
  938.                   hps,                 /* Handle to the Presentation space.   */
  939.                   hbmBitmapToShow,     /* Handle to the bell bitmap.          */
  940.                   (PRECTL) NULL,       /* Use all of the bitmap.              */
  941.                   &ptlBitMapPoint,     /* The point to place the bitmap.      */
  942.                   CLR_NEUTRAL,         /* The Foreground color.               */
  943.                   CLR_BACKGROUND,      /* The background color.               */
  944.                   DBM_NORMAL );        /* How to draw the bitmap.             */
  945.             }
  946.             else
  947.             {
  948.                WinDrawBitmap(
  949.                   hps,                               /* Handle to the PS.     */
  950.                   ahbmBellBitMaps[ IX_CENTER_BELL ], /* Center bell handle.   */
  951.                   (PRECTL) NULL,       /* Use all of the bitmap.              */
  952.                   &ptlBitMapPoint,     /* The point to place the bitmap.      */
  953.                   CLR_NEUTRAL,         /* The Foreground color.               */
  954.                   CLR_BACKGROUND,      /* The background color.               */
  955.                   DBM_NORMAL );        /* How to draw the bitmap.             */
  956.             }  /* End of if loop. */
  957.  
  958.             WinEndPaint( hps );
  959.          }   /* End of Minimize IF */
  960.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  961.       }  /* End of WM_PAINT. */
  962.  
  963.       /*
  964.        * The next two messages are handled so that the Clock application can
  965.        * participate in device sharing.  Since it opens the devices as
  966.        * shareable devices, other applications can gain control of the devices.
  967.        * When this happens, we will receive a pass device message.  We keep
  968.        * track of this device passing in the fPassed boolean variable.
  969.        *
  970.        * If we do not have access to the device when we receive an activate
  971.        * message, then we will issue an acquire device command to gain
  972.        * access to the device.
  973.        */
  974.  
  975.       case MM_MCIPASSDEVICE:
  976.          if (SHORT1FROMMP(mp2) == MCI_GAINING_USE)
  977.          {
  978.             fPassed = FALSE;                    /* Gaining control of device */
  979.          } else
  980.          {
  981.             fPassed = TRUE;                     /* Losing control of device  */
  982.          }
  983.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  984.  
  985.       case WM_ACTIVATE:
  986.  
  987.          /* We use the WM_ACTIVATE message to participate in device sharing.
  988.           * We first check to see if this is an activate or a deactivate
  989.           * message (indicated by mp1). Then, we check to see if we've passed
  990.           * control of the device that we use.  If these conditions are true,
  991.           * then we issue an acquire device command to regain control of the
  992.           * device, since we're now the active window on the screen.
  993.           */
  994.  
  995.          /*
  996.           * First we check to see if we've passed control of the device
  997.           */
  998.  
  999.          if ((BOOL)mp1 && fPassed == TRUE) {
  1000.  
  1001.             mciGenericParms.dwCallback =  (DWORD) hwnd;
  1002.  
  1003.             dwError = mciSendCommand( mciOpenParameters.wDeviceID,
  1004.                                       MCI_ACQUIREDEVICE,
  1005.                                       (DWORD)MCI_NOTIFY,
  1006.                                       (DWORD) &mciGenericParms,
  1007.                                       (WORD)NULL);
  1008.             if (dwError)
  1009.             {
  1010.                ShowAMessage(acStringBuffer[IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT-1],
  1011.                             IDS_CHIME_FILE_ERROR,       /* ID of message      */
  1012.                             MB_OK | MB_INFORMATION |
  1013.                             MB_HELP | MB_APPLMODAL |
  1014.                             MB_MOVEABLE );              /* Style of msg box.  */
  1015.             }
  1016.          }
  1017.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  1018.  
  1019.  
  1020.       default:
  1021.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  1022.  
  1023.    }  /* End of Switch */
  1024.  
  1025.    return( FALSE );
  1026.  
  1027. } /* End of MainDialogProc */
  1028.  
  1029.  
  1030. /*******************************************************************************
  1031.  * Name         : UpdateTheClock
  1032.  *
  1033.  * Description  : This procedure checks to see if the time has changed since
  1034.  *                the last time the clock hands where drawn.  If they have
  1035.  *                and the dialog window is not minimized then the clock hands
  1036.  *                will be redrawn.  If the dialog window is minimized then
  1037.  *                the usLastHour, usLastMinute, usHour, and usMinute global
  1038.  *                variables will be updated to pretend that the clock hands
  1039.  *                have been redrawn.  Whenever the dialog window receives a
  1040.  *                WM_PAINT message the clock hands will be placed into the
  1041.  *                correct position.
  1042.  *
  1043.  * Concepts     : None.
  1044.  *
  1045.  * MMPM/2 API's : None.
  1046.  *
  1047.  * Parameters   : None.
  1048.  *
  1049.  * Return       : None.
  1050.  *
  1051.  ******************************************************************************/
  1052. VOID UpdateTheClock(VOID)
  1053. {
  1054.    DATETIME dtDateTime;          /* Structure to get the date and time.       */
  1055.    USHORT   usNowHour,           /* Hour converted from the above structure.  */
  1056.             usNowMinute;         /* Minute converted from the above structure.*/
  1057.  
  1058.    extern USHORT usLastHour;
  1059.    extern USHORT usLastMinute;
  1060.  
  1061.  
  1062.    DosGetDateTime( &dtDateTime );
  1063.  
  1064.    usNowHour   = (USHORT) dtDateTime.hours;
  1065.    usNowMinute = (USHORT) dtDateTime.minutes;
  1066.  
  1067.    /*
  1068.     * See if the current time differs from the last updated time.  If this is
  1069.     * the case then the clock hands need to be redrawn in the new positions.
  1070.     */
  1071.    if ( usNowHour != usLastHour ||
  1072.         usNowMinute != usLastMinute )
  1073.    {
  1074.       /*
  1075.        * Update the global variables to the new time so that the WM_PAINT
  1076.        * code can set the new hand positions.
  1077.        */
  1078.       usHour   = usNowHour;
  1079.       usMinute = usNowMinute;
  1080.  
  1081.       /*
  1082.        * Since the Time has changed, invalidate the window so that the
  1083.        * clock hands can be redrawn.
  1084.        */
  1085.  
  1086.       WinInvalidateRect(
  1087.          hwndMainDialogBox,
  1088.          &rctClockFaceRectangle,
  1089.          FALSE );
  1090.    }
  1091. } /* End of UpdateTheClock */
  1092.  
  1093. /*****************************************************************************
  1094.  * Name         : DealWithChiming
  1095.  *
  1096.  * Description  : This procedure will handle all of the processing that is
  1097.  *                required to play a chime.  The first thing the procedure
  1098.  *                does is to check to see if it is time to chime. If it is
  1099.  *                then the chiming process will be started otherwise the
  1100.  *                procedure will return to the calling routine.
  1101.  *
  1102.  * Concepts     : None.
  1103.  *
  1104.  * MMPM/2 API's : mciQuerySysValue
  1105.  *
  1106.  * Parameters   : None.
  1107.  *
  1108.  * Return       : None.
  1109.  *
  1110.  ******************************************************************************/
  1111. VOID DealWithChiming( VOID )
  1112. {
  1113.    CHIME_TIME_VALUE_T ctvChimeTime; /* Chime time structure.                  */
  1114.    USHORT usHour;                   /* Hour time.                             */
  1115.    ULONG  fClosedCaptionIsSet;      /* Is closed caption set.                 */
  1116.  
  1117.    if ( IsItChimeTime( &ctvChimeTime, &usHour ) == TRUE &&
  1118.            fThreadIsAlive == TRUE )
  1119.    {
  1120.  
  1121.       /*
  1122.        * If the Close Caption Flag indicates that the bell should be
  1123.        * animated( swung ) then the region of the Presentation space
  1124.        * that contains the Bell bitmap is to be invalidated so that a
  1125.        * WM_PAINT will be sent to draw the Bells.
  1126.        */
  1127.       mciQuerySysValue( MSV_CLOSEDCAPTION, (PVOID)&fClosedCaptionIsSet );
  1128.  
  1129.       if ( (BOOL)fClosedCaptionIsSet == TRUE )
  1130.       {
  1131.          yngContinueToSwingTheBell = READY;
  1132.  
  1133.          hbmBitmapToShow = ahbmBellBitMaps[ IX_CENTER_BELL ];
  1134.  
  1135.          WinInvalidateRect(
  1136.             hwndMainDialogBox,      /* Handle to the dialog box.              */
  1137.             &rctBitMapRectangle,    /* The area in the Pres. Space to update. */
  1138.             TRUE  );                /* Do not bother child window.            */
  1139.  
  1140.       }  /* End of test for closed caption. */
  1141.  
  1142.       FindAndPlayTheCorrectChime(
  1143.          ctvChimeTime,  /* Current Chime Time value.                          */
  1144.          usHour );      /* The current hour.                                  */
  1145.  
  1146.    }  /* End of Chiming */
  1147.  
  1148. } /* End of DealWithChiming */
  1149.  
  1150.  
  1151. /******************************************************************************
  1152.  * Name         : FindTheNearestChimeTimeAndPlayIt
  1153.  *
  1154.  * Description  : This procedure is called when the Play Chime pushbutton is
  1155.  *                pressed.  The code will calculate the next Hour chime time,
  1156.  *                check to see if the CLosed Caption flag is set so that the
  1157.  *                bell can be swung back and forth, and finally will call a
  1158.  *                procedure to start the process to play the next Hour chime.
  1159.  *
  1160.  * Concepts     : None.
  1161.  *
  1162.  * MMPM/2 API's : None.
  1163.  *
  1164.  * Parameters   : None.
  1165.  *
  1166.  * Return       : None.
  1167.  *
  1168.  ******************************************************************************/
  1169. VOID FindTheNearestChimeTimeAndPlayIt( VOID )
  1170. {
  1171.  
  1172.    DATETIME dtDateTime;          /* Date time structure.                      */
  1173.    USHORT   usNextHour;          /* The hour to play.                         */
  1174.    ULONG    fClosedCaptionIsSet; /* Is closed caption set.                    */
  1175.  
  1176.    /*
  1177.     * Since the startup to play the chime can take more than a second, the
  1178.     * hourglass icon will be shown to the user.
  1179.     */
  1180.    WinSetPointer(
  1181.       HWND_DESKTOP,        /* Desktop window handle.                    */
  1182.       WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  1183.          HWND_DESKTOP,     /* Desktop window handle.                    */
  1184.          SPTR_WAIT,        /* The Hourglass icon.                       */
  1185.          FALSE ) );        /* Return the system pointer's handle.       */
  1186.  
  1187.    DosGetDateTime( &dtDateTime );
  1188.  
  1189.    usNextHour = (USHORT) dtDateTime.hours;
  1190.  
  1191.    /*
  1192.     * If it is 24:00, i.e., Midnight the system will return 0.  We want 12.
  1193.     */
  1194.    if ( usNextHour == 0 )
  1195.    {
  1196.       usNextHour = 12;
  1197.    }
  1198.  
  1199.    /*
  1200.     * Go to the next hour.
  1201.     */
  1202.    usNextHour++;
  1203.  
  1204.    /*
  1205.     * Make sure that the next hour does not go past 12 o' clock.  The time
  1206.     * is kept by the system in "military" time, i.e., 4:42 is 16:42 thus
  1207.     * we need to play the Hour chime 4 times not 16.  Therefore subtract
  1208.     * 12 from the next hour value.
  1209.     */
  1210.    if ( usNextHour > 12 )
  1211.    {
  1212.       usNextHour-= 12;
  1213.    }
  1214.  
  1215.     /*
  1216.     * If the Close Caption Flag indicates that the bell should be animate
  1217.     * ( swung ) then the region of the Presentation space that contains
  1218.     * the Bell bitmap is to be invalidated so that a WM_PAINT will be sent
  1219.     * to draw the Bells.
  1220.     */
  1221.    mciQuerySysValue( MSV_CLOSEDCAPTION, (PVOID)&fClosedCaptionIsSet );
  1222.  
  1223.    if ( (BOOL)fClosedCaptionIsSet == TRUE )
  1224.    {
  1225.       yngContinueToSwingTheBell = READY;
  1226.  
  1227.       hbmBitmapToShow = ahbmBellBitMaps[ IX_CENTER_BELL ];
  1228.  
  1229.       WinInvalidateRect(
  1230.          hwndMainDialogBox,      /* Handle to the dialog box.                 */
  1231.          &rctBitMapRectangle,    /* The area in the Pres. Space to update.    */
  1232.          TRUE  );                /* Do not bother child window.               */
  1233.  
  1234.    }  /* End of test for closed caption. */
  1235.  
  1236.    /*
  1237.     * Now that we know what the hour is start playing the chime.
  1238.     */
  1239.    FindAndPlayTheCorrectChime(
  1240.       HOUR,               /* Current Chime Time value.                        */
  1241.       usNextHour );       /* The next hour to chime.                          */
  1242.  
  1243.       /*
  1244.        * Now that the startup processing is over, remove the Hourglass
  1245.        * icon and replace it with the normal arrow icon.
  1246.        */
  1247.       WinSetPointer(
  1248.          HWND_DESKTOP,        /* Desktop window handle.                    */
  1249.          WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  1250.             HWND_DESKTOP,     /* Desktop window handle.                    */
  1251.             SPTR_ARROW,       /* The Hourglass icon.                       */
  1252.             FALSE ) );        /* Return the system pointer's handle.       */
  1253. }  /* End of FindTheNearestChimeTimeAndPlayIt. */
  1254.  
  1255. /*****************************************************************************
  1256.  * Name         : FindAndPlayTheCorrectChime
  1257.  *
  1258.  * Description  : This procedure will take the passed in values, open and
  1259.  *                eventually play the correct chime file based on the given
  1260.  *                information.
  1261.  *
  1262.  * Concepts     : Sending MCI commands to the MCD.
  1263.  *
  1264.  * MMPM/2 API's : mciSendCommand
  1265.  *                MCI_PLAY
  1266.  *
  1267.  * Parameters   : ctvChimeTime           : The time that is to be chimed.
  1268.  *                usHour                 : The Hour to play.
  1269.  *
  1270.  * Return       : None.
  1271.  *
  1272.  ******************************************************************************/
  1273. VOID FindAndPlayTheCorrectChime( CHIME_TIME_VALUE_T ctvChimeTime,
  1274.                                  USHORT             usHour )
  1275. {
  1276.    /*
  1277.     * Flags used to open the playlist.
  1278.     */
  1279.    ULONG ulOpenFlags = MCI_WAIT | MCI_OPEN_PLAYLIST | MCI_OPEN_TYPE_ID |
  1280.                        MCI_OPEN_SHAREABLE;
  1281.  
  1282.    switch( ctvChimeTime )
  1283.    {
  1284.       case HOUR :
  1285.       {
  1286.  
  1287.          OpenPlaylistChimeDevice(
  1288.             ulOpenFlags,                  /* The flags to use when Opening.*/
  1289.             HOUR_PLAYLIST );              /* Which chime file to open.     */
  1290.  
  1291.          /*
  1292.           * Set the playlist to loop for the number of hours that is to
  1293.           * be played.  The hour value will be placed into the high order
  1294.           * of the 32 bit value in operand one of the playlist structure.
  1295.           */
  1296.          apltPlayList[ HOUR_PLAYLIST ][ LOOP_LINE ].ulOperandOne =
  1297.             ((ULONG) (usHour));
  1298.  
  1299.          SetupChimeFileInformation();
  1300.  
  1301.          /*
  1302.           * fill in handle of main window proc for callback processing
  1303.           * after play completes.
  1304.           */
  1305.          mciOpenParameters.dwCallback = (DWORD)hwndMainDialogBox;
  1306.  
  1307.          /* Disable the Play Chime pushbutton while the chime is playing. */
  1308.  
  1309.          WinEnableWindow(
  1310.             hwndPlayChimePB,     /* Handle to the Play Chime push button.   */
  1311.             FALSE);              /* Disable the push button.                */
  1312.  
  1313.          mciSendCommand(
  1314.             mciOpenParameters.wDeviceID,  /* Device to play the chimes.    */
  1315.             MCI_PLAY,                     /* MCI message.                  */
  1316.             MCI_NOTIFY,                   /* Flags for the MCI message.    */
  1317.             (DWORD) &mciOpenParameters,   /* Parameters for the message.   */
  1318.             HOUR_PLAYLIST );              /* Parameter for notify message. */
  1319.  
  1320.          break;
  1321.       }  /* End of Hour Chime. */
  1322.  
  1323.       case HALF_HOUR :
  1324.       {
  1325.          OpenPlaylistChimeDevice(
  1326.             ulOpenFlags,               /* The flags to use when Opening.   */
  1327.             HALF_HOUR_PLAYLIST );      /* Which chime file to open.        */
  1328.  
  1329.          SetupChimeFileInformation();
  1330.  
  1331.          /*
  1332.           * fill in handle of main window proc for callback processing
  1333.           * after play completes.
  1334.           */
  1335.          mciOpenParameters.dwCallback = (DWORD)hwndMainDialogBox;
  1336.  
  1337.          mciSendCommand(
  1338.             mciOpenParameters.wDeviceID,  /* Device to play the chimes.    */
  1339.             MCI_PLAY,                     /* MCI message.                  */
  1340.             MCI_NOTIFY,                   /* Flags for the MCI message.    */
  1341.             (DWORD) &mciOpenParameters,   /* Parameters for the message.   */
  1342.             HALF_HOUR_PLAYLIST );         /* Parameter for notify message. */
  1343.          break;
  1344.       }  /* End of Half Hour Chime. */
  1345.  
  1346.       case QUARTER_HOUR :
  1347.       {
  1348.          OpenPlaylistChimeDevice(
  1349.             ulOpenFlags,               /* The flags to use when Opening.   */
  1350.             QUARTERS_PLAYLIST );       /* Which chime file to open.        */
  1351.  
  1352.          SetupChimeFileInformation();
  1353.  
  1354.          /*
  1355.           * fill in handle of main window proc for callback processing
  1356.           * after play completes.
  1357.           */
  1358.          mciOpenParameters.dwCallback = (DWORD)hwndMainDialogBox;
  1359.  
  1360.          mciSendCommand(
  1361.             mciOpenParameters.wDeviceID,  /* Device to play the chimes.    */
  1362.             MCI_PLAY,                     /* MCI message.                  */
  1363.             MCI_NOTIFY,                   /* Flags for the MCI message.    */
  1364.             (DWORD) &mciOpenParameters,   /* Parameters for the message.   */
  1365.             QUARTERS_PLAYLIST );          /* Parameter for notify message. */
  1366.          break;
  1367.       }  /* End of Quarter Hour chime. */
  1368.  
  1369.       case THREE_QUARTER_HOUR :
  1370.       {
  1371.          OpenPlaylistChimeDevice(
  1372.             ulOpenFlags,               /* The flags to use when Opening.   */
  1373.             THREE_QUARTERS_PLAYLIST ); /* Which chime file to open.        */
  1374.  
  1375.          SetupChimeFileInformation();
  1376.  
  1377.          /*
  1378.           * fill in handle of main window proc for callback processing
  1379.           * after play completes.
  1380.           */
  1381.          mciOpenParameters.dwCallback = (DWORD)hwndMainDialogBox;
  1382.  
  1383.          mciSendCommand(
  1384.             mciOpenParameters.wDeviceID,  /* Device to play the chimes.    */
  1385.             MCI_PLAY,                     /* MCI message.                  */
  1386.             MCI_NOTIFY,                   /* Flags for the MCI message.    */
  1387.             (DWORD) &mciOpenParameters,   /* Parameters for the message.   */
  1388.             THREE_QUARTERS_PLAYLIST );    /* Notify Parameter.           */
  1389.          break;
  1390.       }  /* End of Three Quarter Hour Chime. */
  1391.    }  /* End of Switch. */
  1392.  
  1393. }  /* End of FindAndPlayTheCorrectChime */
  1394.  
  1395.  
  1396. /******************************************************************************
  1397.  * Name        : SetupChimeFileInformation
  1398.  *
  1399.  * Description : This procedure tells the MCD information about the file
  1400.  *               that is about to be played.  The Samples Per Second,
  1401.  *               Bits Per Sample, and the number of channels with which
  1402.  *               the waveform file was created has to be told to the MCD.
  1403.  *
  1404.  * Concepts    : How to set information on waveform files so that they may
  1405.  *               be played.  This info was obtained by querying the header
  1406.  *               of the waveform file in the routine CopyWaveformIntoMemory.
  1407.  *               This information is stored in the global variable,
  1408.  *               mmAudioHeader.
  1409.  *               In this routine, the info is set by issuing an mciSendCommand
  1410.  *               with the MCI_SET message.
  1411.  *
  1412.  * MMPM/2 API's: mciSendCommand
  1413.  *               MCI_SET
  1414.  *
  1415.  * Parameters  : None.
  1416.  *
  1417.  * Return      : None.
  1418.  *
  1419.  ******************************************************************************/
  1420. VOID SetupChimeFileInformation( VOID )
  1421. {
  1422.    MCI_WAVE_SET_PARMS mwspWaveFormParameters;   /* Waveform parameters.       */
  1423.    ULONG              ulRC;                     /* Return code.               */
  1424.  
  1425.    /*
  1426.     * Fill the structure with zeros.
  1427.     */
  1428.    memset( &mwspWaveFormParameters,            /* Object to fill with zeros.  */
  1429.            0,                                  /* Value to place in object.   */
  1430.            sizeof( mwspWaveFormParameters ) ); /* How many zeros's to use.    */
  1431.  
  1432.    /*
  1433.     * Set structure values for the MCI_SET.
  1434.     */
  1435.    mwspWaveFormParameters.nSamplesPerSec =
  1436.       mmAudioHeader.mmXWAVHeader.WAVEHeader.ulSamplesPerSec;
  1437.    mwspWaveFormParameters.wBitsPerSample =
  1438.       mmAudioHeader.mmXWAVHeader.WAVEHeader.usBitsPerSample;
  1439.    mwspWaveFormParameters.nChannels      =
  1440.       mmAudioHeader.mmXWAVHeader.WAVEHeader.usChannels;
  1441.    mwspWaveFormParameters.dwAudio        =
  1442.       MCI_SET_AUDIO_ALL;
  1443.  
  1444.    /*
  1445.     * Set the number of channels.
  1446.     */
  1447.    ulRC =
  1448.       mciSendCommand(
  1449.          mciOpenParameters.wDeviceID,
  1450.          MCI_SET,
  1451.          MCI_WAIT | MCI_WAVE_SET_CHANNELS,
  1452.          (DWORD) &mwspWaveFormParameters,
  1453.          0 );
  1454.  
  1455.    /*
  1456.     * Set the samples per second for the waveform file.
  1457.     */
  1458.    ulRC =
  1459.       mciSendCommand(
  1460.          mciOpenParameters.wDeviceID,
  1461.          MCI_SET,
  1462.          MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC,
  1463.          (DWORD) &mwspWaveFormParameters,
  1464.          0 );
  1465.  
  1466.    /*
  1467.     * Set the bits per second for the waveform file.
  1468.     */
  1469.    ulRC =
  1470.       mciSendCommand(
  1471.          mciOpenParameters.wDeviceID,
  1472.          MCI_SET,
  1473.          MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE,
  1474.          (DWORD) &mwspWaveFormParameters,
  1475.          0 );
  1476.  
  1477. }  /* End of SetupChimeFileInformation. */
  1478.  
  1479.  
  1480. /******************************************************************************
  1481.  * Name        : OpenPlaylistChimeDevice
  1482.  *
  1483.  * Description : This procedure opens a device based on the variable
  1484.  *               usChimeFileToPlay with the open flags given in the
  1485.  *               ulOpenFlags parameter.  The code uses the given parameters
  1486.  *               to set up the open parameters structure and then simply
  1487.  *               opens the playlist.
  1488.  *
  1489.  * Concepts    : How to open playlists and how to retrieve error information
  1490.  *               from failed MMPM/2 APIs.
  1491.  *
  1492.  * MMPM/2 API's: mciSendCommand
  1493.  *               mciGetErrorString
  1494.  *               MCI_OPEN
  1495.  *
  1496.  * Parameters  : ulOpenFlags       : The flags to use when opending the file.
  1497.  *               usChimePlaylistToPlay : Which chime to play.
  1498.  *
  1499.  * Return      : None.
  1500.  *
  1501.  ******************************************************************************/
  1502. VOID OpenPlaylistChimeDevice( ULONG  ulOpenFlags,
  1503.                               USHORT usChimePlaylistToPlay )
  1504.  
  1505. {
  1506.    ULONG mciRC;                 /* MCI generic return code variable.          */
  1507.  
  1508.    /*
  1509.     * Holds error text discription.
  1510.     */
  1511.    CHAR  acErrorStringBuffer[ MCI_ERROR_STRING_LENGTH ];
  1512.  
  1513.    /*
  1514.     * Open the correct waveform device for the chimes with the MCI_OPEN
  1515.     * message to MCI.
  1516.     */
  1517.    mciOpenParameters.lpstrDeviceType  = (LPSTR)
  1518.       MAKEULONG ( MCI_DEVTYPE_WAVEFORM_AUDIO, 1 );
  1519.  
  1520.    /*
  1521.     * The address of the buffer containing the chime waveform file.
  1522.     */
  1523.    mciOpenParameters.lpstrElementName =
  1524.       (LPSTR) &apltPlayList[ usChimePlaylistToPlay ][ 0 ];
  1525.  
  1526.    /*
  1527.     * Initialize the MCI_OPEN_PARMS data structure with hwndMainDialogBox
  1528.     * as callback handle for MM_MCIPASSDEVICE, then issue the MCI_OPEN
  1529.     * command with the mciSendCommand function.  No alias is used.
  1530.     */
  1531.    mciOpenParameters.dwCallback       = (DWORD) hwndMainDialogBox;
  1532.    mciOpenParameters.lpstrAlias       = (CHAR) NULL;
  1533.  
  1534.    /*
  1535.     * Open the waveform file in the playlist mode.
  1536.     */
  1537.    mciRC =
  1538.       mciSendCommand(
  1539.          0,                           /* We don't know the device yet.        */
  1540.          MCI_OPEN,                    /* MCI message.                         */
  1541.          ulOpenFlags,                 /* Flags for the MCI message.           */
  1542.          (DWORD) &mciOpenParameters,  /* Parameters for the message.          */
  1543.          0 );                         /* Parameter for notify message.        */
  1544.  
  1545.    if ( mciRC != 0 )
  1546.    {
  1547.       mciRC =
  1548.          mciGetErrorString(
  1549.             mciRC,
  1550.             (LPSTR) &acErrorStringBuffer[ 0 ],
  1551.             (WORD) MCI_ERROR_STRING_LENGTH );
  1552.  
  1553.       /*
  1554.        * Make sure that the retrieving of the error string was successfull.
  1555.        */
  1556.       if ( mciRC != MCIERR_SUCCESS )
  1557.       {
  1558.          ShowAMessage(
  1559.             acStringBuffer[
  1560.                IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  1561.             IDS_CHIME_FILE_ERROR,
  1562.             MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP | MB_APPLMODAL  );
  1563.  
  1564.          return;
  1565.  
  1566.       }  /* End of IF testing for failed Get Error String API. */
  1567.  
  1568.       /*
  1569.        * Show the error string that was retrieved by the mciGetErrorString
  1570.        * MMPM/2 API.
  1571.        */
  1572.       WinMessageBox(
  1573.          HWND_DESKTOP,                  /* Parent handle.                     */
  1574.          hwndMainDialogBox,             /* Owner handle of the message box.   */
  1575.          acErrorStringBuffer,           /* String to show in the message box. */
  1576.          acStringBuffer[
  1577.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],  /* Title.               */
  1578.          ID_MESSAGE_BOX,                /* Message Box Id.                    */
  1579.          MB_OK | MB_INFORMATION );      /* The style of the message box.      */
  1580.  
  1581.    }  /* End of IF testing for failed MCI Send Command API. */
  1582.  
  1583. }  /* End of OpenPlaylistChimeDevice. */
  1584.  
  1585.  
  1586. /******************************************************************************
  1587.  * Name        : IsItChimeTime
  1588.  *
  1589.  * Description : This procedure will start the processing that is required
  1590.  *               to play a chime.  The first thing the procedure does is
  1591.  *               to check to see if it is time to chime.  If it is, then the
  1592.  *               chime file that is used will be determined and the function
  1593.  *               will return TRUE to the calling routine.  The calling code
  1594.  *               will continue with the processing requied to play a chime
  1595.  *               file.
  1596.  *
  1597.  * Concepts    : None.
  1598.  *
  1599.  * MMPM/2 API's: None.
  1600.  *
  1601.  * Parameters  : ctvChimeTime - What time is it, hour, quarter hour, etc.
  1602.  *               pusNowHour   - Holds the actual hour value.
  1603.  *
  1604.  * Return      : TRUE         - if it is time to chime.
  1605.  *               FALSE        - if it is NOT time to chime.
  1606.  *               ctvChimeTime - This will be returned to the calling
  1607.  *                              routine.
  1608.  *
  1609.  ******************************************************************************/
  1610. BOOL IsItChimeTime( CHIME_TIME_VALUE_T *ctvChimeTime,
  1611.                     USHORT             *pusNowHour )
  1612. {
  1613.    /*
  1614.     * The last valid chime time structure in HOUR, QUARTER....
  1615.     */
  1616.    static CHIME_TIME_VALUE_T ctvLastValidChimeTime = NONE;
  1617.  
  1618.    DATETIME dtDateTime;       /* Date time structure.                         */
  1619.    USHORT   usNowHour,        /* The current hour from the above structure.   */
  1620.             usNowMinute;      /* The current minute from the above structure. */
  1621.  
  1622.    DosGetDateTime( &dtDateTime );
  1623.  
  1624.    usNowHour   = (USHORT) dtDateTime.hours;
  1625.    usNowMinute = (USHORT) dtDateTime.minutes;
  1626.  
  1627.    /*
  1628.     * See if it is greater the 12 o' clock.  If it is then subtract 12 to get
  1629.     * the correct hour.  If the time is 0 then it is midnight which is 12.
  1630.     */
  1631.    if ( usNowHour > 12 )
  1632.    {
  1633.       usNowHour -= 12;
  1634.    }
  1635.    else
  1636.    if ( usNowHour == 0 )
  1637.    {
  1638.       usNowHour = 12;
  1639.    }
  1640.  
  1641.    *pusNowHour = usNowHour;
  1642.  
  1643.    /*
  1644.     * See if the time is one of the chime times.  If so and we have not ever
  1645.     * been in this function since the time changed to a chime time, then
  1646.     * the function will return TRUE and the correct chime time indicator.
  1647.     * Otherwise the function will return FALSE and NONE.
  1648.     */
  1649.    if ( (usNowMinute == 0 || usNowMinute == 60) &&
  1650.          ctvLastValidChimeTime != HOUR)
  1651.    {
  1652.       *ctvChimeTime         = HOUR;
  1653.       ctvLastValidChimeTime = HOUR;
  1654.       return( TRUE );
  1655.    }
  1656.    else
  1657.    if ( usNowMinute == 15 && ctvLastValidChimeTime != QUARTER_HOUR )
  1658.    {
  1659.       *ctvChimeTime         = QUARTER_HOUR;
  1660.       ctvLastValidChimeTime = QUARTER_HOUR;
  1661.       return( TRUE );
  1662.    }
  1663.    else
  1664.    if ( usNowMinute == 30 && ctvLastValidChimeTime != HALF_HOUR )
  1665.    {
  1666.       *ctvChimeTime         = HALF_HOUR;
  1667.       ctvLastValidChimeTime = HALF_HOUR;
  1668.       return( TRUE );
  1669.    }
  1670.    else
  1671.    if ( usNowMinute == 45 && ctvLastValidChimeTime != THREE_QUARTER_HOUR )
  1672.    {
  1673.       *ctvChimeTime         = THREE_QUARTER_HOUR;
  1674.       ctvLastValidChimeTime = THREE_QUARTER_HOUR;
  1675.       return( TRUE );
  1676.    }
  1677.    else
  1678.    {
  1679.       *ctvChimeTime         = NONE;
  1680.       return( FALSE );
  1681.    }
  1682.  
  1683. } /* End of IsItChimeTime */
  1684.  
  1685.  
  1686. /******************************************************************************
  1687.  * Name        : InitializeHelp
  1688.  *
  1689.  * Description : This procedure will set up the initial values in the global
  1690.  *               help structure.  This help structure will then be passed on
  1691.  *               to the Help Manager when the Help Instance is created.  The
  1692.  *               handle to the Help Instance will be kept for later use.
  1693.  *
  1694.  * Concepts    : None.
  1695.  *
  1696.  * MMPM/2 API's: None.
  1697.  *
  1698.  * Parameters  : None.
  1699.  *
  1700.  * Return      : None.
  1701.  *
  1702.  ******************************************************************************/
  1703. VOID InitializeHelp( VOID )
  1704. {
  1705.  
  1706.    /*
  1707.     * Get the size of the initialization structure.
  1708.     */
  1709.    hmiHelpStructure.cb              = sizeof( HELPINIT );
  1710.  
  1711.    hmiHelpStructure.ulReturnCode    = (ULONG) NULL; /* RC from initialization.*/
  1712.    hmiHelpStructure.pszTutorialName = (CHAR) NULL;  /* No tutorial program.   */
  1713.  
  1714.    hmiHelpStructure.phtHelpTable    = (PVOID)(0xffff0000 | ID_CLOCK_HELPTABLE);
  1715.  
  1716.    /*
  1717.     * The action bar is not used, so set the following to NULL.
  1718.     */
  1719.    hmiHelpStructure.hmodAccelActionBarModule = (HMODULE) NULL;
  1720.    hmiHelpStructure.idAccelTable             = (USHORT) NULL;
  1721.    hmiHelpStructure.idActionBar              = (USHORT) NULL;
  1722.  
  1723.    /*
  1724.     * The Help window title.
  1725.     */
  1726.    hmiHelpStructure.pszHelpWindowTitle  =
  1727.       acStringBuffer[ IDS_HELP_WINDOW_TITLE - 1 ];
  1728.  
  1729.    /*
  1730.     * The Help table is in the executable file.
  1731.     */
  1732.    hmiHelpStructure.hmodHelpTableModule = (HMODULE) NULL;
  1733.  
  1734.    /*
  1735.     * The help panel ID is not displayed.
  1736.     */
  1737.    hmiHelpStructure.fShowPanelId       = (ULONG) NULL;
  1738.  
  1739.    /*
  1740.     * The library that contains the clock help panels.
  1741.     */
  1742.    hmiHelpStructure.pszHelpLibraryName  =
  1743.       acStringBuffer[ IDS_HELP_LIBRARY_FILE - 1 ];
  1744.  
  1745.    /*
  1746.     * Create the Help Instance for IPF.
  1747.     * Give IPF the Anchor Block handle and address of the IPF initialization
  1748.     * structure, and check that creation of Help was a success.
  1749.     */
  1750.    hwndHelpInstance = WinCreateHelpInstance(
  1751.                          hab,                   /* Anchor Block Handle.       */
  1752.                          &hmiHelpStructure );   /* Help Structure.            */
  1753.  
  1754.    if ( hwndHelpInstance == (HWND) NULL )
  1755.    {
  1756.       ShowAMessage(
  1757.          acStringBuffer[
  1758.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],   /* Message Box title.  */
  1759.          IDS_HELP_CREATION_ERROR,                      /* ID of the message.  */
  1760.          MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_APPLMODAL );
  1761.    }
  1762.    else
  1763.    {
  1764.       if ( hmiHelpStructure.ulReturnCode )
  1765.       {
  1766.          ShowAMessage(
  1767.             acStringBuffer[
  1768.                IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  1769.             IDS_HELP_CREATION_ERROR,           /* ID of the message.          */
  1770.             MB_OK | MB_INFORMATION | MB_APPLMODAL |
  1771.                MB_MOVEABLE );                  /* Message box style.          */
  1772.  
  1773.          WinDestroyHelpInstance( hwndHelpInstance );
  1774.       }
  1775.    }  /* End of IF checking the creation of the Help Instance. */
  1776.  
  1777.    /*
  1778.     * Associate the Help Instance of the IPF to this dialog window.
  1779.     */
  1780.    if ( hwndHelpInstance != (HWND) NULL )
  1781.    {
  1782.      WinAssociateHelpInstance(
  1783.         hwndHelpInstance,     /* The handle of the Help Instance.             */
  1784.         hwndFrame );          /* Associate to this dialog window.             */
  1785.    }
  1786.  
  1787. }  /* End of InitializeHelp */
  1788.  
  1789. /******************************************************************************
  1790.  * Name        : ShowAMessage
  1791.  *
  1792.  * Description : This function will show text in a message box.  The text
  1793.  *               is pulled from the string table that is originally kept
  1794.  *               in the resource file.  The text is retrieved by the
  1795.  *               message id that is passed into this function.  This id is
  1796.  *               used in the WinLoadString OS/2 API to get the correct
  1797.  *               string from the table.
  1798.  *
  1799.  * Concepts    : None.
  1800.  *
  1801.  * MMPM/2 API's: None.
  1802.  *
  1803.  * Parameters  : pcMessageTitle    - The tile to be placed in the message
  1804.  *                                   box.
  1805.  *               usMessageId       - The message id that identifies which
  1806.  *                                   string to retreived from the string
  1807.  *                                   table.
  1808.  *               ulMessageBoxStyle - The style of the message box.  Which
  1809.  *                                   icons, buttons, etc., to show.
  1810.  *
  1811.  * Return      : The result from the message box.
  1812.  *
  1813.  ******************************************************************************/
  1814. USHORT ShowAMessage( CHAR   *pcMessageTitle,
  1815.                      USHORT usMessageId,
  1816.                      ULONG  ulMessageBoxStyle )
  1817. {
  1818.  
  1819.    CHAR   acStringBuffer[ STRING_SIZE ];        /* String Buffer.             */
  1820.    USHORT usMessageBoxResult;                   /* RC from WinMessageBox.     */
  1821.  
  1822.    /*
  1823.     * Get the string from the Resource defined string table and show it
  1824.     * in the message box.
  1825.     */
  1826.    WinLoadString(
  1827.       hab,                             /* HAB for this dialog box.            */
  1828.       (HMODULE) NULL,                  /* Get the string from the .exe file.  */
  1829.       usMessageId,                     /* Which string to get.                */
  1830.       (SHORT) STRING_SIZE,             /* The size of the buffer.             */
  1831.       acStringBuffer );                /* The buffer to place the string.     */
  1832.  
  1833.    usMessageBoxResult =
  1834.       WinMessageBox(
  1835.          HWND_DESKTOP,                 /* Parent handle of the message box.   */
  1836.          hwndMainDialogBox,            /* Owner handle of the message box.    */
  1837.          acStringBuffer,               /* String to show in the message box.  */
  1838.          pcMessageTitle,               /* Title to shown in the message box.  */
  1839.          ID_MESSAGE_BOX,               /* Message Box Id.                     */
  1840.          ulMessageBoxStyle );          /* The style of the message box.       */
  1841.  
  1842.    return( usMessageBoxResult );
  1843.  
  1844. }  /* End of ShowAMessage */
  1845.  
  1846.  
  1847. /******************************************************************************
  1848.  * Name        : SetupPlayList
  1849.  *
  1850.  * Description : This procedure will load the chimes waveform files into
  1851.  *               buffers as well as setting up the required playlists.
  1852.  *
  1853.  *               - Create memory buffers for the waveform( Chimes ) files.
  1854.  *               - Load the chime files into the buffers( mmioRead ).
  1855.  *               - Create the Playlist
  1856.  *
  1857.  * Concepts    : How to create and use the MMPM/2 Playlist functionality.
  1858.  *
  1859.  * MMPM/2 API's: None.
  1860.  *
  1861.  * Parameters  : None.
  1862.  *
  1863.  * Return      : None.
  1864.  *
  1865.  *************************************************************************/
  1866. VOID SetupPlayList( VOID )
  1867. {
  1868.    /*
  1869.     * This array keeps the address of each audio chime file.
  1870.     */
  1871.    static LONG *pulBaseAddress[ NUMBER_OF_CHIME_FILES ];
  1872.  
  1873.    USHORT usChimeFileId;            /* Chime audio file id.                   */
  1874.    ULONG  ulSizeOfFile,             /* Size of audio file.                    */
  1875.  
  1876.    ulMemoryAllocationFlags = PAG_COMMIT | PAG_READ | PAG_WRITE;
  1877.  
  1878.    for(usChimeFileId=0; usChimeFileId<NUMBER_OF_CHIME_FILES; usChimeFileId++)
  1879.    {
  1880.  
  1881.       ulSizeOfFile = HowBigIsTheChimeFile( usChimeFileId );
  1882.  
  1883.       /*
  1884.        * If the returned file size is zero, there is a problem with the chime
  1885.        * files.  A message will already have been shown to the user by the
  1886.        * HowBigIsTheChimeFile function so get out of this routine.
  1887.        */
  1888.       if ( ulSizeOfFile == 0 )
  1889.       {
  1890.          return;
  1891.       }
  1892.  
  1893.       if ( (pulBaseAddress[ usChimeFileId ] = (LONG *)
  1894.               malloc( ulSizeOfFile )) == (LONG *) NULL )
  1895.       {
  1896.          /*
  1897.           * The memory for the waveform files cannot be allocated.
  1898.           * Notify the user and return from this routine.  No playlist can
  1899.           * be created/played until memory is available.
  1900.           */
  1901.          ShowAMessage(
  1902.             acStringBuffer[
  1903.                IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  1904.             IDS_CANNOT_GET_MEMORY,              /* ID of the message to show. */
  1905.             MB_OK | MB_INFORMATION | MB_HELP |  MB_APPLMODAL |
  1906.                MB_MOVEABLE );                   /* Style of the message box.  */
  1907.  
  1908.          return;
  1909.  
  1910.       }  /* End of IF allocation fails. */
  1911.  
  1912.       /*
  1913.        * Place the waveform files into the memory buffer that was just
  1914.        * created.
  1915.        */
  1916.       CopyWaveformIntoMemory(
  1917.          pulBaseAddress[ usChimeFileId ],
  1918.          ulSizeOfFile,
  1919.          usChimeFileId );
  1920.  
  1921.       /*
  1922.        * Now that we've loaded the waveform into memory, we need to put
  1923.        * it's address and size into the playlist data statements that
  1924.        * use this particular file.
  1925.        *
  1926.        * It's address must be placed into the Data statement's first operand
  1927.        * and its size must be placed in the Data statement's second operand.
  1928.        *
  1929.        * For the four different playlist, one for each chime time, 1/4, 1/2,
  1930.        * 3/4 and 1 hour increments, the address of the chime file and it's
  1931.        * size will be loaded into each Data statement of the Playlist.
  1932.        */
  1933.       if ( usChimeFileId == 0 )
  1934.       /* If we just loaded clock1.wav */
  1935.       {
  1936.  
  1937.          /*
  1938.           * Put the address of this chime into the first operand of
  1939.           * every data operation that uses this particular chime.
  1940.           */
  1941.          apltPlayList[ 0 ][ 0 ].ulOperandOne =        /* 1/4 hour 1st data op */
  1942.          apltPlayList[ 1 ][ 0 ].ulOperandOne =        /* 1/2 hour 1st data op */
  1943.          apltPlayList[ 2 ][ 0 ].ulOperandOne =        /* 3/4 hour 1st data op */
  1944.          apltPlayList[ 2 ][ 2 ].ulOperandOne =        /* 3/4 hour 3rd data op */
  1945.          apltPlayList[ 3 ][ 0 ].ulOperandOne =        /* 1   hour 1st data op */
  1946.          apltPlayList[ 3 ][ 2 ].ulOperandOne =        /* 1   hour 3rd data op */
  1947.             (ULONG) pulBaseAddress[ usChimeFileId ];  /* address              */
  1948.  
  1949.          /*
  1950.           * Now put the size of the file into the second operand of every
  1951.           * data operation that uses this particular chime.
  1952.           */
  1953.          apltPlayList[ 0 ][ 0 ].ulOperandTwo =        /* 1/4 hour 1st data op */
  1954.          apltPlayList[ 1 ][ 0 ].ulOperandTwo =        /* 1/2 hour 1st data op */
  1955.          apltPlayList[ 2 ][ 0 ].ulOperandTwo =        /* 3/4 hour 1st data op */
  1956.          apltPlayList[ 2 ][ 2 ].ulOperandTwo =        /* 3/4 hour 3rd data op */
  1957.          apltPlayList[ 3 ][ 0 ].ulOperandTwo =        /* 1   hour 1st data op */
  1958.          apltPlayList[ 3 ][ 2 ].ulOperandTwo =        /* 1   hour 3rd data op */
  1959.             ulSizeOfFile;                             /* size                 */
  1960.  
  1961.       }
  1962.       else
  1963.       if ( usChimeFileId == 1 )
  1964.       /* If we just loaded clock2.wav */
  1965.       {
  1966.          /*
  1967.           * Put the address of this chime into the first operand of
  1968.           * every data operation that uses this particular chime.
  1969.           */
  1970.          apltPlayList[ 1 ][ 1 ].ulOperandOne =        /* 1/2 hour 2nd data op */
  1971.          apltPlayList[ 2 ][ 1 ].ulOperandOne =        /* 3/4 hour 2nd data op */
  1972.          apltPlayList[ 3 ][ 1 ].ulOperandOne =        /* 1   hour 2nd data op */
  1973.          apltPlayList[ 3 ][ 3 ].ulOperandOne =        /* 1   hour 4th data op */
  1974.             (ULONG) pulBaseAddress[ usChimeFileId ];  /* address              */
  1975.  
  1976.          /*
  1977.           * Now put the size of the file into the second operand of every
  1978.           * data operation that uses this particular chime.
  1979.           */
  1980.          apltPlayList[ 1 ][ 1 ].ulOperandTwo =        /* 1/2 hour 2nd data op */
  1981.          apltPlayList[ 2 ][ 1 ].ulOperandTwo =        /* 3/4 hour 2nd data op */
  1982.          apltPlayList[ 3 ][ 1 ].ulOperandTwo =        /* 1   hour 2nd data op */
  1983.          apltPlayList[ 3 ][ 3 ].ulOperandTwo =        /* 1   hour 4th data op */
  1984.             ulSizeOfFile;                             /* size                 */
  1985.       }
  1986.       else
  1987.       if ( usChimeFileId == 2 )
  1988.       /* If we just loaded clock3.wav (this is the gong part of the chime) */
  1989.       {
  1990.          /*
  1991.           * Put the address of this chime into the first operand of
  1992.           * every data operation that uses this particular chime.
  1993.           */
  1994.          apltPlayList[ 3 ][ 5 ].ulOperandOne =        /* 1 hour 5th data op */
  1995.             (ULONG) pulBaseAddress[ usChimeFileId ];
  1996.  
  1997.          /*
  1998.           * Now put the size of the file into the second operand of every
  1999.           * data operation that uses this particular chime.
  2000.           */
  2001.          apltPlayList[ 3 ][ 5 ].ulOperandTwo =        /* 1 hour 5th data op */
  2002.             ulSizeOfFile;
  2003.       }
  2004.  
  2005.    }  /* End of For loop of chime files. */
  2006.  
  2007. }  /* End of SetupPlayList */
  2008.  
  2009.  
  2010. /******************************************************************************
  2011.  * Name        : HowBigIsTheChimeFile
  2012.  *
  2013.  * Description : This function will retrieve the size of a chime file.
  2014.  *               The chime file is identified by the passed in parameter.
  2015.  *
  2016.  * Concepts    : None.
  2017.  *
  2018.  * MMPM/2 API's: mmioOpen  - MMIO_READ
  2019.  *               mmioGetHeader
  2020.  *               mmioClose
  2021.  *
  2022.  * Parameters  : usChimeFileId - Chime file id.
  2023.  *
  2024.  * Return      : Size of the file.
  2025.  *
  2026.  ******************************************************************************/
  2027. ULONG HowBigIsTheChimeFile( USHORT usChimeFileId )
  2028. {
  2029.    MMAUDIOHEADER mmAudHeader;          /* Get size of audio data from this.   */
  2030.    HMMIO hmmioFileHandle;              /* Handle to the audio file handle.    */
  2031.    ULONG ulRC;                         /* Return code from mmioGetHeader.     */
  2032.    ULONG ulBytesRead;                  /* Returned from mmioGetHeader.        */
  2033.    LONG  lMMIOResults;                 /* Results from the MMIO calls.        */
  2034.    CHAR  acFileName[ FILE_NAME_SIZE ]; /* Name of the file.                   */
  2035.  
  2036.    switch( usChimeFileId )
  2037.    {
  2038.       case 0 :
  2039.          strcpy( acFileName, acStringBuffer[ IDS_CHIME_FILE_A - 1] );
  2040.          break;
  2041.  
  2042.       case 1 :
  2043.          strcpy( acFileName, acStringBuffer[ IDS_CHIME_FILE_B - 1 ] );
  2044.          break;
  2045.  
  2046.       case 2 :
  2047.          strcpy( acFileName, acStringBuffer[ IDS_CHIME_FILE_C - 1 ] );
  2048.          break;
  2049.  
  2050.       default:
  2051.          ShowAMessage(
  2052.             acStringBuffer[
  2053.                IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2054.             IDS_CHIME_FILE_ERROR,               /* ID of the message to show. */
  2055.             MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2056.                MB_MOVEABLE );                   /* Style of the message box.  */
  2057.          return;
  2058.  
  2059.    }  /* End of switch statment. */
  2060.  
  2061.    /*
  2062.     * Open the chime file.
  2063.     */
  2064.    hmmioFileHandle =
  2065.       mmioOpen(
  2066.          acFileName,
  2067.          (PMMIOINFO) NULL,
  2068.          MMIO_READ );
  2069.  
  2070.    /*
  2071.     * See if the file open was successful.  If it was not then show an
  2072.     * error message, set a flag so that NO chimes will be played and
  2073.     * return a size 0.
  2074.     */
  2075.    if ( hmmioFileHandle == (HMMIO) NULL )
  2076.    {
  2077.       yngAreChimeFilesLoaded = STOP;
  2078.       ShowAMessage(
  2079.          acStringBuffer[
  2080.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2081.          IDS_CHIME_FILE_ERROR,                  /* ID of the message to show. */
  2082.          MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2083.             MB_MOVEABLE );                      /* Style of the message box.  */
  2084.       return (0);
  2085.    }
  2086.  
  2087.    /*
  2088.     * Get the header information from the waveform file. From this
  2089.     * information, we can get the size of the waveform data in the file.
  2090.     *
  2091.     * We only want to copy the waveform data into memory, we do not
  2092.     * want to copy the header as well.  So, we use the usAudioLengthInBytes
  2093.     * field of the XWAV_HEADERINFO structure, which indicates the size of
  2094.     * the audio data in the file.
  2095.     */
  2096.    ulRC = mmioGetHeader ( hmmioFileHandle,
  2097.                           (PVOID)&mmAudHeader,
  2098.                           sizeof (MMAUDIOHEADER),
  2099.                           (PLONG) &ulBytesRead,
  2100.                           (DWORD) NULL,
  2101.                           (DWORD) NULL);
  2102.  
  2103.  
  2104.    if (ulRC != MMIO_SUCCESS) {
  2105.       yngAreChimeFilesLoaded = STOP;
  2106.       ShowAMessage(
  2107.          acStringBuffer[
  2108.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2109.          IDS_CHIME_FILE_ERROR,                  /* ID of the message to show. */
  2110.          MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2111.             MB_MOVEABLE );                      /* Style of the message box.  */
  2112.       return (0);
  2113.    }
  2114.  
  2115.    /*
  2116.     * If the global flag is not stop then assign the GO value.  This will allow
  2117.     * a chime file to be played.
  2118.     */
  2119.    if ( yngAreChimeFilesLoaded != STOP )
  2120.    {
  2121.       yngAreChimeFilesLoaded = GO;
  2122.    }
  2123.  
  2124.    /*
  2125.     * Close the file.
  2126.     */
  2127.    lMMIOResults =
  2128.       mmioClose(
  2129.          hmmioFileHandle,             /* Handle of the file to close.         */
  2130.          0 );                         /* No flags are used.                   */
  2131.  
  2132.  
  2133.    /* Return the size of the audio data in bytes.
  2134.     */
  2135.  
  2136.    return( mmAudHeader.mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes );
  2137.  
  2138. }  /* End of HowBigIsTheChimeFile */
  2139.  
  2140.  
  2141. /******************************************************************************
  2142.  * Name        : CopyWaveformIntoMemory
  2143.  *
  2144.  * Description : This procedure loads the chime waveform files from DASD into
  2145.  *               the memory buffer that was created by the routine that called
  2146.  *               CopyWaveformIntoMemory.  It also querys information in the
  2147.  *               header of the waveform file for use in a later routine,
  2148.  *               SetupChimeFileInformation.
  2149.  *
  2150.  * Concepts    : How to open and read files with the MMIO APIs.
  2151.  *
  2152.  * MMPM/2 API's: mmioOpen
  2153.  *               mmioRead
  2154.  *               mmioClose
  2155.  *               mmioGetHeader
  2156.  *
  2157.  * Parameters  : pulBaseAddress - The address of the buffer that will hold
  2158.  *                                one of the chime waveform files.
  2159.  *               ulSizeOfBuffer - The size the file buffer.
  2160.  *               usChimeFile    - The identifier for the chime file.
  2161.  *
  2162.  * Return      : None.
  2163.  *
  2164.  ******************************************************************************/
  2165. VOID CopyWaveformIntoMemory( LONG   *pulBaseAddress,
  2166.                              ULONG  ulSizeOfBuffer,
  2167.                              USHORT usChimeFile )
  2168. {
  2169.  
  2170.    HMMIO hmmioFileHandle;              /* Handle to the audio file handle.    */
  2171.    CHAR  acFileName[ FILE_NAME_SIZE ]; /* Name of the file.                   */
  2172.    LONG  lMMIOResults;                 /* Results from the MMIO calls.        */
  2173.    ULONG ulRC;                         /* Return code from mmioGetHeader.     */
  2174.    ULONG ulBytesRead;                  /* Returned from mmioGetHeader.        */
  2175.  
  2176.    switch( usChimeFile )
  2177.    {
  2178.       case 0 :
  2179.          strcpy( acFileName, acStringBuffer[ IDS_CHIME_FILE_A - 1] );
  2180.          break;
  2181.  
  2182.       case 1 :
  2183.          strcpy( acFileName, acStringBuffer[ IDS_CHIME_FILE_B - 1 ] );
  2184.          break;
  2185.  
  2186.       case 2 :
  2187.          strcpy( acFileName, acStringBuffer[ IDS_CHIME_FILE_C - 1 ] );
  2188.          break;
  2189.  
  2190.       default:
  2191.          ShowAMessage(
  2192.             acStringBuffer[
  2193.                IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2194.             IDS_CHIME_FILE_ERROR,               /* ID of the message to show. */
  2195.             MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2196.                MB_MOVEABLE );                   /* Style of the message box.  */
  2197.          return;
  2198.  
  2199.    }  /* End of switch statment. */
  2200.  
  2201.    /*
  2202.     * Open the chime file.
  2203.     */
  2204.    hmmioFileHandle =
  2205.       mmioOpen(
  2206.          acFileName,
  2207.          (PMMIOINFO) NULL,
  2208.          MMIO_READ );
  2209.  
  2210.    if ( hmmioFileHandle == (HMMIO) NULL )
  2211.    {
  2212.       ShowAMessage(
  2213.          acStringBuffer[
  2214.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2215.          IDS_CHIME_FILE_ERROR,                  /* ID of the message to show. */
  2216.          MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2217.             MB_MOVEABLE );                      /* Style of the message box.  */
  2218.       return;
  2219.    }
  2220.  
  2221.    /*
  2222.     * Get the header information from the waveform file.  This information
  2223.     * will be used later in the routine SetupChimeFileInformation in order
  2224.     * to setup the device to play the playlist.  We only need to do this
  2225.     * for the first file, since all of the chime files were recorded in the
  2226.     * same way. The fInitHeader boolean indicates if we've already performed
  2227.     * this query or not.
  2228.     */
  2229.  
  2230.    if (fInitHeader) {
  2231.       ulRC = mmioGetHeader ( hmmioFileHandle,
  2232.                              (PVOID)&mmAudioHeader,
  2233.                              sizeof (MMAUDIOHEADER),
  2234.                              (PLONG) &ulBytesRead,
  2235.                              (DWORD) NULL,
  2236.                              (DWORD) NULL);
  2237.       fInitHeader = FALSE;
  2238.    }
  2239.  
  2240.  
  2241.    /*
  2242.     * Move the data from the chime file into the buffer.
  2243.     */
  2244.    lMMIOResults =
  2245.       mmioRead(
  2246.          hmmioFileHandle,
  2247.          (HPSTR) pulBaseAddress,
  2248.          ulSizeOfBuffer );
  2249.  
  2250.    if ( lMMIOResults == MMIO_ERROR )
  2251.    {
  2252.       ShowAMessage(
  2253.          acStringBuffer[
  2254.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2255.          IDS_CHIME_FILE_ERROR,                  /* ID of the message to show. */
  2256.          MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2257.             MB_MOVEABLE );                      /* Style of the message box.  */
  2258.    }
  2259.  
  2260.    /*
  2261.     * Close the file.
  2262.     */
  2263.    lMMIOResults =
  2264.       mmioClose(
  2265.          hmmioFileHandle,             /* Handle of the file to close.         */
  2266.          0 );                         /* No flags are used.                   */
  2267.  
  2268.    if ( lMMIOResults != MMIO_SUCCESS )
  2269.    {
  2270.       ShowAMessage(
  2271.          acStringBuffer[
  2272.             IDS_NORMAL_ERROR_MESSAGE_BOX_TEXT - 1 ],
  2273.          IDS_FAILED_MMIO_CLOSE,                 /* ID of the message to show. */
  2274.          MB_OK | MB_INFORMATION | MB_HELP | MB_APPLMODAL |
  2275.             MB_MOVEABLE );                      /* Style of the message box.  */
  2276.    }
  2277.  
  2278. }  /* End of CopyWaveformIntoMemory */
  2279.  
  2280.  
  2281. /******************************************************************************
  2282.  * Name        : LoadBellBitmaps
  2283.  *
  2284.  * Description : This procedure will load the bitmaps that are required to
  2285.  *               animate the bell.  The handle for each bitmap is stored in
  2286.  *               a global array for later use.
  2287.  *
  2288.  * Concepts    : None.
  2289.  *
  2290.  * MMPM/2 API's: None.
  2291.  *
  2292.  * Parameters  : None.
  2293.  *
  2294.  * Return      : None.
  2295.  *
  2296.  ******************************************************************************/
  2297. VOID LoadBellBitmaps( VOID )
  2298. {
  2299.    USHORT usBitmapIdCounter,     /* Bitmap id counter.                        */
  2300.           usCount;               /* Generic counter.                          */
  2301.  
  2302.    usBitmapIdCounter            = ID_CENTER_BELL;
  2303.  
  2304.    for( usCount=0; usCount<NUMBER_OF_BELL_BITMAPS; usCount++)
  2305.    {
  2306.       /*
  2307.        * Believe It or Not if the following sleep is not performed some of
  2308.        * the bitmaps will not be loaded and therefore the 'ringing' swing
  2309.        * of the bell will not work correctly.  Without the sleep some of
  2310.        * the bitmaps will not be loaded, i.e., every other one.
  2311.        */
  2312.       DosSleep( 300 );
  2313.  
  2314.       ahbmBellBitMaps[ usCount ] =
  2315.          GpiLoadBitmap(
  2316.             hps,
  2317.             (HMODULE) NULL,
  2318.             usBitmapIdCounter,
  2319.             (LONG) BELL_BITMAP_X_SIZE,
  2320.             (LONG) BELL_BITMAP_Y_SIZE );
  2321.  
  2322.       usBitmapIdCounter++;
  2323.  
  2324.    }  /* End of For loop to load the bitmaps. */
  2325.  
  2326. }  /* End of LoadBellBitmaps */
  2327.  
  2328.  
  2329. /******************************************************************************
  2330.  * Name        : SwingTheBell
  2331.  *
  2332.  * Description : This procedure will handle all of the processing that is
  2333.  *               required animate the bell bitmaps.  The bitmaps will be
  2334.  *               moved if the Closed Caption Flag is set to show a non-audio
  2335.  *               method of indicating sound.  The bells will be moved until
  2336.  *               the MCI Notify message is received by the message loop at
  2337.  *               which point a semaphore, hevContinueToSwingTheBell will
  2338.  *               be set so that the animation will stop.
  2339.  *
  2340.  *               This routine will be set up in a seperate thread to allow
  2341.  *               the main window procedure to continue processing message.
  2342.  *
  2343.  * Concepts    : None.
  2344.  *
  2345.  * MMPM/2 API's: None.
  2346.  *
  2347.  * Parameters  : None.
  2348.  *
  2349.  * Return      : None.
  2350.  *
  2351.  ******************************************************************************/
  2352. VOID SwingTheBell( VOID )
  2353. {
  2354.    USHORT usCount;            /* Generic counter.                             */
  2355.  
  2356.    while( DosWaitEventSem(
  2357.              hevContinueToSwingTheBell,
  2358.              SEM_INDEFINITE_WAIT ) ==  NO_ERROR )
  2359.    {
  2360.       for( usCount=0; usCount<NUMBER_OF_BELLS_IN_A_SWING; usCount++ )
  2361.       {
  2362.          /*
  2363.           * The important element in the next function call is how the
  2364.           * correct bitmap handle is picked.  This is done by using the
  2365.           * usCount value to index into the ausBellSwingOrder array. This
  2366.           * array has the order that the bitmaps are to be shown.  The
  2367.           * ausBellSwingOrder returns a value that indexes into the array
  2368.           * that contains the handle to the bitmaps.  This will indicate
  2369.           * which bitmap is to be drawn.
  2370.           */
  2371.  
  2372.         hbmBitmapToShow = ahbmBellBitMaps[ ausBellSwingOrder[ usCount ] ];
  2373.  
  2374.         WinInvalidateRect(
  2375.            hwndMainDialogBox,       /* Handle to the dialog box.              */
  2376.            &rctBitMapRectangle,     /* The area in the Pres. Space to update. */
  2377.            TRUE  );                 /* Do not bother child window.            */
  2378.  
  2379.         DosSleep( PAUSE_BETWEEN_BITMAPS );
  2380.  
  2381.       }  /* End of for loop. */
  2382.  
  2383.    }  /* End of while loop */
  2384.  
  2385.   DosExit(
  2386.      0,        /* Exit only from this thread leave other threads alone.       */
  2387.      0 );      /* Return value from the thread.                               */
  2388.  
  2389. } /* End of SwingTheBell */
  2390.