home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / source / mmpm2src / doubplay / doubplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-18  |  45.8 KB  |  1,161 lines

  1. /*******************************************************************************
  2.  * File Name   : DOUPLAY.C
  3.  *
  4.  * Description : This file contains the C source code required for the Double
  5.  *               Buffering Playlist sample program.  This sample allows
  6.  *               the user to play a wave file continuously by pushing the
  7.  *               play button.  The user can stop playing the wave file by
  8.  *               pushing the stop button.  Both of these push buttons are
  9.  *               animated.
  10.  *
  11.  * Concepts    : This program illustrates how to use a Memory
  12.  *               Playlist in a double buffering manner for reading and playing
  13.  *               a wave file at the same time.
  14.  *               This concept can be used in a lot of real time recording
  15.  *               applications such as:
  16.  *               1. Real Time recording and playing of the wave file
  17.  *               2. Censoring a Speech being transmitted.
  18.  *               The sample also shows how to use MMIO API's used in opening,
  19.  *               reading, seeking, and closing files.
  20.  *
  21.  * MMPM/2 API's: List of all MMPM/2 API's that are used in this module.
  22.  *
  23.  *               mciSendCommand
  24.  *                  MCI_ACQUIREDEVICE
  25.  *                  MCI_OPEN
  26.  *                  MCI_PLAY
  27.  *                  MCI_SET
  28.  *               mciGetErrorString
  29.  *               mmioOpen
  30.  *               mmioGetHeader
  31.  *               mmioRead
  32.  *               mmioSeek
  33.  *               mmioClose
  34.  *
  35.  * Required
  36.  *    Files    : doubplay.c         Source Code.
  37.  *               doubapp.c          Source Code.
  38.  *               doubplay.h         Include file.
  39.  *               doubapp.h          Include file.
  40.  *               doubplay.dlg       Dialog definition.
  41.  *               doubplay.rc        Resources.
  42.  *               doubplay.ipf       Help text.
  43.  *               makefile           Make file.
  44.  *               doubplay.def       Linker definition file.
  45.  *               doubplay.ico       Doubplay icon.
  46.  *               mywave.wav         Wave File Played.
  47.  *               play0.bmp          Play PushButton Bitmap 0
  48.  *               play1.bmp          Play PushButton Bitmap 1
  49.  *               play2.bmp          Play PushButton Bitmap 2
  50.  *               play3.bmp          Play PushButton Bitmap 3
  51.  *               play4.bmp          Play PushButton Bitmap 4
  52.  *               stop.bmp           Stop PushButton Bitmap
  53.  *
  54.  * Copyright (C) IBM  1993
  55.  ******************************************************************************/
  56.  
  57. #define  INCL_DOS                   /* required to use Dos APIs.           */
  58. #define  INCL_WIN                   /* required to use Win APIs.           */
  59. #define  INCL_PM                    /* required to use PM APIs.            */
  60. #define  INCL_OS2MM                 /* required for MCI and MMIO headers   */
  61. #define  INCL_WINHELP               /* required to use IPF.                */
  62. #define  INCL_WINSTDSLIDER          /* required for using slider control   */
  63. #define  INCL_SECONDARYWINDOW       /* required for secondary window       */
  64. #define  INCL_GRAPHICBUTTON         /* required for graphic button control */
  65.  
  66. #include <os2.h>
  67. #include <stdio.h>
  68. #include <os2me.h>
  69. #include <stdlib.h>
  70.  
  71. #include <sw.h>
  72.  
  73. #include "doubplay.h"               /* Dialog Ids, Resource Ids etc        */
  74. #include "doubapp.h"                /* application defined values          */
  75.  
  76.  
  77. #define HELP_FILE "DOUBPLAY.HLP"
  78. /*******************************************************************/
  79.  
  80. /* Procedure / Function prototypes */
  81.  
  82. #pragma linkage( MainDialogProc, system)
  83. MRESULT EXPENTRY MainDialogProc(HWND, ULONG, MPARAM, MPARAM);
  84. void main(int i,char *p[]);
  85. void InitializeDialog(void);
  86. void Finalize(void);
  87. void InitializePlayList();
  88. void OpenAudioDevice(HWND hwnd);
  89. VOID InitializeHelp( VOID );
  90. void CloseAll();
  91.  
  92. /*******************************************************************/
  93.  
  94. /* Global Variables */
  95.  
  96. HAB      hab;                                 /* anchor block handle         */
  97. QMSG     qmsg;                                /* Message Que                 */
  98. HMQ      hmq;
  99. HWND     hwndDiag;                            /* Application Dialog handle   */
  100. HWND     hwndFrame;                           /* Application Frame handle    */
  101. BOOL     fPassedDevice = FALSE;               /* Do we own the Audio device  */
  102. TID      PlayThreadId;                        /* Id for the PlayWave Thread  */
  103. USHORT   usWaveDeviceId;                      /* Id for the Wave Device      */
  104. CHAR     achDataBuffer[MAXBUFF][MAXSIZE];     /* Data Buffer which will hold */
  105.                                               /* wave for Memory Playlist    */
  106. CHAR     achHelpTitle[STRING_SIZE];           /* Title for the Help          */
  107. HMMIO    hmmioFileHandle;                     /* Handle to the Wave File     */
  108. LONG     lState = STATE_IS_STOP;              /* state of the application    */
  109.                                               /* Can be STOP or PLAYING      */
  110. HWND     hwndHelpInstance;                    /* Handle to Help window       */
  111. HELPINIT hmiHelpStructure;                    /* Help init. structure        */
  112. /*
  113.  * The Play List structure is an array of 2*MAXBUFF+2 number of items.
  114.  * This is because during initialization every even number i.e. 0, 2, 4
  115.  * etc is going to have the DATA instruction while every odd number i.e. 1,3,5
  116.  * is going to have the MESSAGE instruction.  The 2*MAXBUFF is going to contain
  117.  * the BRANCH instruction which will be dynamically modified to loop back to
  118.  * the first data instruction  when the Play pushbutton is used.
  119.  * When Stop push button is pressed this will be dynamically modifed to
  120.  * go to the EXIT instruction.
  121.  * The 2*MAXBUFF+1 is going to be contain the EXIT instruction.  When the
  122.  * BRANCH instruction is modified to loop to the EXIT instruction, the playing
  123.  * of the wave file will stop.
  124.  */
  125. PLAY_LIST_STRUCTURE_T aplayList[2*MAXBUFF+2]; /* Play List memory Structure  */
  126.  
  127. /******************************************************************************
  128.  * Name         : main
  129.  *
  130.  * Description  : This function calls the Intialize procedure to prepare
  131.  *                everything for the program's operation, enters the
  132.  *                message loop, then call Finalize to shut everything down
  133.  *                when the program is terminated.
  134.  *
  135.  * Concepts     : None.
  136.  *
  137.  * MMPM/2 API's : None.
  138.  *
  139.  * Parameters   : argc - Number of parameters passed into the program.
  140.  *                argv - Command line parameters.
  141.  *
  142.  * Return       : None.
  143.  *
  144.  *************************************************************************/
  145. void main(int argc, char *argv[])
  146. {
  147. InitializeDialog();
  148.  
  149. /* Handle the messages: */
  150. while(WinGetMsg(hab,&qmsg,0,0,0))
  151.         WinDispatchMsg(hab,&qmsg);
  152.  
  153. Finalize();
  154.  
  155. }
  156.  
  157. /*************************************************************************
  158.  * Name         : InitializeDialog
  159.  *
  160.  * Description  : This function performs the necessary initializations and
  161.  *                setups that are required to show/run a dialog box as a
  162.  *                main window.  The message queue will be created, as will
  163.  *                the dialog box.
  164.  *
  165.  * Concepts     : Secondary Windows is used to create and show a dialog box.
  166.  *                A system clock is displayed till the application is loaded.
  167.  *
  168.  * MMPM/2 API's : WinLoadSecondaryWindow
  169.  *                WinQuerySecondaryHWND
  170.  *
  171.  * Parameters   : None.
  172.  *
  173.  * Return       : None.
  174.  *
  175.  *************************************************************************/
  176. void InitializeDialog()
  177. {
  178. CHAR achTitle[STRING_SIZE] = "";
  179. CHAR achDefaultSize[STRING_SIZE] = "";
  180.  
  181.  
  182.    /*
  183.     * Setup and initialize the dialog window.
  184.     * Change pointer to a waiting pointer first, since this might take a
  185.     * couple of seconds.
  186.     */
  187.  
  188.  
  189.    WinSetPointer(
  190.       HWND_DESKTOP,        /* Desktop window handle.                    */
  191.       WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  192.          HWND_DESKTOP,     /* Desktop window handle.                    */
  193.          SPTR_WAIT,        /* The waiting icon.                         */
  194.          FALSE ) );        /* Return the system pointer's handle.       */
  195.  
  196.    /* Initialize the Dialog window */
  197.    hab = WinInitialize(0);
  198.  
  199.    /* create a message queue for the window */
  200.    hmq = WinCreateMsgQueue(hab,0);
  201.  
  202.  
  203.  
  204.    /* Load the Dialog - This will return the Handle to the Frame */
  205.    hwndFrame =
  206.        WinLoadSecondaryWindow(HWND_DESKTOP
  207.                             ,HWND_DESKTOP
  208.                             ,(PFNWP)MainDialogProc
  209.                             ,(HMODULE)NULL
  210.                             ,ID_SAMPLE
  211.                             ,(PVOID)NULL);
  212.  
  213.  
  214.    /*
  215.     * By specifying the QS_DIALOG flag we will get the handle to the Dialog of
  216.     * the frame
  217.     */
  218.    hwndDiag = WinQuerySecondaryHWND(hwndFrame,QS_DIALOG);
  219.  
  220.    /* Get the string for default size */
  221.    WinLoadString(
  222.       hab,
  223.       (HMODULE) NULL,
  224.       IDS_DEFAULT_SIZE,
  225.       (SHORT) sizeof( achDefaultSize),
  226.       achDefaultSize);
  227.    /* Add Default Size menu item to system menu of the secondary window. */
  228.    WinInsertDefaultSize(hwndFrame, achDefaultSize);
  229.  
  230.    /*
  231.     * Get the window title string from the Resource string table
  232.     * and set it as the window text for the dialog window.
  233.     */
  234.    WinLoadString(
  235.       hab,
  236.       (HMODULE) NULL,
  237.       IDS_MAIN_WINDOW_TITLE,
  238.       (SHORT) sizeof( achTitle),
  239.       achTitle);
  240.  
  241.    /* Set the Title of the Dialog */
  242.    WinSetWindowText( hwndFrame, achTitle);
  243.  
  244.  
  245.    /*
  246.     * Now that we're done with initialization, so we don't the need the waiting
  247.     * icon, so we are going to change the pointer back to the arrow.
  248.     */
  249.  
  250.    WinSetPointer(
  251.       HWND_DESKTOP,        /* Desktop window handle.                    */
  252.       WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  253.          HWND_DESKTOP,     /* Desktop window handle.                    */
  254.          SPTR_ARROW,       /* The Arrow icon.                           */
  255.          FALSE ) );        /* Return the system pointer's handle.       */
  256.  
  257.    /*
  258.     * Initialize the help structure and associate the help instance to this
  259.     * dialog via it's handle to anchor block.
  260.     */
  261.  
  262.    InitializeHelp( );
  263.  
  264. }
  265.  
  266. /******************************************************************************
  267.  * Name         : CloseAll
  268.  *
  269.  * Description  : This function is called when the current Thread finishes
  270.  *                execution and is placed in DosExitList during the WM_INITDLG
  271.  *                message.  This function allows to terminate itself and all
  272.  *                of its children processes.
  273.  *
  274.  * Concepts     : None.
  275.  *
  276.  * MMPM/2 API's : None.
  277.  *
  278.  * Parameters   : None
  279.  *
  280.  * Return       : None.
  281.  *
  282.  *************************************************************************/
  283. void CloseAll()
  284. {
  285.      DosExit(EXIT_PROCESS, 0);
  286.      DosExitList(EXLST_EXIT, NULL);
  287. }
  288. /******************************************************************************
  289.  * Name        : InitializeHelp
  290.  *
  291.  * Description : This procedure will set up the initial values in the global
  292.  *               help structure.  This help structure will then be passed on
  293.  *               to the Help Manager when the Help Instance is created.  The
  294.  *               handle to the Help Instance will be kept for later use.
  295.  *
  296.  * Concepts    : None.
  297.  *
  298.  * MMPM/2 API's: None.
  299.  *
  300.  * Parameters  : None.
  301.  *
  302.  * Return      : None.
  303.  *
  304.  ******************************************************************************/
  305. VOID InitializeHelp( VOID )
  306. {
  307.    /*  Get the size of the initialization structure. */
  308.    hmiHelpStructure.cb              = sizeof( HELPINIT );
  309.  
  310.    hmiHelpStructure.ulReturnCode    = (ULONG) NULL; /* RC from initialization.*/
  311.    hmiHelpStructure.pszTutorialName = (CHAR) NULL;  /* No tutorial program.   */
  312.  
  313.    hmiHelpStructure.phtHelpTable    = (PVOID)(0xffff0000 | ID_DOUBPLAY_HELPTABLE);
  314.  
  315.    /* The action bar is not used, so set the following to NULL. */
  316.    hmiHelpStructure.hmodAccelActionBarModule = (HMODULE) NULL;
  317.    hmiHelpStructure.idAccelTable             = (USHORT) NULL;
  318.    hmiHelpStructure.idActionBar              = (USHORT) NULL;
  319.  
  320.    /* The Help window title. */
  321.    WinLoadString(
  322.       hab,                             /* HAB for this dialog box.            */
  323.       (HMODULE) NULL,                  /* Get the string from the .exe file.  */
  324.       IDS_HELP_WINDOW_TITLE,           /* Which string to get.                */
  325.       (SHORT) STRING_SIZE,             /* The size of the buffer.             */
  326.       achHelpTitle );                  /* The buffer to place the string.     */
  327.  
  328.    hmiHelpStructure.pszHelpWindowTitle  =
  329.       achHelpTitle;
  330.  
  331.    /* The Help table is in the executable file. */
  332.    hmiHelpStructure.hmodHelpTableModule = (HMODULE) NULL;
  333.  
  334.    /* The help panel ID is not displayed. */
  335.    hmiHelpStructure.fShowPanelId       = (ULONG) NULL;
  336.  
  337.    /* The library that contains the Double Buffering help panels. */
  338.    hmiHelpStructure.pszHelpLibraryName  = HELP_FILE;
  339.  
  340.    /*
  341.     * Create the Help Instance for IPF.
  342.     * Give IPF the Anchor Block handle and address of the IPF initialization
  343.     * structure, and check that creation of Help was a success.
  344.     */
  345.    hwndHelpInstance = WinCreateHelpInstance(
  346.                          hab,                   /* Anchor Block Handle.       */
  347.                          &hmiHelpStructure );   /* Help Structure.            */
  348.  
  349.    if ( hwndHelpInstance == (HWND) NULL )
  350.    {
  351.      ShowAMessage(
  352.            IDS_ERROR_TITLE,
  353.            IDS_HELP_CREATION_ERROR,
  354.            MB_OK | MB_INFORMATION | MB_MOVEABLE |  MB_APPLMODAL ,
  355.            FALSE);
  356.    }
  357.    else
  358.    {
  359.       if ( hmiHelpStructure.ulReturnCode )
  360.       {
  361.        ShowAMessage(
  362.            IDS_ERROR_TITLE,
  363.            IDS_HELP_CREATION_ERROR,
  364.            MB_OK | MB_INFORMATION | MB_MOVEABLE |  MB_APPLMODAL ,
  365.            FALSE);
  366.  
  367.       WinDestroyHelpInstance( hwndHelpInstance );
  368.       }
  369.    }  /* End of IF checking the creation of the Help Instance. */
  370.  
  371.    /* Associate the Help Instance of the IPF to this dialog window. */
  372.    if ( hwndHelpInstance != (HWND) NULL )
  373.    {
  374.      WinAssociateHelpInstance(
  375.         hwndHelpInstance,     /* The handle of the Help Instance.             */
  376.         hwndFrame );          /* Associate to this dialog window.             */
  377.    }
  378.  
  379. }  /* End of InitializeHelp */
  380.  
  381. /*************************************************************************
  382.  * Name         : Finalize
  383.  *
  384.  * Description  : This routine is called after the message dispatch loop
  385.  *                has ended because of a WM_QUIT message.  The code will
  386.  *                destroy the help instance, messages queue, and window.
  387.  *
  388.  * Concepts     : None.
  389.  *
  390.  * MMPM/2 API's : None.
  391.  *
  392.  * Parameters   : None.
  393.  *
  394.  * Return       : None.
  395.  *
  396.  *************************************************************************/
  397. VOID Finalize( VOID )
  398. {
  399.    /* Destroy the Help Instance for this dialog window. */
  400.    if ( hwndHelpInstance != (HWND) NULL)
  401.    {
  402.       WinDestroyHelpInstance( hwndHelpInstance );
  403.    }
  404.  
  405.    WinDestroySecondaryWindow( hwndFrame );
  406.    WinDestroyMsgQueue( hmq );
  407.    WinTerminate( hab );
  408.  
  409. }  /* End of Finalize */
  410. /*******************************************************************************
  411.  * Name        : MainDialogProc
  412.  *
  413.  * Description : This function controls the main dialog box.  It will handle
  414.  *               received messages such as pushbutton notifications, playlist
  415.  *               messages, etc
  416.  *
  417.  *               The following messages are handled specifically by this
  418.  *               routine.
  419.  *
  420.  *                  WM_INITDLG
  421.  *                  WM_CLOSE
  422.  *                  WM_HELP
  423.  *                  WM_COMMAND
  424.  *                  MM_MCIPLAYLISTMESSAGE
  425.  *                  MM_MCIPASSDEVICE
  426.  *                  WM_ACTIVATE
  427.  *
  428.  *
  429.  * Concepts    : The MM_MCIPLAYLISTMESSAGE message is used to indicate when
  430.  *               a data buffer of the playlist is finished processing.  At this
  431.  *               time the wave file is read into the buffer number passed in.
  432.  *               Wave is being constantly read into the data buffer of the play
  433.  *               list (when the playlist message is received) while the wave is
  434.  *               constantly being played by the other thread thus illustrating
  435.  *               the double buffering concept of the playlist.   This concept
  436.  *               can be used in a lot of real time recording applications as:
  437.  *               1. Real Time recording and playing of the wave file
  438.  *               2. Censoring a Speech being transmitted.
  439.  *               A separate thread is created to play the wave file.  This
  440.  *               thread sends messages to the MainDialogProc after it has
  441.  *               finished playing every DATA instruction for reading more of
  442.  *               the wave file into the buffer.
  443.  *               Also, the dynamic modification of a memory playlist's branch
  444.  *               instruction is illustrated when the STOP and PLAY pushbuttons
  445.  *               are pressed.
  446.  *
  447.  *
  448.  *
  449.  *
  450.  * MMPM/2 API's : mciSendCommand
  451.  *                   MCI_ACQUIREDEVICE
  452.  *                mmioClose
  453.  *                mmioRead
  454.  *                mmioSeek
  455.  *
  456.  * Parameters   : hwnd - Handle for the Main dialog box.
  457.  *                msg  - Message received by the dialog box.
  458.  *                mp1  - Parameter 1 for the just recieved message.
  459.  *                mp2  - Parameter 2 for the just recieved message.
  460.  *
  461.  * Return       :
  462.  *
  463.  *
  464.  ******************************************************************************/
  465. MRESULT EXPENTRY MainDialogProc(
  466.                 HWND hwnd,
  467.                  ULONG msg,
  468.                  MPARAM mp1,
  469.                  MPARAM mp2)
  470. {
  471. static MCI_GENERIC_PARMS  lpWaveGeneric; /* Used for MCI_ACQUIREDEVICE      */
  472. ULONG                     ulReturn;      /* Ret Code for Dos and MCI calls  */
  473. ULONG                     ulBufferNum;   /* index to read the wave into     */
  474. ULONG                     ulBytesRead;   /* Number of bytes read from wave  */
  475. USHORT                    usNotifyCode;
  476. USHORT                    usUserParm;
  477. USHORT                    usCommandMessage; /* high-word */
  478.  
  479.  
  480.  
  481. switch (msg)
  482.   {
  483.  
  484.    /*
  485.     * This message is recieved when the DataBuffer index number ulBufferNum
  486.     * is just finished playing.  Now, the next MAXSIZE of the wave file is
  487.     * going to be recorded into this buffer number.  This new part of the wave
  488.     * file which is read will be played during the next BRANCH iteration.
  489.     * MM_MCIPLAYLISTMESSAGE indicates that the bufferno ulBufferNum is finished
  490.     * playing, so read the next part of the wave file into the buffer.
  491.     */
  492.  
  493.     case MM_MCIPLAYLISTMESSAGE:
  494.        /*
  495.         * The Buffer Number has just finished playing, so refill the buffer
  496.         * for next loop.  Remeber only the buffer which has finished playing
  497.         * should be filled compared to the next buffer or so on because some
  498.         * data may be lost otherwise.
  499.         */
  500.  
  501.        /* Extract the Buffer Number which was just played */
  502.        ulBufferNum = (ULONG) mp2;
  503.  
  504.        /* Read the Next MAXSIZE bytes of the wave file */
  505.        ulBytesRead =
  506.               mmioRead(hmmioFileHandle,
  507.                        (HPSTR) achDataBuffer[ulBufferNum],
  508.                        MAXSIZE);
  509.  
  510.        /*
  511.         * If we have reached the end of the wave file then set the file marker
  512.         * to the begining of the file and start reading into the bufferno.
  513.         * This causes the continuous filling and playing of the data buffer
  514.         * again and again as long as the END push button is not pressed.
  515.         * The wave file is going to keep on playing without any interruptions
  516.         * as long as the BRANCH instruction is not modified.
  517.         */
  518.        if (ulBytesRead == 0)
  519.          {
  520.           /* Seek to the starting of the wave file */
  521.           mmioSeek(hmmioFileHandle, 0, SEEK_SET);
  522.  
  523.           /* Read the Next MAXSIZE bytes of the wave file */
  524.           ulBytesRead =
  525.                  mmioRead(hmmioFileHandle,
  526.                          (HPSTR) achDataBuffer[ulBufferNum],
  527.                          MAXSIZE);
  528.          }
  529.        return ((MRESULT) NULL);
  530.  
  531.  
  532.     case WM_CLOSE:
  533.        WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  534.        return ((MRESULT) NULL);
  535.  
  536.     case WM_HELP :
  537.        /*
  538.         * The dialog window has recieved a request for help from the user,
  539.         * i.e., the Help pushbutton was pressed.  Send the HM_DISPLAY_HELP
  540.         * message to the Help Instance with the IPF resource identifier
  541.         * for the correct HM panel.  This will show the help panel for this
  542.         * sample program.
  543.         */
  544.        WinSendMsg(
  545.           hwndHelpInstance,
  546.           HM_DISPLAY_HELP,
  547.           MPFROMSHORT( 1 ),
  548.           MPFROMSHORT( HM_RESOURCEID ) );
  549.        return( 0 );
  550.  
  551.     case WM_INITDLG:
  552.        /*
  553.         * Put the Playlist Instructions into the Playlist structure.
  554.         * Every even subscipt (0,2,4 etc) gets the DATA_OPERATION instruction
  555.         * and every odd subscript (1,3,5 etc) gets the MESSAGE_OPERATION
  556.         * instruction.  After every DATA_OPERATION instruction is executed
  557.         * a message is given to the application and the wave file is read again
  558.         * into the data buffer
  559.         */
  560.        InitializePlayList();
  561.  
  562.        /* Opens the Audio device for playlist */
  563.        OpenAudioDevice(hwnd);
  564.        /*
  565.         * Since the play button is an animated button, we need to initialize it
  566.         */
  567.        WinSendMsg (
  568.            WinWindowFromID(
  569.                 hwnd,             /* Dialog window handle             */
  570.                 ID_PLAY),         /* Id - Play graphic button         */
  571.            GBM_SETANIMATIONRATE,  /* Animation rate control           */
  572.            MPFROMLONG(100L),      /* Update play bitmap every .1 sec  */
  573.            NULL);                 /* Ignore return data               */
  574.  
  575.        /*
  576.         * Place function CloseAll in exit list because in order to play
  577.         * we have to create another thread and when we terminate we want
  578.         * to stop all child processes.
  579.         */
  580.  
  581.        DosExitList(EXLST_ADD,(PFNEXITLIST) CloseAll);
  582.  
  583.        return((MRESULT)NULL);
  584.  
  585.     /*  Service all of the button pushes */
  586.     case WM_COMMAND:
  587.        switch (SHORT1FROMMP(mp1)) {
  588.          case ID_END:
  589.            /* If we are playing the playlist only then stop it */
  590.            if (lState == STATE_IS_PLAYING)
  591.               {
  592.               /*
  593.                * When the stop button is pushed, then we are going to modify
  594.                * BRANCH_INSTRUCTION and make it branch to the EXIT_INSTRUCTION
  595.                * When the BRANCH instruction is going to be encountered instead
  596.                * of looping back to the DATA instruction, we are going to go to
  597.                * EXIT instruction which will cause the wave to stop playing.
  598.                * Till the BRANCH instruction is encountered the buffer will keep
  599.                * on filling and the wave will keep on playing.
  600.                * This is the reason why there may be a delay between pushing the
  601.                * STOP button and time it takes for the wave to stop playing.
  602.                * So here we dynamically modify operand of BRANCH instruction
  603.                * (2*MAXBUFF index) to go to EXIT instruction (2*MAXBUFF+1)
  604.                * instead of looping back to the first DATA instruction.
  605.                * For a more detailed description on playlist instructions
  606.                * refer to the MMPM/2 programming guide.
  607.                */
  608.  
  609.               aplayList[2*MAXBUFF].ulOperandTwo = 2*MAXBUFF+1;
  610.  
  611.               /* Wait for the PlayThreadId to end */
  612.               DosWaitThread(&PlayThreadId, DCWW_WAIT);
  613.  
  614.               }
  615.           break;
  616.  
  617.  
  618.          case ID_PLAY:
  619.            /* If we are not playing the playlist only then Play it */
  620.            if (lState == STATE_IS_STOP)
  621.               {
  622.               if (fPassedDevice)
  623.                  {
  624.                  /*
  625.                   * If we don't have the device then display a message.
  626.                   * FALSE is passed because this is not a MCI error.
  627.                   */
  628.  
  629.                   ShowAMessage(
  630.                        IDS_ERROR_TITLE,
  631.                        IDS_CANT_PROCESS_MESSAGE,
  632.                        MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  633.                        MB_APPLMODAL ,
  634.                        FALSE);
  635.                  }
  636.               else
  637.                  {
  638.                  /*
  639.                   * We have the device so no problem.
  640.                   * Modify the operand of the LOOP instruction to loop back
  641.                   * to the first DATA instruction so the wave file can be
  642.                   * played continuously without any interruptions.  When we
  643.                   * want the wave to stop playing then we will modify this
  644.                   * instruction again
  645.                   */
  646.                   aplayList[2*MAXBUFF].ulOperandTwo = 0;
  647.  
  648.                   /*
  649.                    * Create a thread called PlayTheWave which will start
  650.                    * playing the wave file and send messages to this Dialog
  651.                    * procedure
  652.                    */
  653.  
  654.                   PlayThreadId =
  655.                      _beginthread(
  656.                                   PlayTheWave,
  657.                                   NULL,
  658.                                   16384,
  659.                                   NULL);
  660.  
  661.  
  662.  
  663.                  }
  664.               }
  665.            break;
  666.  
  667.        }
  668.        return((MRESULT)NULL);
  669.        break;
  670.  
  671.     /*
  672.      * The next two messages are handled so that the Double Buffering
  673.      * application can participate in device sharing.  Since it opens
  674.      * the devices as shareable devices, other applications can gain
  675.      * control of the devices.  When this happens, we will receive a
  676.      * pass device message.  We keep track of this device passing in
  677.      * the fPassedDevice boolean variable.
  678.      *
  679.      * fPassedDevice will be TRUE if we don't have the device and will
  680.      * be FALSE
  681.      *
  682.      * If we do not have access to the device when we receive an activate
  683.      * message, then we will issue an acquire device command to gain
  684.      * access to the device.
  685.      */
  686.  
  687.     case MM_MCIPASSDEVICE:
  688.        if (SHORT1FROMMP(mp2) == MCI_GAINING_USE)
  689.           {
  690.           /* Have gained use of the Audio Device so update the flag */
  691.           fPassedDevice = FALSE;
  692.  
  693.           if (lState == STATE_IS_PLAYING) {   /* If the duet was playing     */
  694.              WinSendMsg(                      /* Start Play button animation */
  695.                  WinWindowFromID (
  696.                       hwnd,                   /* Dialog window handle        */
  697.                       ID_PLAY),               /* Id - Play graphic button    */
  698.                  GBM_ANIMATE,                 /* Animation control           */
  699.                  MPFROMSHORT(TRUE),           /* Animation flag              */
  700.                  NULL);                       /* Ignore return data          */
  701.               }
  702.            }
  703.        else
  704.           {
  705.           /* Have lost use of the Audio Device so update the flag */
  706.           fPassedDevice = TRUE;
  707.  
  708.           if (lState == STATE_IS_PLAYING) {   /* If the duet was playing     */
  709.              WinSendMsg(                      /* Stop Play button animation  */
  710.                  WinWindowFromID (
  711.                        hwnd,                  /* Dialog window handle        */
  712.                        ID_PLAY),              /* Id - Play graphic button    */
  713.                  GBM_ANIMATE,                 /* Animation control           */
  714.                  MPFROMSHORT(FALSE),          /* Animation flag              */
  715.                  NULL);                       /* Ignore return data          */
  716.              }
  717.           }
  718.        break;
  719.  
  720.  
  721.       case MM_MCINOTIFY:
  722.          usNotifyCode = (USHORT) SHORT1FROMMP( mp1);
  723.          usUserParm  = (USHORT) SHORT2FROMMP( mp1);
  724.  
  725.          usCommandMessage = (USHORT) SHORT2FROMMP( mp2); /* high-word */
  726.  
  727.          switch (usCommandMessage)
  728.          {
  729.             case MCI_PLAY:
  730.                switch (usNotifyCode)
  731.                {
  732.                   case MCI_NOTIFY_SUCCESSFUL:
  733.                      if (lState != STATE_IS_STOP)
  734.                      {
  735.                         /*
  736.                         * We will receive the MCI_NOTIFY_SUCCESSFUL message
  737.                         * so we need to be sure to only take this action if
  738.                         * the state is not stopped.  That's why we are
  739.                         * checking the lState and then immediately setting it
  740.                         * to STATE_IS_STOP.
  741.                         */
  742.                         lState = STATE_IS_STOP;
  743.                         /* Disables the animation of the Play button */
  744.                         WinSendMsg (
  745.                            WinWindowFromID(
  746.                              hwnd,            /* Dialog window handle        */
  747.                              ID_PLAY),        /* Id - Play graphic button    */
  748.                            GBM_ANIMATE,       /* Animation control           */
  749.                            MPFROMSHORT(FALSE),/* Animation flag              */
  750.                            NULL);             /* Ignore return data          */
  751.  
  752.                         /* Close the Wave file */
  753.                         ulReturn =
  754.                              mmioClose(hmmioFileHandle, (USHORT) NULL);
  755.                        if (ulReturn != 0)
  756.                           {
  757.                          /*
  758.                           * This is an MCI Error so show the message by
  759.                           * passing TRUE
  760.                           */
  761.                          ShowAMessage(
  762.                              IDS_ERROR_TITLE,
  763.                              ulReturn,
  764.                              MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  765.                              MB_APPLMODAL,
  766.                              TRUE);
  767.                            }
  768.  
  769.                      }
  770.                      break;
  771.  
  772.                   case MCI_NOTIFY_SUPERSEDED:
  773.                   case MCI_NOTIFY_ABORTED:
  774.                      /* we don't need to handle these messages. */
  775.                      break;
  776.  
  777.                   default:
  778.                      /*
  779.                       * If the message is none of the above, then it must be
  780.                       * a notification error message.
  781.                       */
  782.                     ShowAMessage(
  783.                         IDS_ERROR_TITLE,
  784.                         usNotifyCode,
  785.                         MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  786.                         MB_APPLMODAL,
  787.                         TRUE);
  788.  
  789.                         lState = STATE_IS_STOP;
  790.                         /* Disables the animation of the Play button */
  791.                         WinSendMsg (
  792.                            WinWindowFromID(
  793.                              hwnd,            /* Dialog window handle        */
  794.                              ID_PLAY),        /* Id - Play graphic button    */
  795.                            GBM_ANIMATE,       /* Animation control           */
  796.                            MPFROMSHORT(FALSE),/* Animation flag              */
  797.                            NULL);             /* Ignore return data          */
  798.  
  799.                      break;
  800.  
  801.                }
  802.                break;
  803.          }
  804.          return( (MRESULT) 0);
  805.  
  806.     /*
  807.      * We use the WM_ACTIVATE message to participate in device sharing.
  808.      * We first check to see if this is an activate or a deactivate
  809.      * message (indicated by mp1). Then, we check to see if we've passed
  810.      * control of the device that we use.  If these conditions are true,
  811.      * then we issue an acquire device command to regain control of the
  812.      * device, since we're now the active window on the screen.
  813.      *
  814.      * This is one possible method that can be used to implement
  815.      * device sharing. For applications that are more complex
  816.      * than this sample program, developers may wish to take
  817.      * advantage of a more robust method of device sharing.
  818.      * This can be done by using the MCI_ACQUIRE_QUEUE flag on
  819.      * the MCI_ACQUIREDEVICE command.  Please refer to the MMPM/2
  820.      * documentation for more information on this flag.
  821.      */
  822.     case WM_ACTIVATE:
  823.        /* First we check to see if we've passed control of the device */
  824.        if ((BOOL)mp1 && fPassedDevice == TRUE)
  825.           {
  826.           lpWaveGeneric.hwndCallback =   hwnd;
  827.           ulReturn = mciSendCommand( usWaveDeviceId,
  828.                                      MCI_ACQUIREDEVICE,
  829.                                      (ULONG)MCI_WAIT,
  830.                                      (PVOID)&lpWaveGeneric,
  831.                                      (USHORT)NULL );
  832.           if (ulReturn != 0)
  833.              {
  834.              /* This is an MCI Error so show the message by passing TRUE */
  835.              ShowAMessage(
  836.                      IDS_ERROR_TITLE,
  837.                      ulReturn,
  838.                      MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  839.                      MB_APPLMODAL,
  840.                      TRUE);
  841.              }
  842.  
  843.           }
  844.        return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  845.  
  846.      /*
  847.       * This is an application defined message.  This message is received
  848.       * from the PlayTheWave thread when the mmioOpen, MCI_SET or MCI_PLAY is
  849.       * not successfull
  850.       */
  851.      case WM_PLAYFAILED:
  852.  
  853.          ShowAMessage(
  854.                       IDS_ERROR_TITLE,
  855.                       LONGFROMMP(mp1),
  856.                       MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  857.                       MB_APPLMODAL,
  858.                       (BOOL) LONGFROMMP(mp2));
  859.          break;
  860.      /*
  861.       * If MCI_PLAY is successful then PlayTheWave thread sends us a message
  862.       * indicating that the playing of the wave file has started, so that we
  863.       * can start the animation of the play button and update the state of the
  864.       * application
  865.       */
  866.      case WM_PLAYSTARTED:
  867.             /*
  868.              * The MCI_PLAY was successful and the thread send us a message
  869.              * that the Playing of the wave file has started, so enable the
  870.              * animation  of the button
  871.              */
  872.              WinSendMsg (
  873.                WinWindowFromID(
  874.                  hwnd,             /* Dialog window handle      */
  875.                  ID_PLAY),         /* Id - Play graphic button  */
  876.                GBM_ANIMATE,        /* Animation control         */
  877.                MPFROMSHORT(TRUE),  /* Animation flag            */
  878.                NULL);              /* Ignore return data        */
  879.  
  880.              /* Update the State of the application */
  881.              lState = STATE_IS_PLAYING;
  882.  
  883.          break;
  884.  
  885.        default:
  886.           return ( WinDefDlgProc( hwnd, msg, mp1, mp2 ) );
  887.     }
  888. }
  889.  
  890.  
  891.  
  892. /******************************************************************************
  893.  * Name        : InitializePlayList
  894.  *
  895.  * Description : This procedure will initialize the playlist structure with
  896.  *               playlist instructions.
  897.  *               Every even number of the playlist structure subscript contains
  898.  *               a DATA_INSTRUCTION.  Operand One of the data instruction
  899.  *               is pointing to the pre-allocated buffer where the wave file
  900.  *               will be copied into.  Operand two of the data instruction
  901.  *               contains the maximum size of the buffer.
  902.  *               Every odd number of the playlist structure subscript contains
  903.  *               a MESSAGE_INSTRUCTION.  Operand two of the message
  904.  *               instruction contains the Number to return to the application.
  905.  *               Operand one and Operand three for message instruction are
  906.  *               ignored.
  907.  *               After every DATA_OPERATION instruction is executed a message
  908.  *               is sent to the application about the bufferno (subscript) it
  909.  *               just finished playing.  At this time the wave file is read
  910.  *               into the Data buffer.  The playing of the wave file thus
  911.  *               continues without any interruption.
  912.  *               Second to Last instruction in the playlist structure
  913.  *               (2*MAXBUFF) is the BRANCH_OPERATION which is initialized
  914.  *               to go to the next instruction (2*MAXBUFF+1) which is the
  915.  *               EXIT_OPERATION.
  916.  *               When the play pushbutton is pressed, the BRANCH instruction
  917.  *               is dynamically modified to go to the first DATA instruction
  918.  *               so the wave can play continuously in loops.
  919.  *               In order to stop playing the play list the operand of the
  920.  *               BRANCH_OPERATION is simply changed to the EXIT_OPERATION in
  921.  *               the routine.
  922.  *
  923.  *
  924.  * Concepts    : Initialize the memory playlist data structure.
  925.  *
  926.  * MMPM/2 API's: None.
  927.  *
  928.  * Parameters  : None.
  929.  *
  930.  * Return      : None.
  931.  *
  932.  *************************************************************************/
  933.  void InitializePlayList()
  934.  {
  935.  ULONG ulNumber;
  936.  
  937.       for (ulNumber=0; ulNumber<MAXBUFF; ulNumber++)
  938.         {
  939.          /*
  940.           * every 0, 2, 4, 6 etc index of the playlist contains the
  941.           * DATA instruction.  Operand one contains the buffer of the data
  942.           * Operand two contains the maxmimum size for the data buffer.
  943.           * Operand three is ignored.
  944.           */
  945.          aplayList[2*ulNumber].ulCommand = DATA_OPERATION;
  946.          aplayList[2*ulNumber].ulOperandOne = (ULONG) achDataBuffer[ulNumber];
  947.          aplayList[2*ulNumber].ulOperandTwo = (ULONG) MAXSIZE;
  948.          aplayList[2*ulNumber].ulOperandThree = (ULONG) 0;
  949.  
  950.          /*
  951.           * every 1, 3, 5, 7 etc index of the playlist contains the
  952.           * MESSAGE instruction.  Operand two contains the buffer number
  953.           * which will be returned to the application.
  954.           * Operand one and three are ignored.
  955.           */
  956.          aplayList[2*ulNumber+1].ulCommand = (ULONG) MESSAGE_OPERATION;
  957.          aplayList[2*ulNumber+1].ulOperandTwo = (ULONG) ulNumber;
  958.          aplayList[2*ulNumber+1].ulOperandOne = (ULONG) 0;
  959.          aplayList[2*ulNumber+1].ulOperandThree = (ULONG) 0;
  960.         } /* endfor */
  961.  
  962.       /*
  963.        * Initialize the BRANCH_OPEATION to loop to the last EXIT Operation
  964.        * Instruction.  This will be dynamically modified when the play
  965.        * push button is pressed.
  966.        */
  967.       aplayList[2*MAXBUFF].ulCommand = BRANCH_OPERATION;
  968.       aplayList[2*MAXBUFF].ulOperandOne = (ULONG) 2*MAXBUFF+1;
  969.       aplayList[2*MAXBUFF].ulOperandThree = (ULONG) 2*MAXBUFF+1;
  970.       aplayList[2*MAXBUFF].ulOperandTwo = 0;
  971.  
  972.       aplayList[2*MAXBUFF+1].ulCommand = EXIT_OPERATION;
  973.       aplayList[2*MAXBUFF+1].ulOperandOne =  (ULONG) 0;
  974.       aplayList[2*MAXBUFF+1].ulOperandTwo =  (ULONG) 0;
  975.       aplayList[2*MAXBUFF+1].ulOperandThree = (ULONG) 0;
  976.  
  977. }
  978.  
  979. /******************************************************************************
  980.  * Name        : OpenAudioDevice
  981.  *
  982.  * Description : This procedure will open the device for Playlist.
  983.  *
  984.  *
  985.  * Concepts    : How to Open a Device to play a wave file from Playlist.
  986.  *
  987.  * MMPM/2 API's:  mciSendCommand         MCI_OPEN
  988.  *
  989.  * Parameters  : None.
  990.  *
  991.  * Return      : None.
  992.  *
  993.  *************************************************************************/
  994.  
  995. void  OpenAudioDevice(HWND hwnd)
  996. {
  997.  
  998. MCI_OPEN_PARMS          lpWaveOpen;        /* Used for MCI_OPEN messages */
  999. ULONG                   ulReturn;          /* Used for ret code for API  */
  1000.  
  1001.  
  1002.    /*
  1003.     * Initialize the MCI_OPEN_PARMS data structure with hwndMainDialogBox
  1004.     * as callback handle for MM_MCIPASSDEVICE, then issue the MCI_OPEN
  1005.     * command with the mciSendCommand function.  No alias is used.
  1006.     */
  1007.  
  1008.    lpWaveOpen.hwndCallback       =  hwnd;
  1009.    lpWaveOpen.pszAlias       = (PSZ) NULL;
  1010.  
  1011.  
  1012.    /*
  1013.     * Open the correct waveform device with the MCI_OPEN message to MCI.
  1014.     * Use 0 instead of 1 because this will then use the default audio device.
  1015.     */
  1016.    lpWaveOpen.pszDeviceType  =
  1017.          (PSZ) (MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,0));
  1018.  
  1019.    /*
  1020.     * The address of the buffer which will record and play the wave.
  1021.     */
  1022.    lpWaveOpen.pszElementName = (PSZ) &aplayList[0];
  1023.  
  1024.  
  1025.    /*
  1026.     * Open the waveform file in the playlist mode.
  1027.     */
  1028.    ulReturn =
  1029.        mciSendCommand(0,
  1030.                       MCI_OPEN,
  1031.                       MCI_WAIT | MCI_OPEN_PLAYLIST |
  1032.                       MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
  1033.                       (PVOID) &lpWaveOpen,
  1034.                       (USHORT) NULL);
  1035.  
  1036.    if (ulReturn != 0)
  1037.       {
  1038.       /* MCI Open was not successfull so show a message by passing a TRUE */
  1039.        ShowAMessage(
  1040.              IDS_ERROR_TITLE,
  1041.              ulReturn,
  1042.              MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP | MB_APPLMODAL,
  1043.              TRUE);
  1044.       }
  1045.  
  1046.    /* Save the Device Id in the global variable to be used later */
  1047.    usWaveDeviceId = lpWaveOpen.usDeviceID;
  1048. }
  1049.  
  1050.  
  1051. /******************************************************************************
  1052.  * Name        : ShowAMessage
  1053.  *
  1054.  * Description : This function will show text in a message box.
  1055.  *               If the Message is an MCI Error then the text is pulled
  1056.  *               by issuing a mciGetErrorString.  The text is retrieved by the
  1057.  *               Return code of the mci call which failed.
  1058.  *               If the Message is not an MCI Error then the text
  1059.  *               is pulled from the string table that is originally kept
  1060.  *               in the resource file .  The text is retrieved by the
  1061.  *               message id that is passed into this function.  This id is
  1062.  *               used in the WinLoadString OS/2 API to get the correct
  1063.  *               string from the table.
  1064.  *
  1065.  * Concepts    : None.
  1066.  *
  1067.  * MMPM/2 API's: mciGetErrorString
  1068.  *
  1069.  * Parameters  : usTitleId         - The tile id that identifies which string
  1070.  *                                   to retrieve from the string table.
  1071.  *               usTextId          - The message text to be placed in the
  1072.  *                                   message box.  This value is the Return
  1073.  *                                   value for the failed MCI call if fMCIError
  1074.  *                                   is true and is the Message id (application
  1075.  *                                   owned) if fMCIError is False.
  1076.  *               ulMessageBoxStyle - The style of the message box.  Which
  1077.  *                                   icons, buttons, etc., to show.
  1078.  *               fMCIError         - If the Error is an MCIError (TRUE) or
  1079.  *                                   if it is an application message id (FALSE).
  1080.  *
  1081.  * Return      : The result from the message box.
  1082.  *
  1083.  ******************************************************************************/
  1084. USHORT ShowAMessage( USHORT usTitleId,
  1085.                      USHORT usTextId,
  1086.                      ULONG  ulMessageBoxStyle,
  1087.                      BOOL   fMCIError)
  1088. {
  1089.  
  1090.    CHAR   achStringBuffer[ STRING_SIZE ];       /* Title String Buffer.      */
  1091.    USHORT usMessageBoxResult;                   /* RC from WinMessageBox.    */
  1092.    CHAR   achMessageText[STRING_SIZE];          /* Message String Buffer     */
  1093.    ULONG  ulReturn;                             /* Return from MCI ERROR     */
  1094.  
  1095.    /*
  1096.     * Load the Title for the message box from the string table defined in
  1097.     * the resources.
  1098.     */
  1099.  
  1100.    WinLoadString(
  1101.       hab,                           /* HAB for this dialog box.            */
  1102.       (HMODULE) NULL,                /* Get the string from the .exe file.  */
  1103.       usTitleId,                     /* Which string to get.                */
  1104.       (SHORT) STRING_SIZE,           /* The size of the buffer.             */
  1105.       achStringBuffer );             /* The buffer to place the string.     */
  1106.  
  1107.    /* If we are to show a MCIERROR, then load it by mciGetErrorString API */
  1108.    if (fMCIError)
  1109.      {
  1110.         ulReturn =
  1111.             mciGetErrorString(
  1112.                             usTextId,
  1113.                             (PSZ)achMessageText,
  1114.                             (USHORT) STRING_SIZE );
  1115.  
  1116.  
  1117.            /*
  1118.             * Make sure that the retrieving of the error string was successfull.
  1119.             */
  1120.            if ( ulReturn != MCIERR_SUCCESS )
  1121.              {
  1122.               WinLoadString(
  1123.                     hab,                       /* HAB for this dialog box.   */
  1124.                     (HMODULE) NULL,            /* Get string from .exe file. */
  1125.                     IDS_CANT_PROCESS_MESSAGE,  /* Which string to get.       */
  1126.                     (SHORT) STRING_SIZE,       /* The size of the buffer.    */
  1127.                     achMessageText);           /* Buffer to place the string.*/
  1128.  
  1129.               ulMessageBoxStyle = MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  1130.                                   MB_APPLMODAL;
  1131.              }  /* End of IF testing for failed Get Error String API. */
  1132.  
  1133.      }
  1134.    else
  1135.      {
  1136.      /*
  1137.       This is not an MCIError so load the Text for Message Box from
  1138.       the string table defined in the resources.
  1139.       */
  1140.        WinLoadString(
  1141.            hab,                     /* HAB for this dialog box.   */
  1142.            (HMODULE) NULL,          /* Get string from .exe file. */
  1143.            usTextId,                /* Which string to get.       */
  1144.            (SHORT) STRING_SIZE,     /* The size of the buffer.    */
  1145.            achMessageText );        /* Buffer to place the string.*/
  1146.      }
  1147.    usMessageBoxResult =
  1148.       WinMessageBox(
  1149.          HWND_DESKTOP,              /* Parent handle of the message box.   */
  1150.          hwndDiag,                  /* Owner handle of the message box.    */
  1151.          achMessageText,            /* String to show in the message box.  */
  1152.          achStringBuffer,           /* Title to shown in the message box.  */
  1153.          ID_MESSAGE_BOX,            /* Message Box Id.                     */
  1154.          ulMessageBoxStyle );       /* The style of the message box.       */
  1155.  
  1156.    return( usMessageBoxResult );
  1157.  
  1158. }  /* End of ShowAMessage */
  1159.  
  1160.  
  1161.