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