home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mmpm21tk.zip / TK / DUET1 / DUET1.C < prev    next >
C/C++ Source or Header  |  1993-03-02  |  73KB  |  1,891 lines

  1. /*************************************************************************
  2.  * File Name    :  DUET1.C
  3.  *
  4.  * Description  :  This file contains the C source code required for the
  5.  *                 DUET1 sample program.
  6.  *
  7.  * Concepts     :  Two parts of a duet will be played as a non-piecemeal group.
  8.  *                 Each part will be streamed from a waveform file.  Also, the
  9.  *                 volume of the group (and therefore each device) will be
  10.  *                 manipulated.  Additionally, an audio help message will be
  11.  *                 incorporated  into IPF help.
  12.  *
  13.  * MMPM/2 API's :  List of all MMPM/2 API's that are used in
  14.  *                 this module
  15.  *
  16.  *                 mciSendCommand    MCI_OPEN
  17.  *                                   MCI_LOAD
  18.  *                                   MCI_CUE
  19.  *                                   MCI_PLAY
  20.  *                                   MCI_PAUSE
  21.  *                                   MCI_RESUME
  22.  *                                   MCI_CLOSE
  23.  *                                   MCI_SET
  24.  *                                   MCI_GROUP
  25.  *                 mciGetErrorString
  26.  *                 mmioOpen
  27.  *                 mmioClose
  28.  *
  29.  * Required
  30.  *    Files     :  duet1.c        Source Code.
  31.  *                 duet1.h        Include file.
  32.  *                 duet1.dlg      Dialog definition.
  33.  *                 duet1.rc       Resources.
  34.  *                 duet1.ipf      Help text.
  35.  *                 duet1.mak      Make file.
  36.  *                 duet1.def      Linker definition file.
  37.  *                 duet1.ico      Program icon.
  38.  *
  39.  * Copyright (C) IBM 1991, 1992, 1993
  40.  *************************************************************************/
  41. #define  INCL_OS2MM                 /* required for MCI and MMIO headers   */
  42. #define  INCL_WIN                   /* required to use Win APIs.           */
  43. #define  INCL_PM                    /* required to use PM APIs.            */
  44. #define  INCL_WINHELP               /* required to use IPF.                */
  45. #define  INCL_WINSTDSLIDER          /* required for using slider control   */
  46. #define  INCL_SECONDARYWINDOW       /* required for secondary window       */
  47. #define  INCL_CIRCULARSLIDER        /* required for circular slider control*/
  48. #define  INCL_GRAPHICBUTTON         /* required for graphic button control */
  49. #define  INCL_MACHDR                /* required for mciplyfile             */
  50.  
  51. #include <os2.h>
  52. #include <os2me.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55.  
  56. #include <sw.h>
  57.  
  58. #include "duet1.h"
  59.  
  60.  
  61. typedef struct
  62.    {
  63.    CHAR  achTitle[LEN_DUET_TITLE];     /* the duet's title                 */
  64.    CHAR  achPart1[LEN_AUDIO_FILENAME]; /* the filename of one duet part    */
  65.    CHAR  achPart2[LEN_AUDIO_FILENAME]; /* the filename of the other part   */
  66.    }DUET;
  67.  
  68. enum DuetStates {ST_CLOSED, ST_STOPPED, ST_PLAYING, ST_PAUSED};
  69.  
  70. /*
  71.  * Procedure/Function Prototypes
  72.  */
  73. MRESULT EXPENTRY  MainDialogProc( HWND hwnd,
  74.                                   ULONG msg,
  75.                                   MPARAM mp1,
  76.                                   MPARAM mp2);
  77.  
  78. USHORT            DuetMessageBox( USHORT usTitleID,
  79.                                   USHORT usMessageID,
  80.                                   ULONG  ulStyle);
  81.  
  82. VOID              ShowMCIErrorMessage( ULONG ulError);
  83.  
  84. VOID              Initialize( VOID);
  85. VOID              Finalize( VOID);
  86. VOID              InitializeHelp( VOID);
  87. BOOL              PlayTheDuet( HWND hwnd);
  88. BOOL              PauseTheDuet( HWND hwnd);
  89. BOOL              ResumeTheDuet( HWND hwnd);
  90. VOID              StopTheDuet( HWND hwnd);
  91. VOID              CloseTheDuet( VOID);
  92. BOOL              DoesFileExist( PSZ pszFilename);
  93. VOID              SetDuetVolume( HWND hwnd);
  94.  
  95.  
  96. /*************** End of Procedure/Function Prototypes *************************/
  97.  
  98.  
  99. /*
  100.  * Global Variables.
  101.  */
  102. HELPINIT hmiHelpStructure;       /* Help initialization structure.         */
  103.  
  104. HAB      hab;
  105. QMSG     qmsg;
  106. HMQ      hmq;
  107. HWND     hwndMainDialogBox;      /* Handle to the dialog window.           */
  108. HWND     hwndFrame;              /* Handle to the frame window.            */
  109. HWND     hwndHelpInstance;       /* Handle to Help window.                 */
  110.  
  111. enum     DuetStates   eState;
  112. /* state of the selected duet - playing, paused, or stopped */
  113.  
  114. DUET     aDuet[NUM_DUETS]; /* array of duets with information about each   */
  115.  
  116. CHAR     achHelpWindowTitle[LEN_HELP_WINDOW_TITLE];
  117. CHAR     achHelpLibraryName[LEN_HELP_LIBRARY_NAME];
  118.  
  119. USHORT   usDuetPart1ID;              /* device ID for part 1 of the duet      */
  120. USHORT   usDuetPart2ID;              /* device ID for part 2 of the duet      */
  121. USHORT   usGroupHandle;              /* handle to group - duet                */
  122. SHORT    sVolumeLevel;               /* desired volume level                  */
  123.  
  124. BOOL     fPassedDuet      = FALSE;/* for MCI_ACQUIRE to play the Duet         */
  125. BOOL     fSecondDuetPass  = FALSE;/* for setting fPassedDuet-2 devices in grp */
  126. BOOL     fFirstPlay       = TRUE;    /* Indicates we've played for first time */
  127. CHAR     achAudioHelpFile[LEN_AUDIO_FILENAME];
  128. /************************** End of Global Variables ***************************/
  129.  
  130.  
  131. /*************************************************************************
  132.  * Name         : main
  133.  *
  134.  * Description  : This function calls the Intialize procedure to prepare
  135.  *                everything for the program's operation, enters the
  136.  *                message loop, then call Finalize to shut everything down
  137.  *                when the program is terminated.
  138.  *
  139.  * Concepts     : None.
  140.  *
  141.  * MMPM/2 API's : None.
  142.  *
  143.  * Parameters   : argc - Number of parameters passed into the program.
  144.  *                argv - Command line parameters.
  145.  *
  146.  * Return       : TRUE is returned to the operating system.
  147.  *
  148.  *************************************************************************/
  149. INT main( VOID )
  150. {
  151.  
  152.    Initialize();
  153.  
  154.    while ( WinGetMsg( hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0) )
  155.       WinDispatchMsg( hab, (PQMSG) &qmsg );
  156.  
  157.    Finalize();
  158.  
  159.    return( TRUE);
  160.  
  161. } /* End of main */
  162.  
  163.  
  164.  
  165. /*************************************************************************
  166.  * Name         : Initialize
  167.  *
  168.  * Description  : This function performs the necessary initializations and
  169.  *                setups that are required to show/run a dialog box as a
  170.  *                main window.  The message queue will be created, as will
  171.  *                the dialog box.
  172.  *
  173.  * Concepts     : None.
  174.  *
  175.  * MMPM/2 API's : None.
  176.  *
  177.  * Parameters   : None.
  178.  *
  179.  * Return       : None.
  180.  *
  181.  *************************************************************************/
  182. VOID Initialize( VOID)
  183. {
  184.    CHAR     achTitle[LEN_PROGRAM_TITLE]; /* buffer for window title text      */
  185.    CHAR     szDefaultSize[CCHMAXPATH];   /* buffer for default size menu text */
  186.  
  187.    /*
  188.     * Setup and initialize the dialog window.
  189.     * Change pointer to a waiting pointer first, since this might take a
  190.     * couple of seconds.
  191.     */
  192.  
  193.    WinSetPointer(
  194.       HWND_DESKTOP,        /* Desktop window handle.                    */
  195.       WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  196.          HWND_DESKTOP,     /* Desktop window handle.                    */
  197.          SPTR_WAIT,        /* The waiting icon.                         */
  198.          FALSE ) );        /* Return the system pointer's handle.       */
  199.  
  200.    hab = WinInitialize( 0);
  201.  
  202.    hmq = WinCreateMsgQueue( hab, 0);
  203.  
  204.  
  205.    /*
  206.     * Load the strings for the Duet Titles and filenames from the resource
  207.     * file.  This must be done before the dialog box is loaded since it
  208.     * fills the listbox with titles when it receives the WM_INITDLG message.
  209.     */
  210.    WinLoadString(
  211.       hab,
  212.       (HMODULE) NULL,
  213.       IDS_DUET_1_TITLE,
  214.       (SHORT) sizeof( aDuet[0].achTitle),
  215.       aDuet[0].achTitle);
  216.  
  217.    WinLoadString(
  218.       hab,
  219.       (HMODULE) NULL,
  220.       IDS_DUET_1_PART1_FILE,
  221.       (SHORT) sizeof( aDuet[0].achPart1),
  222.       aDuet[0].achPart1);
  223.  
  224.    WinLoadString(
  225.       hab,
  226.       (HMODULE) NULL,
  227.       IDS_DUET_1_PART2_FILE,
  228.       (SHORT) sizeof( aDuet[0].achPart2),
  229.       aDuet[0].achPart2);
  230.  
  231.  
  232.    WinLoadString(
  233.       hab,
  234.       (HMODULE) NULL,
  235.       IDS_DUET_2_TITLE,
  236.       (SHORT) sizeof( aDuet[1].achTitle),
  237.       aDuet[1].achTitle);
  238.  
  239.    WinLoadString(
  240.       hab,
  241.       (HMODULE) NULL,
  242.       IDS_DUET_2_PART1_FILE,
  243.       (SHORT) sizeof( aDuet[1].achPart1),
  244.       aDuet[1].achPart1);
  245.  
  246.    WinLoadString(
  247.       hab,
  248.       (HMODULE) NULL,
  249.       IDS_DUET_2_PART2_FILE,
  250.       (SHORT) sizeof( aDuet[1].achPart2),
  251.       aDuet[1].achPart2);
  252.  
  253.  
  254.    WinLoadString(
  255.       hab,
  256.       (HMODULE) NULL,
  257.       IDS_DUET_3_TITLE,
  258.       (SHORT) sizeof( aDuet[2].achTitle),
  259.       aDuet[2].achTitle);
  260.  
  261.    WinLoadString(
  262.       hab,
  263.       (HMODULE) NULL,
  264.       IDS_DUET_3_PART1_FILE,
  265.       (SHORT) sizeof( aDuet[2].achPart1),
  266.       aDuet[2].achPart1);
  267.  
  268.    WinLoadString(
  269.       hab,
  270.       (HMODULE) NULL,
  271.       IDS_DUET_3_PART2_FILE,
  272.       (SHORT) sizeof( aDuet[2].achPart2),
  273.       aDuet[2].achPart2);
  274.  
  275.    WinLoadString(
  276.       hab,
  277.       (HMODULE) NULL,
  278.       IDS_DEFAULTSIZE,
  279.       sizeof(szDefaultSize),
  280.       szDefaultSize);
  281.  
  282.    hwndFrame =                  /* Returns the handle to the frame.           */
  283.       WinLoadSecondaryWindow(
  284.          HWND_DESKTOP,          /* Parent of the dialog box.                  */
  285.          HWND_DESKTOP,          /* Owner of the dialog box.                   */
  286.          (PFNWP) MainDialogProc,/* 'Window' procedure for the dialog box.     */
  287.          (HMODULE) NULL,        /* Where is the dialog.  Null is EXE file..   */
  288.          ID_DLG_MAIN,           /* Dialog ID.                                 */
  289.          (PVOID) NULL);         /* Creation Parameters for the dialog.        */
  290.  
  291.    /*
  292.     * Retrieve the handle to the dialog box by specifying the QS_DIALOG flag.
  293.     */
  294.    hwndMainDialogBox = WinQuerySecondaryHWND(hwndFrame, QS_DIALOG);
  295.  
  296.    /*
  297.     * Add Default Size menu item to system menu of the secondary window.
  298.     */
  299.    WinInsertDefaultSize(hwndFrame, szDefaultSize);
  300.  
  301.    /*
  302.     * Get the window title string from the Resource string table
  303.     * and set it as the window text for the dialog window.
  304.     */
  305.    WinLoadString(
  306.       hab,                          /* HAB for this dialog box.            */
  307.       (HMODULE) NULL,               /* Get the string from the .exe file.  */
  308.       IDS_PROGRAM_TITLE,            /* Which string to get.                */
  309.       (SHORT) sizeof( achTitle),    /* The size of the buffer.             */
  310.       achTitle);                    /* The buffer to place the string.     */
  311.  
  312.  
  313.    WinSetWindowText( hwndFrame, achTitle);
  314.  
  315.  
  316.    /*
  317.     * Initialize the help structure and associate the help instance to this
  318.     * dialog via it's handle to anchor block.
  319.     */
  320.    InitializeHelp();
  321.  
  322.    /*
  323.     * Now that we're done here, change the pointer back to the arrow.
  324.     */
  325.  
  326.    WinSetPointer(
  327.       HWND_DESKTOP,        /* Desktop window handle.                    */
  328.       WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  329.          HWND_DESKTOP,     /* Desktop window handle.                    */
  330.          SPTR_ARROW,       /* The Arrow icon.                           */
  331.          FALSE ) );        /* Return the system pointer's handle.       */
  332.  
  333. } /* End of Initialize */
  334.  
  335.  
  336.  
  337. /*************************************************************************
  338.  * Name         : Finalize
  339.  *
  340.  * Description  : This routine is called after the message dispatch loop
  341.  *                has ended because of a WM_QUIT message.  The code will
  342.  *                destroy the help instance, messages queue, and window.
  343.  *
  344.  * Concepts     : None.
  345.  *
  346.  * MMPM/2 API's : None.
  347.  *
  348.  * Parameters   : None.
  349.  *
  350.  * Return       : None.
  351.  *
  352.  *************************************************************************/
  353. VOID Finalize( VOID )
  354. {
  355.    /*
  356.     * Destroy the Help Instance for this dialog window.
  357.     */
  358.    if ( hwndHelpInstance != (HWND) NULL)
  359.    {
  360.       WinDestroyHelpInstance( hwndHelpInstance );
  361.    }
  362.  
  363.    WinDestroySecondaryWindow( hwndFrame );
  364.    WinDestroyMsgQueue( hmq );
  365.    WinTerminate( hab );
  366.  
  367. }  /* End of Finalize */
  368.  
  369.  
  370.  
  371. /******************************************************************************
  372.  * Name         : MainDialogProc
  373.  *
  374.  * Description  : This function controls the main dialog box.  It will
  375.  *                handle received messages such as pushbutton notifications,
  376.  *                timing events, etc.
  377.  *
  378.  * Concepts     : None.
  379.  *
  380.  *
  381.  * MMPM/2 API's : None.
  382.  *
  383.  *
  384.  * Parameters   : hwnd - Handle for the Main dialog box.
  385.  *                msg  - Message received by the dialog box.
  386.  *                mp1  - Parameter 1 for the just recieved message.
  387.  *                mp2  - Parameter 2 for the just recieved message.
  388.  *
  389.  * Return       :
  390.  *
  391.  ******************************************************************************/
  392. MRESULT EXPENTRY MainDialogProc( HWND   hwnd,
  393.                                  ULONG  msg,
  394.                                  MPARAM mp1,
  395.                                  MPARAM mp2 )
  396. {
  397.    HPOINTER          hpProgramIcon;           /* handle to program's icon     */
  398.    PSWP              pswpWindowActionMP;      /* hold status of window        */
  399.    int               iDuet;                   /* index of duet number         */
  400.    USHORT            usUserParm;              /* user parameter returned      */
  401.    USHORT            usNotifyCode;            /* notification message code    */
  402.    USHORT            usCommandMessage;        /* command message for notify   */
  403.    MCI_GENERIC_PARMS mciGenericParms;         /* generic parms for MCI_ACQUIRE*/
  404.    ULONG             ulError;                 /* rc for MCI_ACQUIRE send cmd  */
  405.    CHAR              achAudioHelpFile[LEN_AUDIO_FILENAME];/* Audio file name  */
  406.  
  407.  
  408.    switch( msg )
  409.    {
  410.  
  411.       case WM_INITDLG :
  412.  
  413.          /*
  414.           * Initialize the dialog window.
  415.           * Change pointer to a waiting pointer first, since this might take a
  416.           * couple of seconds.
  417.           */
  418.  
  419.          WinSetPointer(
  420.             HWND_DESKTOP,        /* Desktop window handle.                    */
  421.             WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  422.                HWND_DESKTOP,     /* Desktop window handle.                    */
  423.                SPTR_WAIT,        /* The waiting icon.                         */
  424.                FALSE ) );        /* Return the system pointer's handle.       */
  425.  
  426.          hpProgramIcon =
  427.             WinLoadPointer(
  428.                HWND_DESKTOP,
  429.                (HMODULE) NULL, /* Where the resource is kept. (Exe file)      */
  430.                ID_ICON );      /* Which icon to use.                          */
  431.  
  432.          WinDefSecondaryWindowProc(
  433.             hwnd,              /* Dialog window handle.                       */
  434.             WM_SETICON,        /* Message to the dialog.  Set it's icon.      */
  435.             (MPARAM) hpProgramIcon,
  436.             (MPARAM) 0 );      /* mp2 no value.                               */
  437.  
  438.          /*
  439.           * We need to fill the listbox with the titles of the duets.
  440.           * To do this, loop through each duet and send a LM_INSERTITEM
  441.           * message to the listbox with the text of the duet's title.
  442.           */
  443.          for(iDuet=0; iDuet<NUM_DUETS; iDuet++)
  444.          {
  445.             WinSendMsg( WinWindowFromID( hwnd, ID_LB_DUET),
  446.                         LM_INSERTITEM,
  447.                         (MPARAM) LIT_END,
  448.                         aDuet[iDuet].achTitle);
  449.          }
  450.  
  451.  
  452.          /* select the first duet in the listbox by default */
  453.  
  454.          WinSendMsg( WinWindowFromID (hwnd, ID_LB_DUET),
  455.                      LM_SELECTITEM,
  456.                      (MPARAM) 0,
  457.                      (MPARAM) TRUE);
  458.  
  459.          sVolumeLevel = INIT_VOLUME;  /* initialize the desired volume level */
  460.          /*
  461.           * The slider control cannot be completely set from the dialog
  462.           * template so some aspects must be set here.  We will set the
  463.           * volume range to 0-100, increment to 1-10, and the initial
  464.           * volume level to 75.
  465.           */
  466.          WinSendMsg( WinWindowFromID (hwnd, ID_SL_VOLUME),
  467.                      CSM_SETRANGE,
  468.                      (MPARAM) 0L,
  469.                      (MPARAM) 100L);
  470.  
  471.          WinSendMsg( WinWindowFromID (hwnd, ID_SL_VOLUME),
  472.                      CSM_SETINCREMENT,
  473.                      (MPARAM) 10L,
  474.                      (MPARAM) 1L);
  475.  
  476.          WinSendMsg( WinWindowFromID (hwnd, ID_SL_VOLUME),
  477.                      CSM_SETVALUE,
  478.                      (MPARAM) sVolumeLevel,
  479.                      (MPARAM) NULL);
  480.  
  481.          /*
  482.           * Set up the PLAY graphic pushbutton.
  483.           */
  484.          WinSendMsg (
  485.             WinWindowFromID(
  486.                hwnd,                /* Dialog window handle             */
  487.                ID_GPB_PLAY),        /* Id - Play graphic button         */
  488.             GBM_SETANIMATIONRATE,   /* Animation rate control           */
  489.             MPFROMLONG(100L),       /* Update play bitmap every .1 sec  */
  490.             NULL);                  /* Ignore return data               */
  491.  
  492.          eState = ST_CLOSED;       /* The initial duet state is closed.      */
  493.          /*
  494.           * Now that we're done here, change the pointer back to the arrow.
  495.           */
  496.  
  497.          WinSetPointer(
  498.             HWND_DESKTOP,        /* Desktop window handle.                    */
  499.             WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  500.                HWND_DESKTOP,     /* Desktop window handle.                    */
  501.                SPTR_ARROW,       /* The Arrow icon.                           */
  502.                FALSE ) );        /* Return the system pointer's handle.       */
  503.  
  504.          return( (MRESULT) 0);
  505.  
  506.  
  507.       case WM_CLOSE :
  508.  
  509.          /*
  510.           * Clean up the devices and group.
  511.           */
  512.  
  513.          if (!fFirstPlay) {        /* If we've opened the devices */
  514.             CloseTheDuet();
  515.          }
  516.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2));
  517.  
  518.       case WM_HELP :
  519.          /*
  520.           * The dialog window has recieved a request for help from the user,
  521.           * i.e., the Help pushbutton was pressed.  Send the HM_DISPLAY_HELP
  522.           * message to the Help Instance with the IPF resource identifier
  523.           * for the correct HM panel.  This will show the help panel for this
  524.           * sample program.
  525.           */
  526.          WinSendMsg( hwndHelpInstance,
  527.                      HM_DISPLAY_HELP,
  528.                      MPFROMSHORT(1),
  529.                      MPFROMSHORT(HM_RESOURCEID));
  530.          return( (MRESULT) 0);
  531.  
  532.       case WM_COMMAND :
  533.          /*
  534.           * To get which pushbutton was pressed the SHORT1FROMMP macro
  535.           * is used.
  536.           */
  537.          switch (SHORT1FROMMP(mp1))
  538.          {
  539.  
  540.             case ID_GPB_PLAY:     /* user selected "Play"    */
  541.                if ((eState==ST_CLOSED) || (eState==ST_STOPPED))
  542.                {
  543.  
  544.                   if (fPassedDuet)
  545.                   {                       /* If we've passed the device away */
  546.  
  547.                      /* If we don't have control of the device (ie. if we've
  548.                       * passed it) then put up an error message.
  549.                       */
  550.  
  551.                      DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  552.                                      IDS_CANT_PROCESS_MESSAGE,
  553.                                      MB_OK | MB_INFORMATION  | MB_MOVEABLE);
  554.                   }
  555.                   else                   /* If we haven't passed the device */
  556.                   {
  557.                      /* eState will be set in PlayTheDuet */
  558.                      if (PlayTheDuet( hwnd))
  559.                      {
  560.  
  561.                         WinEnableWindow( WinWindowFromID( hwnd, ID_LB_DUET),
  562.                                          FALSE);
  563.                         /*
  564.                          * Start the play button animation
  565.                          */
  566.                         WinSendMsg(
  567.                            WinWindowFromID (
  568.                               hwnd,            /* Dialog window handle      */
  569.                               ID_GPB_PLAY),    /* Id - Play graphic button  */
  570.                            GBM_ANIMATE,        /* Animation control         */
  571.                            MPFROMSHORT(TRUE),  /* Animation flag            */
  572.                            NULL);              /* Ignore return data        */
  573.                      }
  574.                      else
  575.                         eState = ST_STOPPED;
  576.                   }  /* End of if we've passed the device away              */
  577.                }
  578.                else if (eState==ST_PAUSED)
  579.                {
  580.                   if (fPassedDuet)
  581.                   {     /* If we've passed the device away                  */
  582.  
  583.                      /* If we don't have control of the device (ie. if we've
  584.                       * passed it) then put up an error message.
  585.                       */
  586.  
  587.                      DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  588.                                      IDS_CANT_PROCESS_MESSAGE,
  589.                                      MB_OK | MB_INFORMATION  | MB_MOVEABLE);
  590.                   }
  591.                   else  /* If we haven't passed the device away             */
  592.                   {
  593.                      if (ResumeTheDuet(hwnd))
  594.                         eState = ST_PLAYING;
  595.                   }  /* End of if we've passed the device away.             */
  596.                }
  597.                break;
  598.  
  599.             case ID_GPB_PAUSE:    /* user selected "Pause"   */
  600.                if (eState==ST_PLAYING || eState==ST_PAUSED)
  601.                {
  602.                   if (fPassedDuet)
  603.                   {  /* If we've passed the device away...                   */
  604.  
  605.                      /* If we don't have control of the device (ie. if we've
  606.                       * passed it) then put up an error message.
  607.                       */
  608.  
  609.                      DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  610.                                      IDS_CANT_PROCESS_MESSAGE,
  611.                                      MB_OK | MB_INFORMATION  | MB_MOVEABLE);
  612.                   }
  613.                   else  /* If we haven't passed the device away...           */
  614.                   {
  615.                      if (PauseTheDuet(hwnd))
  616.                         eState = ST_PAUSED;
  617.                   }  /* End of if we've passed the device away               */
  618.                }
  619.                break;
  620.  
  621.             case ID_GPB_STOP:     /* user selected "Stop"    */
  622.                if (eState==ST_PLAYING || eState==ST_PAUSED)
  623.                {
  624.                   if (fPassedDuet)
  625.                   {      /* If we've passed control of device away           */
  626.  
  627.                      /* If we don't have control of the device (ie. if we've
  628.                       * passed it) then put up an error message.
  629.                       */
  630.  
  631.                      DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  632.                                      IDS_CANT_PROCESS_MESSAGE,
  633.                                      MB_OK | MB_INFORMATION  | MB_MOVEABLE);
  634.                   }
  635.                   else
  636.                   {
  637.                      eState = ST_STOPPED;
  638.                      StopTheDuet(hwnd);
  639.                      WinEnableWindow( WinWindowFromID( hwnd, ID_LB_DUET), TRUE);
  640.                   }
  641.                }
  642.                break;
  643.  
  644.             case DID_CANCEL:     /* user selected ESC key  */
  645.             case ID_PB_CANCEL:   /* user selected "Cancel"  */
  646.                WinSendMsg( hwnd, WM_CLOSE, (MPARAM) NULL, (MPARAM) NULL);
  647.                break;
  648.  
  649.             default:
  650.                break;
  651.  
  652.          }  /* End of Command Switch */
  653.          return( (MRESULT) 0);
  654.  
  655.       case WM_CONTROL:
  656.          if (SHORT1FROMMP(mp1)==ID_SL_VOLUME)
  657.          {
  658.             if ((SHORT2FROMMP(mp1)==CSN_CHANGED) ||    /* change volume?   */
  659.                 (SHORT2FROMMP(mp1)==CSN_TRACKING))     /* tracking volume? */
  660.             {
  661.                sVolumeLevel = SHORT1FROMMP (mp2);
  662.                SetDuetVolume(hwnd);
  663.             }
  664.          }
  665.          return( (MRESULT) 0);
  666.  
  667.       case WM_MINMAXFRAME:
  668.  
  669.          /*
  670.           * Handling this message is required since this program is using
  671.           * a dialog box as the main window.  In PM, the controls in the
  672.           * bottom left corner of the dialog box may overlap the icon when
  673.           * the progrma is minimized.
  674.           *
  675.           * Therefore, if the message action indicates that the program is
  676.           * about to be minimized then we will hide the pushbutton in the
  677.           * lower lefthand corner.  Otherwise, we assume the program is about
  678.           * be restored so we will allow the pushbutton to be shown.
  679.           */
  680.  
  681.          pswpWindowActionMP = (PSWP) LONGFROMMP( mp1 );
  682.  
  683.          if ( pswpWindowActionMP->fl & SWP_MINIMIZE )
  684.             WinShowWindow( WinWindowFromID( hwnd, ID_PB_CANCEL), FALSE);
  685.          else
  686.             WinShowWindow( WinWindowFromID( hwnd, ID_PB_CANCEL), TRUE);
  687.  
  688.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  689.  
  690.       /*
  691.        * The next two messages are handled so that the Duet Player
  692.        * application can participate in device sharing.  Since it opens
  693.        * the devices as shareable devices, other applications can gain
  694.        * control of the devices.  When this happens, we will receive a
  695.        * pass device message.  We keep track of this device passing in
  696.        * the fPassedDuet boolean variable.
  697.        *
  698.        * Be careful, though, because we'll be getting a pass device for
  699.        * each device in the group.  Don't issue the acquire till we've
  700.        * gotten the pass device for both devices in the group.  This is
  701.        * kept track of by the fSecondDuetPass variable.
  702.        *
  703.        * If we do not have access to the device when we receive an activate
  704.        * message, then we will issue an acquire device command to gain
  705.        * access to the device.
  706.        */
  707.  
  708.       case MM_MCIPASSDEVICE:
  709.          if (SHORT1FROMMP(mp2) == MCI_GAINING_USE) {          /* GAINING USE */
  710.  
  711.             if (fSecondDuetPass) {           /* If this is the 2nd pass msg. */
  712.  
  713.                fPassedDuet = FALSE;          /* Gaining control of device.   */
  714.                fSecondDuetPass = FALSE;      /* Reset BOOL for next test.    */
  715.  
  716.                if (eState == ST_PLAYING) {      /* If the duet was playing   */
  717.                   WinSendMsg(                   /* Start Play button animation*/
  718.                      WinWindowFromID (
  719.                         hwnd,                   /* Dialog window handle       */
  720.                         ID_GPB_PLAY),           /* Id - Play graphic button   */
  721.                      GBM_ANIMATE,               /* Animation control          */
  722.                      MPFROMSHORT(TRUE),         /* Animation flag             */
  723.                      NULL);                     /* Ignore return data         */
  724.                }
  725.  
  726.             }
  727.             else                             /* If this is the 1st pass msg. */
  728.             {
  729.                fSecondDuetPass = TRUE;       /* Set BOOL for next test.      */
  730.             }
  731.  
  732.          } else {                                             /* LOSING USE  */
  733.  
  734.             if (fSecondDuetPass) {           /* If this is the 2nd pass msg. */
  735.  
  736.                fPassedDuet = TRUE;           /* Losing  control of device.   */
  737.                fSecondDuetPass = FALSE;      /* Reset BOOL for next test.    */
  738.  
  739.                if (eState == ST_PLAYING) {      /* If the duet was playing   */
  740.                   WinSendMsg(                   /* Start Play button animation. */
  741.                      WinWindowFromID (
  742.                         hwnd,                   /* Dialog window handle         */
  743.                         ID_GPB_PLAY),           /* Id - Play graphic button     */
  744.                      GBM_ANIMATE,               /* Animation control            */
  745.                      MPFROMSHORT(FALSE),        /* Animation flag               */
  746.                      NULL);                     /* Ignore return data           */
  747.                 }
  748.             }
  749.             else                             /* If this is the 1st pass msg. */
  750.             {
  751.                fSecondDuetPass = TRUE;       /* Set BOOL for next test.      */
  752.             }
  753.          }
  754.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  755.  
  756.       case WM_ACTIVATE:
  757.  
  758.       /**************************************************************
  759.        * We use the WM_ACTIVATE message to participate in device
  760.        * sharing.  We first check to see if this is an activate
  761.        * or a deactivate message (indicated by mp1).  Then,
  762.        * we check to see if we've passed control of the duets'
  763.        * devices.  If these conditions are true, then
  764.        * we issue an acquire device command to regain control of
  765.        * the device, since we're now the active window on the screen.
  766.        *
  767.        * This is one possible method that can be used to implement
  768.        * device sharing. For applications that are more complex
  769.        * than this sample program, developers may wish to take
  770.        * advantage of a more robust method of device sharing.
  771.        * This can be done by using the MCI_ACQUIRE_QUEUE flag on
  772.        * the MCI_ACQUIREDEVICE command.  Please refer to the MMPM/2
  773.        * documentation for more information on this flag.
  774.        **************************************************************/
  775.  
  776.          if ((BOOL)mp1 && fPassedDuet == TRUE) {
  777.  
  778.             mciGenericParms.hwndCallback = hwnd;
  779.  
  780.             ulError = mciSendCommand( usGroupHandle,
  781.                                       MCI_ACQUIREDEVICE,
  782.                                      (ULONG)MCI_NOTIFY,
  783.                                      (PVOID) &mciGenericParms,
  784.                                      (USHORT)NULL);
  785.             if (ulError)
  786.             {
  787.                ShowMCIErrorMessage( ulError);
  788.             }
  789.  
  790.          }
  791.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  792.  
  793.       case MM_MCINOTIFY:
  794.          usNotifyCode = (USHORT) SHORT1FROMMP( mp1);
  795.          usUserParm  = (USHORT) SHORT2FROMMP( mp1);
  796.  
  797.          usCommandMessage = (USHORT) SHORT2FROMMP( mp2); /* high-word */
  798.  
  799.          switch (usCommandMessage)
  800.          {
  801.             case MCI_PLAY:
  802.                switch (usNotifyCode)
  803.                {
  804.                   case MCI_NOTIFY_SUCCESSFUL:
  805.                      if (eState != ST_STOPPED && eState != ST_CLOSED)
  806.                      {
  807.                         /*
  808.                         * We will receive the MCI_NOTIFY_SUCCESSFUL message
  809.                         * for each device in the group, so we need to be sure
  810.                         * to only do this action once.  That's why we are
  811.                         * checking the eState and then immediately setting it
  812.                         * to ST_STOPPED.
  813.                         */
  814.  
  815.                         eState = ST_STOPPED;
  816.  
  817.                         /*
  818.                          * Stop the play button animation
  819.                          */
  820.  
  821.                         WinSendMsg (
  822.                            WinWindowFromID(
  823.                               hwnd,             /* Dialog window handle      */
  824.                               ID_GPB_PLAY),     /* Id - Play graphic button  */
  825.                            GBM_ANIMATE,         /* Animation control         */
  826.                            MPFROMSHORT(FALSE),  /* Animation flag            */
  827.                            NULL);               /* Ignore return data        */
  828.  
  829.                         WinEnableWindow( WinWindowFromID( hwnd, ID_LB_DUET),
  830.                               TRUE);
  831.                      }
  832.                      break;
  833.  
  834.                   case MCI_NOTIFY_SUPERSEDED:
  835.                   case MCI_NOTIFY_ABORTED:
  836.                      /* we don't need to handle these messages. */
  837.                      break;
  838.  
  839.                   default:
  840.                      /*
  841.                       * If the message is none of the above, then it must be
  842.                       * a notification error message.
  843.                       */
  844.                      ShowMCIErrorMessage( usNotifyCode);
  845.                      eState = ST_STOPPED;
  846.  
  847.                      /*
  848.                       * Stop the play button animation
  849.                       */
  850.  
  851.                      WinSendMsg (
  852.                         WinWindowFromID(
  853.                            hwnd,             /* Dialog window handle      */
  854.                            ID_GPB_PLAY),     /* Id - Play graphic button  */
  855.                         GBM_ANIMATE,         /* Animation control         */
  856.                         MPFROMSHORT(FALSE),  /* Animation flag            */
  857.                         NULL);               /* Ignore return data        */
  858.  
  859.                      WinEnableWindow( WinWindowFromID( hwnd, ID_LB_DUET),
  860.                            TRUE);
  861.                      break;
  862.  
  863.                }
  864.                break;
  865.  
  866.          }
  867.          return( (MRESULT) 0);
  868.  
  869.       case HM_INFORM:
  870.          /*
  871.           * The user has selected the "Play Audio Help" selection in the
  872.           * IPF help panel.
  873.           *
  874.           * To initiate the playing of audio help, we need to issue mciPlayFile.
  875.           *
  876.           * Note that we assume the HM_INFORM message came from the "Play
  877.           * Audio Help" selection since it is the only :link. with an inform
  878.           * reftype in the .ipf file.  If there were more, we would have to
  879.           * check the resource identifier to determine for which selection
  880.           * this message was generated.
  881.           */
  882.  
  883.          /*
  884.           * Load the name of the audio help file from the resource
  885.           */
  886.          WinLoadString( hab,
  887.                         (HMODULE) NULL,
  888.                         IDS_HELP_WAVEFILE,
  889.                         (SHORT) sizeof( achAudioHelpFile),
  890.                         achAudioHelpFile);
  891.  
  892.          ulError = mciPlayFile( (HWND)NULL,            /* Ignore owner window */
  893.                                 (PSZ)achAudioHelpFile, /* Audio file to play  */
  894.                                 MCI_ASYNC,             /* Flags               */
  895.                                 (PSZ)NULL,             /* Ignore title        */
  896.                                 (HWND)NULL );          /* Ignore viewport wnd */
  897.          if (ulError)
  898.          {
  899.             ShowMCIErrorMessage( ulError);
  900.          }
  901.          return( (MRESULT) 0);
  902.  
  903.       default:
  904.          return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2));
  905.  
  906.    }  /* End of msg Switch */
  907.  
  908.    return( (MRESULT) FALSE);
  909.  
  910. } /* End of MainDialogProc */
  911.  
  912.  
  913. /*************************************************************************
  914.  * Name         : InitializeHelp
  915.  *
  916.  * Description  : This procedure will set up the initial values in the
  917.  *                global help structure.  This help structure will then
  918.  *                be passed on to the Help Manager when the Help Instance
  919.  *                is created.  The handle to the Help Instance will be
  920.  *                kept for later use.
  921.  *
  922.  * Concepts     : None.
  923.  *
  924.  * MMPM/2 API's : None.
  925.  *
  926.  * Parameters   : None.
  927.  *
  928.  * Return       : None.
  929.  *
  930.  *************************************************************************/
  931. VOID InitializeHelp( VOID )
  932. {
  933.    BOOL  fHelpCreated = FALSE;
  934.  
  935.  
  936.    /*
  937.     * Load the strings for the Help window title and library name.
  938.     */
  939.  
  940.    WinLoadString(
  941.       hab,
  942.       (HMODULE) NULL,
  943.       IDS_HELP_WINDOW_TITLE,
  944.       (SHORT) sizeof( achHelpWindowTitle),
  945.       achHelpWindowTitle);
  946.  
  947.    WinLoadString(
  948.       hab,
  949.       (HMODULE) NULL,
  950.       IDS_HELP_LIBRARY_NAME,
  951.       (SHORT) sizeof( achHelpLibraryName),
  952.       achHelpLibraryName);
  953.  
  954.  
  955.    /*
  956.     * Get the size of the initialization structure.
  957.     */
  958.    hmiHelpStructure.cb              = sizeof( HELPINIT);
  959.  
  960.    hmiHelpStructure.ulReturnCode    = (ULONG) 0;   /* RC from HM init      */
  961.    hmiHelpStructure.pszTutorialName = (PSZ) NULL;  /* No tutorial program  */
  962.  
  963.    hmiHelpStructure.phtHelpTable    = (PVOID)(0xffff0000 | ID_DUET_HELPTABLE);
  964.  
  965.  
  966.    /*
  967.     * The action bar is not used, so set the following to NULL.
  968.     */
  969.    hmiHelpStructure.hmodAccelActionBarModule = (HMODULE) 0;
  970.    hmiHelpStructure.idAccelTable             = (USHORT) 0;
  971.    hmiHelpStructure.idActionBar              = (USHORT) 0;
  972.  
  973.    /*
  974.     * The Help window title.
  975.     */
  976.    hmiHelpStructure.pszHelpWindowTitle  = achHelpWindowTitle;
  977.  
  978.    /*
  979.     * The Help table is in the executable file.
  980.     */
  981.    hmiHelpStructure.hmodHelpTableModule = (HMODULE) 0;
  982.  
  983.    /*
  984.     * The help panel ID is not displayed.
  985.     */
  986.    hmiHelpStructure.fShowPanelId       = (ULONG) 0;
  987.  
  988.    /*
  989.     * The library that contains the help panels.
  990.     */
  991.    hmiHelpStructure.pszHelpLibraryName  = achHelpLibraryName;
  992.  
  993.    /*
  994.     * Create the Help Instance for IPF.
  995.     * Give IPF the Anchor Block handle and address of the IPF initialization
  996.     * structure, and check that creation of Help was a success.
  997.     */
  998.    hwndHelpInstance = WinCreateHelpInstance(
  999.                          hab,                   /* Anchor Block Handle.    */
  1000.                          &hmiHelpStructure );   /* Help Structure.         */
  1001.  
  1002.    if ( hwndHelpInstance == (HWND) NULL)
  1003.    {
  1004.       fHelpCreated = FALSE;
  1005.    }
  1006.    else
  1007.    {
  1008.       if ( hmiHelpStructure.ulReturnCode)
  1009.       {
  1010.          WinDestroyHelpInstance( hwndHelpInstance);
  1011.          fHelpCreated = FALSE;
  1012.       }
  1013.       else  /* help creation worked */
  1014.       {
  1015.          WinAssociateHelpInstance(
  1016.             hwndHelpInstance,     /* The handle of the Help Instance.      */
  1017.             hwndFrame);           /* Associate to this dialog window.      */
  1018.  
  1019.             fHelpCreated = TRUE;
  1020.       }
  1021.    }  /* End of IF checking the creation of the Help Instance. */
  1022.  
  1023.    /*
  1024.     * Associate the Help Instance of the IPF to this dialog window.
  1025.     */
  1026.    if (!fHelpCreated)
  1027.    {
  1028.       DuetMessageBox( IDS_DUET_PLAYER_ERROR,    /* ID of the title         */
  1029.                       IDS_HELP_CREATION_FAILED, /* ID of the message       */
  1030.                       MB_OK | MB_INFORMATION  | MB_MOVEABLE);  /* style    */
  1031.    }
  1032.  
  1033. }  /* End of InitializeHelp */
  1034.  
  1035.  
  1036. /*************************************************************************
  1037.  * Name         :  DuetMessageBox
  1038.  *
  1039.  * Description  :  This procedure will display messages for the application
  1040.  *                 based upon string IDs passed in.  The actual text will be
  1041.  *                 loaded from the string table in the resource.
  1042.  *
  1043.  * Concepts     :  None.
  1044.  *
  1045.  * MMPM/2 API's :  None.
  1046.  *
  1047.  * Parameters   :  usTitleID   - ID of the title string
  1048.  *                 usMessageID - ID of the message string
  1049.  *                 ulStyle     - Style of the message box (WinMessageBox)
  1050.  *
  1051.  * Return       :  TRUE  -  if the operation was initiated without error.
  1052.  *                 FALSE -  if an error occurred.
  1053.  *
  1054.  *************************************************************************/
  1055. USHORT DuetMessageBox(  USHORT usTitleID,
  1056.                         USHORT usMessageID,
  1057.                         ULONG  ulStyle)
  1058. {
  1059.    CHAR     achTitle[LEN_ERROR_TITLE];
  1060.    CHAR     achMessage[LEN_ERROR_MESSAGE];
  1061.    USHORT   usResult;
  1062.  
  1063.  
  1064.  
  1065.    /*
  1066.     * Get the string from the Resource defined string table and show it
  1067.     * in the message box.
  1068.     */
  1069.    WinLoadString(
  1070.       hab,                          /* HAB for this dialog box.            */
  1071.       (HMODULE) NULL,               /* Get the string from the .exe file.  */
  1072.       usTitleID,                    /* Which string to get.                */
  1073.       (SHORT) sizeof( achTitle),    /* The size of the buffer.             */
  1074.       achTitle );                   /* The buffer to place the string.     */
  1075.  
  1076.    WinLoadString(
  1077.       hab,                          /* HAB for this dialog box.            */
  1078.       (HMODULE) NULL,               /* Get the string from the .exe file.  */
  1079.       usMessageID,                  /* Which string to get.                */
  1080.       (SHORT) sizeof( achMessage),  /* The size of the buffer.             */
  1081.       achMessage );                 /* The buffer to place the string.     */
  1082.  
  1083.  
  1084.    usResult =
  1085.       WinMessageBox(
  1086.          HWND_DESKTOP,              /* Parent handle of the message box.   */
  1087.          hwndMainDialogBox,         /* Owner handle of the message box.    */
  1088.          achMessage,                /* String to show in the message box.  */
  1089.          achTitle,                  /* Title to shown in the message box.  */
  1090.          (USHORT) ID_MESSAGEBOX,    /* Message Box Id.                     */
  1091.          ulStyle );                 /* The style of the message box.       */
  1092.  
  1093.    return( usResult);
  1094.  
  1095. }  /* End of DuetMessageBox */
  1096.  
  1097.  
  1098.  
  1099. /*************************************************************************
  1100.  * Name         :  PlayTheDuet
  1101.  *
  1102.  * Description  :  This procedure will begin the playing of the duet.
  1103.  *
  1104.  * Concepts     :  Opening mci devices.
  1105.  *                 Creating a group.
  1106.  *                 Playing a group.
  1107.  *
  1108.  * MMPM/2 API's :  mciSendCommand    MCI_OPEN
  1109.  *                                   MCI_PLAY
  1110.  *                                   MCI_CUE
  1111.  *                                   MCI_LOAD
  1112.  *                                   MCI_GROUP
  1113.  *
  1114.  * Parameters   :  hwnd - Handle for the Main dialog box.
  1115.  *
  1116.  * Return       :  TRUE  -  if the operation was initiated without error.
  1117.  *                 FALSE -  if an error occurred.
  1118.  *
  1119.  * IMPORTANT NOTE ABOUT DEVICE SHARING UNDER MMPM/2:
  1120.  *
  1121.  * To be a well behaved MMPM/2 application, you should participate in
  1122.  * the system's device sharing scheme.  This is done by processing the
  1123.  * MM_MCIPASSDEVICE message and the WM_ACTIVATE message in the window
  1124.  * procedure of your application.  When you open the device, you specify
  1125.  * the handle of your window procedure as the callback window handle of
  1126.  * the MCI_OPEN_PARMS data structure.  This handle tells MMPM/2 what
  1127.  * window procedure to send the MM_MCIPASSDEVICE message to when control
  1128.  * of the device you're opening is gained or lost by your app. Also, when
  1129.  * you open the device, you specify if you want exclusive use of the
  1130.  * device, or if you're willing to share the device.  The Duet Player
  1131.  * opens all of its devices as shareable devices.  The MMPM/2 default
  1132.  * is to open the device exclusively unless otherwise specified by the
  1133.  * app.
  1134.  *
  1135.  * The implementation shown in the Duet Player Sample Program is just
  1136.  * one possible way to participate in MMPM/2's device sharing scheme.
  1137.  * This implementation was kept simple for the purposes of illustration.
  1138.  * More robust implementations are possible.
  1139.  *
  1140.  * For example, a more complex and robust way of implementing this device
  1141.  * sharing scheme may include logic to make sure we don't lose the device
  1142.  * between the time we open it and the time we play it.  Also, logic
  1143.  * could be added to make sure that another application doesn't have
  1144.  * exclusive use of the device when we open it.  The current implementation
  1145.  * in the Duet Player will simply display an error message to the user
  1146.  * when one of these two situations exist.
  1147.  *
  1148.  *************************************************************************/
  1149. BOOL PlayTheDuet( HWND hwnd)
  1150. {
  1151.    ULONG             ulError;                /* error value from mci calls    */
  1152.    SHORT             sDuet;                  /* duet number to play           */
  1153.    BOOL              bReturn = FALSE;        /* function return value         */
  1154.    MCI_OPEN_PARMS    mopDuetPart;            /* open parms for MCI_OPEN       */
  1155.    MCI_PLAY_PARMS    mppGroup;               /* play parms for MCI_PLAY       */
  1156.    ULONG             ulDeviceList[NUM_PARTS];/* array of device IDs to group  */
  1157.    MCI_GENERIC_PARMS mciGenericParms;        /* generic parms for MCI_CLOSE   */
  1158.    MCI_LOAD_PARMS    mlpLoad;                /* load parms for MCI_LOAD       */
  1159.    MCI_GROUP_PARMS   mgpGroupParms;          /* Group Parms for MCI_GROUP     */
  1160.  
  1161.    /* Get the duet selection from the listbox */
  1162.  
  1163.    sDuet = (USHORT) WinSendMsg( WinWindowFromID( hwnd, ID_LB_DUET),
  1164.                                 LM_QUERYSELECTION,
  1165.                                 (MPARAM) LIT_FIRST,
  1166.                                 (MPARAM) NULL);
  1167.  
  1168.    /* this is a safety net - one should always be selected  */
  1169.  
  1170.    if (sDuet==(SHORT)LIT_NONE)
  1171.    {
  1172.       DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  1173.                       IDS_NO_DUET_SELECTED,
  1174.                       MB_CANCEL | MB_HELP | MB_ERROR | MB_MOVEABLE);
  1175.  
  1176.       return( bReturn);
  1177.    }
  1178.  
  1179.  
  1180.    /*
  1181.     * Before we get ready to open the audio file, we will check to
  1182.     * see it the file exists.  This is important to do since we
  1183.     * can open a file that does not exist to record into it.
  1184.     */
  1185.    if ( DoesFileExist( aDuet[sDuet].achPart1) &&
  1186.         DoesFileExist( aDuet[sDuet].achPart2))
  1187.    {
  1188.  
  1189.       /*
  1190.        * Change pointer to a waiting pointer first, since this might take a
  1191.        * couple of seconds.
  1192.        */
  1193.  
  1194.       WinSetPointer(
  1195.          HWND_DESKTOP,        /* Desktop window handle.                    */
  1196.          WinQuerySysPointer(  /* This API will give the handle of the PTR. */
  1197.             HWND_DESKTOP,     /* Desktop window handle.                    */
  1198.             SPTR_WAIT,        /* The waiting icon.                         */
  1199.             FALSE ) );        /* Return the system pointer's handle.       */
  1200.  
  1201.       if (fFirstPlay)
  1202.       /* If this is the first time thru this routine, then we need to open
  1203.        * the devices and make the group.  That's what this IF is for.
  1204.        *
  1205.        * On subsequent calls to this routine, the devices are already open
  1206.        * and the group is already made, so we only need to load the
  1207.        * appropriate files onto the devices.
  1208.        */
  1209.       {
  1210.          /*
  1211.           * Open one part of the duet. The first step is to initialize an
  1212.           * MCI_OPEN_PARMS data structure with the appropriate information,
  1213.           * then issue the MCI_OPEN command with the mciSendCommand function.
  1214.           * We will be using an open with only the element name specified.
  1215.           * This will cause the default connection, as specified in the MMPM.INI
  1216.           * file, for the data type.
  1217.           */
  1218.          mopDuetPart.hwndCallback       = hwnd;         /* For MM_MCIPASSDEVICE */
  1219.          mopDuetPart.usDeviceID       = (USHORT)  NULL; /* this is returned   */
  1220.          mopDuetPart.pszDeviceType    = (PSZ)   NULL; /* using default conn.  */
  1221.          mopDuetPart.pszElementName   = (PSZ)   aDuet[sDuet].achPart1;
  1222.  
  1223.          ulError = mciSendCommand( (USHORT) 0,
  1224.                                    MCI_OPEN,
  1225.                                    MCI_WAIT | MCI_OPEN_ELEMENT |
  1226.                                    MCI_OPEN_SHAREABLE | MCI_READONLY,
  1227.                                    (PVOID) &mopDuetPart,
  1228.                                    UP_OPEN);
  1229.  
  1230.          if (!ulError)  /* if we opened part 1 */
  1231.          {
  1232.             usDuetPart1ID = mopDuetPart.usDeviceID;
  1233.  
  1234.             /*
  1235.              * Now, open the other part
  1236.              */
  1237.             mopDuetPart.pszElementName    = (PSZ)   aDuet[sDuet].achPart2;
  1238.  
  1239.             ulError = mciSendCommand( (USHORT) 0,
  1240.                                       MCI_OPEN,
  1241.                                       MCI_WAIT | MCI_OPEN_ELEMENT |
  1242.                                       MCI_OPEN_SHAREABLE | MCI_READONLY,
  1243.                                       (PVOID) &mopDuetPart,
  1244.                                       UP_OPEN);
  1245.  
  1246.             if (!ulError)  /* if we opened part 2 */
  1247.             {
  1248.                usDuetPart2ID = mopDuetPart.usDeviceID;
  1249.  
  1250.                /*
  1251.                 * So far, so good.  Now we need to create a group.  To do this,
  1252.                 * we need to fill an array with the ID's of the already open
  1253.                 * devices that we want to group.  Then we call MCI_GROUP to
  1254.                 * create the group and return us a handle to it.
  1255.                 */
  1256.  
  1257.                ulDeviceList[0] = (ULONG)usDuetPart1ID;
  1258.                ulDeviceList[1] = (ULONG)usDuetPart2ID;
  1259.  
  1260.                mgpGroupParms.hwndCallback = (HWND) NULL;          /* Not needed - we're waiting */
  1261.                mgpGroupParms.ulNumDevices = NUM_PARTS;            /* Count of devices           */
  1262.                mgpGroupParms.paulDeviceID = (PULONG)&ulDeviceList;/* Array of devices           */
  1263.                mgpGroupParms.ulStructLength = sizeof (mgpGroupParms);
  1264.  
  1265.                ulError = mciSendCommand( (USHORT) 0,
  1266.                                          MCI_GROUP,
  1267.                                          MCI_WAIT | MCI_GROUP_MAKE|
  1268.                                          MCI_NOPIECEMEAL,
  1269.                                          (PVOID) &mgpGroupParms,
  1270.                                          UP_GROUP);
  1271.  
  1272.                fFirstPlay = FALSE;
  1273.  
  1274.                if (ulError!=MCIERR_SUCCESS)   /* if we did not made the group */
  1275.                {
  1276.                   WinSetPointer(
  1277.                      HWND_DESKTOP,        /* Desktop window handle.             */
  1278.                      WinQuerySysPointer(  /* This API gives handle of the PTR.  */
  1279.                         HWND_DESKTOP,     /* Desktop window handle.             */
  1280.                         SPTR_ARROW,       /* The Arrow icon.                    */
  1281.                         FALSE ) );        /* Return the sys pointer's handle.   */
  1282.  
  1283.                   DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  1284.                                   IDS_CANNOT_MAKE_GROUP,
  1285.                                   MB_CANCEL | MB_HELP | MB_ERROR | MB_MOVEABLE);
  1286.  
  1287.                   /* we need to close parts 1 and 2 */
  1288.  
  1289.                   mciSendCommand( usDuetPart1ID,
  1290.                                   MCI_CLOSE,
  1291.                                   MCI_WAIT,
  1292.                                   (PVOID) &mciGenericParms,
  1293.                                   UP_CLOSE);
  1294.  
  1295.                   usDuetPart1ID = (USHORT) NULL;
  1296.  
  1297.                   mciSendCommand( usDuetPart2ID,
  1298.                                   MCI_CLOSE,
  1299.                                   MCI_WAIT,
  1300.                                   (PVOID) &mciGenericParms,
  1301.                                   UP_CLOSE);
  1302.  
  1303.                   usDuetPart2ID = (USHORT) NULL;
  1304.                }
  1305.                else  /* We did make the group */
  1306.                {
  1307.                   /* The handle of the group is returned in the usGroupID
  1308.                    * field of the structure.  Here, assign it to our global
  1309.                    * variable.
  1310.                    */
  1311.                   usGroupHandle = mgpGroupParms.usGroupID;
  1312.                }
  1313.             }
  1314.             else  /* we didn't open part 2 */
  1315.             {
  1316.  
  1317.                /*
  1318.                 * Change the pointer back to an arrow.
  1319.                 */
  1320.  
  1321.                WinSetPointer(
  1322.                   HWND_DESKTOP,        /* Desktop window handle.             */
  1323.                   WinQuerySysPointer(  /* This API gives handle of the PTR.  */
  1324.                      HWND_DESKTOP,     /* Desktop window handle.             */
  1325.                      SPTR_ARROW,       /* The Arrow icon.                    */
  1326.                      FALSE ) );        /* Return the sys pointer's handle.   */
  1327.  
  1328.                ShowMCIErrorMessage( ulError);
  1329.  
  1330.                /* we need to close part 1 */
  1331.                mciSendCommand( usDuetPart1ID,
  1332.                                MCI_CLOSE,
  1333.                                MCI_WAIT,
  1334.                                (PVOID) &mciGenericParms,
  1335.                                UP_CLOSE);
  1336.  
  1337.                usDuetPart1ID = (USHORT) NULL;
  1338.             }
  1339.          }
  1340.          else  /* we didn't open part 1 */
  1341.          {
  1342.             /*
  1343.              * Change the pointer back to an arrow.
  1344.              */
  1345.  
  1346.             WinSetPointer(
  1347.                HWND_DESKTOP,        /* Desktop window handle.             */
  1348.                WinQuerySysPointer(  /* This API gives handle of the PTR.  */
  1349.                   HWND_DESKTOP,     /* Desktop window handle.             */
  1350.                   SPTR_ARROW,       /* The Arrow icon.                    */
  1351.                   FALSE ) );        /* Return the sys pointer's handle.   */
  1352.             ShowMCIErrorMessage( ulError);
  1353.          }
  1354.       }
  1355.       else        /* Just load the files  */
  1356.       /* If this is the first time thru this routine, then we need to open
  1357.        * the devices and make the group.
  1358.        *
  1359.        * On subsequent calls to this routine, the devices are already open
  1360.        * and the group is already made, so we only need to load the
  1361.        * appropriate files onto the devices.  That's what this ELSE is for.
  1362.        */
  1363.       {
  1364.           /*
  1365.            * Load one part of the duet. The first step is to initialize an
  1366.            * MCI_LOAD_PARMS data structure with the appropriate information,
  1367.            * then issue the MCI_LOAD command with the mciSendCommand function.
  1368.            */
  1369.           mlpLoad.hwndCallback       = (ULONG) NULL;                   /* We're waiting */
  1370.           mlpLoad.pszElementName   = (PSZ)   aDuet[sDuet].achPart1;  /* part 1 of duet */
  1371.  
  1372.           ulError = mciSendCommand( usDuetPart1ID,
  1373.                                     MCI_LOAD,
  1374.                                     MCI_WAIT | MCI_READONLY,
  1375.                                     (PVOID) &mlpLoad,
  1376.                                     (ULONG) NULL);
  1377.           if (!ulError)  /* if we loaded part 1 of the duet on the first device */
  1378.           {
  1379.                /*
  1380.                 * Now, open the other part
  1381.                 */
  1382.                mlpLoad.pszElementName    = (PSZ)   aDuet[sDuet].achPart2;  /* part 2 of duet */
  1383.  
  1384.                ulError = mciSendCommand( usDuetPart2ID,
  1385.                                          MCI_LOAD,
  1386.                                          MCI_WAIT | MCI_READONLY,
  1387.                                          (PVOID) &mlpLoad,
  1388.                                          (ULONG) NULL);
  1389.               if (ulError)  /* if we could not loaded part 2 of the duet */
  1390.               {
  1391.                  /*
  1392.                   * Change the pointer back to an arrow.
  1393.                   */
  1394.  
  1395.                  WinSetPointer(
  1396.                     HWND_DESKTOP,        /* Desktop window handle.             */
  1397.                     WinQuerySysPointer(  /* This API gives handle of the PTR.  */
  1398.                        HWND_DESKTOP,     /* Desktop window handle.             */
  1399.                        SPTR_ARROW,       /* The Arrow icon.                    */
  1400.                        FALSE ) );        /* Return the sys pointer's handle.   */
  1401.                  ShowMCIErrorMessage (ulError);
  1402.               }
  1403.           }
  1404.           else /* if we couldn't load part one of the duet */
  1405.           {
  1406.              /*
  1407.               * Change the pointer back to an arrow.
  1408.               */
  1409.  
  1410.              WinSetPointer(
  1411.                 HWND_DESKTOP,        /* Desktop window handle.             */
  1412.                 WinQuerySysPointer(  /* This API gives handle of the PTR.  */
  1413.                    HWND_DESKTOP,     /* Desktop window handle.             */
  1414.                    SPTR_ARROW,       /* The Arrow icon.                    */
  1415.                    FALSE ) );        /* Return the sys pointer's handle.   */
  1416.              ShowMCIErrorMessage (ulError);
  1417.           }
  1418.  
  1419.       }
  1420.       if (ulError == MCIERR_SUCCESS)
  1421.       {
  1422.           eState = ST_PLAYING;               /* set state to PLAYING    */
  1423.           SetDuetVolume(hwnd);               /* set the starting volume */
  1424.  
  1425.           /*
  1426.            * OK, we've made the group - now we need to start it playing.
  1427.            * First, preroll the devices so they will both start playing
  1428.            * at precisely the same time without any delay.
  1429.            */
  1430.           mciSendCommand( usDuetPart1ID,              /* ID of device   */
  1431.                           MCI_CUE,                    /* CUE message    */
  1432.                           MCI_WAIT | MCI_CUE_OUTPUT,  /* standard flags */
  1433.                           (PVOID)&mciGenericParms,    /* generic struc  */
  1434.                           (USHORT)NULL);              /* no user parm   */
  1435.  
  1436.           mciSendCommand( usDuetPart2ID,              /* ID of device   */
  1437.                           MCI_CUE,                    /* CUE message    */
  1438.                           MCI_WAIT | MCI_CUE_OUTPUT,  /* standard flags */
  1439.                           (PVOID)&mciGenericParms,    /* generic struc  */
  1440.                           (USHORT)NULL);              /* no user parm   */
  1441.  
  1442.            /*
  1443.             * Next, we need to initialize an MCI_PLAY_PARMS structure with
  1444.             * the pertinent information then issue an MCI_PLAY command via
  1445.             * mciSendCommand.  This time we will be using the notification
  1446.             * version of the command - a MM_MCINOTIFY message will be sent
  1447.             * to the window specified in hwndCallback when the operation is
  1448.             * completed.  Since we want the whole audio file to be played,
  1449.             * we won't specify flags of MCI_FROM or MCI_TO so we don't
  1450.             * need to fill in these parameters in the structure.
  1451.             */
  1452.  
  1453.            mppGroup.hwndCallback = hwnd;            /* notify our window    */
  1454.  
  1455.            ulError = mciSendCommand( usGroupHandle,
  1456.                                      MCI_PLAY,
  1457.                                      MCI_NOTIFY,
  1458.                                      (PVOID) &mppGroup,
  1459.                                      UP_PLAY);
  1460.  
  1461.            /*
  1462.             * Change the pointer back to an arrow.
  1463.             */
  1464.  
  1465.            WinSetPointer(
  1466.               HWND_DESKTOP,        /* Desktop window handle.             */
  1467.               WinQuerySysPointer(  /* This API gives handle of the PTR.  */
  1468.                  HWND_DESKTOP,     /* Desktop window handle.             */
  1469.                  SPTR_ARROW,       /* The Arrow icon.                    */
  1470.                  FALSE ) );        /* Return the sys pointer's handle.   */
  1471.  
  1472.            if (ulError)
  1473.            {
  1474.               ShowMCIErrorMessage( ulError);
  1475.  
  1476.               /*
  1477.                * If we couldn't play - we need to halt audio gracefully
  1478.                * and get to stable, known state.
  1479.                */
  1480.  
  1481.               eState = ST_STOPPED;
  1482.               StopTheDuet(hwnd);
  1483.            }
  1484.            else
  1485.               bReturn = TRUE;
  1486.       }
  1487.    }
  1488.    else  /* cannot find audio file */
  1489.    {
  1490.       DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  1491.                       IDS_CANNOT_FIND_AUDIO_FILE,
  1492.                       MB_CANCEL | MB_HELP | MB_ERROR | MB_MOVEABLE);
  1493.    }
  1494.  
  1495.  
  1496.    return( bReturn);
  1497.  
  1498. }  /* end of PlayTheDuet */
  1499.  
  1500.  
  1501.  
  1502. /*************************************************************************
  1503.  * Name         :  PauseTheDuet
  1504.  *
  1505.  * Description  :  This procedure will pause a duet that is playing.
  1506.  *
  1507.  * Concepts     :  Pausing a group.
  1508.  *
  1509.  * MMPM/2 API's :  mciSendCommand    MCI_PAUSE
  1510.  *
  1511.  * Parameters   :  hwnd - Handle for the Main dialog box.
  1512.  *
  1513.  * Return       :  TRUE  -  if the operation was initiated without error.
  1514.  *                 FALSE -  if an error occurred.
  1515.  *
  1516.  *************************************************************************/
  1517. BOOL PauseTheDuet(HWND hwnd)
  1518. {
  1519.    ULONG                ulError;          /* return value for mci command  */
  1520.    MCI_GENERIC_PARMS    mciGenericParms;  /* info data structure for cmd.  */
  1521.  
  1522.  
  1523.    /*
  1524.     * Stop the play button animation
  1525.     */
  1526.    WinSendMsg (
  1527.       WinWindowFromID(
  1528.          hwnd,              /* Dialog window handle      */
  1529.          ID_GPB_PLAY),      /* Id - Play graphic button  */
  1530.       GBM_ANIMATE,          /* Animation control         */
  1531.       MPFROMSHORT(FALSE),   /* Animation flag            */
  1532.       NULL);                /* Ignore return data        */
  1533.  
  1534.    /*
  1535.     * To pause the duet, we will issue an MCI_PAUSE command via mciSendCommand
  1536.     * using an MCI_GENERIC_PARMS structure.  This pause command is done for
  1537.     * the group handle rather than the individual device IDs.  This will cause
  1538.     * the action to be performed for the each device in the group.
  1539.     */
  1540.    mciGenericParms.hwndCallback = hwndMainDialogBox;
  1541.  
  1542.    ulError = mciSendCommand( usGroupHandle,
  1543.                              MCI_PAUSE,
  1544.                              MCI_NOTIFY,
  1545.                              (PVOID) &mciGenericParms,
  1546.                              UP_PAUSE);
  1547.  
  1548.    if (ulError)
  1549.    {
  1550.       ShowMCIErrorMessage( ulError);
  1551.       return( FALSE);
  1552.    }
  1553.    else
  1554.       return( TRUE);
  1555.  
  1556. }  /* end of PauseTheDuet */
  1557.  
  1558.  
  1559.  
  1560. /*************************************************************************
  1561.  * Name         :  ResumeTheDuet
  1562.  *
  1563.  * Description  :  This procedure will resume the playing of the duet that
  1564.  *                 has been paused.
  1565.  *
  1566.  * Concepts     :  Resuming a group.
  1567.  *
  1568.  * MMPM/2 API's :  mciSendCommand    MCI_RESUME
  1569.  *
  1570.  * Parameters   :  hwnd - Handle for the Main dialog box.
  1571.  *
  1572.  * Return       :  TRUE if the operation was initiated without error.
  1573.  *                 FALSE if an error occurred.
  1574.  *
  1575.  *************************************************************************/
  1576. BOOL ResumeTheDuet(HWND hwnd)
  1577. {
  1578.    ULONG                ulError;          /* return value for mci command  */
  1579.    MCI_GENERIC_PARMS    mciGenericParms;  /* info data structure for cmd.  */
  1580.  
  1581.  
  1582.    /*
  1583.     * To resume the duet, we will issue an MCI_RESUME command via mciSendCommand
  1584.     * using an MCI_GENERIC_PARMS structure.  This pause command is done for
  1585.     * the group handle rather than the individual device IDs.  This will cause
  1586.     * the action to be performed for the each device in the group.
  1587.     */
  1588.    mciGenericParms.hwndCallback = hwndMainDialogBox;
  1589.  
  1590.    ulError = mciSendCommand( usGroupHandle,
  1591.                              MCI_RESUME,
  1592.                              MCI_NOTIFY,
  1593.                              (PVOID) &mciGenericParms,
  1594.                              UP_RESUME);
  1595.  
  1596.  
  1597.    if (ulError)
  1598.    {
  1599.       ShowMCIErrorMessage( ulError);
  1600.       return( FALSE);
  1601.    }
  1602.    else
  1603.    {
  1604.       /*
  1605.        * Start the play button animation
  1606.        */
  1607.       WinSendMsg (
  1608.          WinWindowFromID(
  1609.             hwnd,             /* Dialog window handle      */
  1610.             ID_GPB_PLAY),     /* Id - Play graphic button  */
  1611.          GBM_ANIMATE,         /* Animation control         */
  1612.          MPFROMSHORT(TRUE),   /* Animation flag            */
  1613.          NULL);               /* Ignore return data        */
  1614.       return( TRUE);
  1615.    }
  1616.  
  1617. }  /* End of ResumeTheDuet */
  1618.  
  1619.  
  1620.  
  1621. /*************************************************************************
  1622.  * Name         :  StopTheDuet
  1623.  *
  1624.  * Description  :  This procedure will stop the duet that is playing or
  1625.  *                 paused.
  1626.  *
  1627.  * Concepts     :  Stopping a group.
  1628.  *
  1629.  * MMPM/2 API's :  mciSendCommand    MCI_STOP
  1630.  *
  1631.  * Parameters   :  hwnd - Handle for the Main dialog box.
  1632.  *
  1633.  * Return       :  nothing.
  1634.  *
  1635.  *************************************************************************/
  1636. VOID StopTheDuet(HWND hwnd)
  1637. {
  1638.    ULONG                ulError;          /* return value for mci command  */
  1639.    MCI_GENERIC_PARMS    mciGenericParms;  /* info data structure for cmd.  */
  1640.  
  1641.    /*
  1642.     * Stop the play button animation
  1643.     */
  1644.    WinSendMsg (
  1645.       WinWindowFromID(
  1646.          hwnd,             /* Dialog window handle      */
  1647.          ID_GPB_PLAY),     /* Id - Play graphic button  */
  1648.       GBM_ANIMATE,         /* Animation control         */
  1649.       MPFROMSHORT(FALSE),  /* Animation flag            */
  1650.       NULL);               /* Ignore return data        */
  1651.  
  1652.    /*
  1653.     * To stop the duet, we will issue an MCI_STOP command via mciSendCommand
  1654.     * using an MCI_GENERIC_PARMS structure.  This pause command is done for
  1655.     * the group handle rather than the individual device IDs.  This will cause
  1656.     * the action to be performed for the each device in the group.
  1657.     */
  1658.    mciGenericParms.hwndCallback = hwndMainDialogBox;
  1659.  
  1660.    ulError = mciSendCommand( usGroupHandle,
  1661.                              MCI_STOP,
  1662.                              MCI_NOTIFY,
  1663.                              (PVOID) &mciGenericParms,
  1664.                              UP_STOP);
  1665.    if (ulError)
  1666.       ShowMCIErrorMessage( ulError);
  1667.  
  1668.    return;
  1669.  
  1670. }  /* end of StopTheDuet */
  1671.  
  1672.  
  1673.  
  1674. /*************************************************************************
  1675.  * Name         :  CloseTheDuet
  1676.  *
  1677.  * Description  :  This procedure will close both parts of the duet and
  1678.  *                 delete the group.
  1679.  *
  1680.  * Concepts     :  Deleting a group.
  1681.  *                 Closing mci devices.
  1682.  *
  1683.  * MMPM/2 API's :  mciSendCommand    MCI_CLOSE
  1684.  *                                   MCI_GROUP
  1685.  *
  1686.  * Parameters   :  None.
  1687.  *
  1688.  * Return       :  nothing.
  1689.  *
  1690.  *************************************************************************/
  1691.  
  1692. VOID CloseTheDuet( VOID)
  1693. {
  1694.    ULONG                ulError;          /* return value for mci command  */
  1695.    MCI_GENERIC_PARMS    mciGenericParms;  /* info data structure for cmd.  */
  1696.    MCI_GROUP_PARMS   mgpGroupParms;       /* Group Parms for MCI_GROUP     */
  1697.  
  1698.    mciGenericParms.hwndCallback = hwndMainDialogBox;
  1699.  
  1700.    /*
  1701.     * Now, we will close the group.  This is done by issuing an
  1702.     * MCI_CLOSE command to the groups ID.  Also, we'll set the global
  1703.     * device IDs to NULL since they will no longer be valid.
  1704.     */
  1705.    ulError = mciSendCommand( usGroupHandle,
  1706.                              MCI_CLOSE,
  1707.                              MCI_NOTIFY,
  1708.                              (PVOID) &mciGenericParms,
  1709.                              UP_CLOSE);
  1710.    if (ulError)
  1711.       ShowMCIErrorMessage( ulError);
  1712.  
  1713.    usDuetPart1ID = (USHORT) NULL;
  1714.    usDuetPart2ID = (USHORT) NULL;
  1715.  
  1716.    /* Now, we need to kill the group - also we'll set its handle to NULL.  */
  1717.  
  1718.     mgpGroupParms.hwndCallback = (HWND) NULL;          /* Not needed - we're waiting */
  1719.     mgpGroupParms.usGroupID    = usGroupHandle;        /* Id of group to delete      */
  1720.     mgpGroupParms.ulStructLength = sizeof (mgpGroupParms);
  1721.  
  1722.     ulError = mciSendCommand( (USHORT) 0,
  1723.                                          MCI_GROUP,
  1724.                                          MCI_WAIT | MCI_GROUP_DELETE,
  1725.                                          (PVOID) &mgpGroupParms,
  1726.                                          UP_GROUP);
  1727.    usGroupHandle = (USHORT) NULL;
  1728.  
  1729.    return;
  1730.  
  1731. }  /* end of CloseTheDuet */
  1732.  
  1733.  
  1734.  
  1735. /*************************************************************************
  1736.  * Name         :  ShowMCIErrorMessage
  1737.  *
  1738.  * Description  :  This window procedure displays an MCI error message based
  1739.  *                 based upon a ulError return code.  The MCI function
  1740.  *                 mciGetErrorString is used to convert the error code into
  1741.  *                 a text string and the title is pulled from the resource
  1742.  *                 based upon a string id.
  1743.  *
  1744.  * Concepts     :  Using mciGetErrorString to convert an error code into
  1745.  *                 a textual message.  Error handling of mciGetErrorString.
  1746.  *
  1747.  * MMPM/2 API's :  mciGetErrorString
  1748.  *
  1749.  * Parameters   :  ulError  -  MCI error code.
  1750.  *
  1751.  * Return       :  nothing
  1752.  *
  1753.  *************************************************************************/
  1754. VOID  ShowMCIErrorMessage( ULONG ulError)
  1755. {
  1756.    CHAR  achTitle[LEN_ERROR_TITLE];
  1757.    CHAR  achBuffer[LEN_ERROR_MESSAGE];
  1758.  
  1759.    switch(mciGetErrorString( ulError, (PSZ)achBuffer,   sizeof( achBuffer)))
  1760.    {
  1761.       case MCIERR_SUCCESS:
  1762.          /*
  1763.           * This is what we want.  We were able to use mciGetErrorString to
  1764.           * retrieve a textual error message we can show in a message box.
  1765.           * Now, we need to load the string for the title of the message box.
  1766.           * Then, we'll show it to the user.
  1767.           */
  1768.          WinLoadString( hab,
  1769.                         (HMODULE) NULL,
  1770.                         IDS_DUET_PLAYER_ERROR,
  1771.                         (SHORT) sizeof( achTitle),
  1772.                         achTitle );
  1773.  
  1774.          WinMessageBox( HWND_DESKTOP,
  1775.                         hwndMainDialogBox,
  1776.                         achBuffer,
  1777.                         achTitle,
  1778.                         (USHORT) ID_MESSAGEBOX,
  1779.                         MB_CANCEL | MB_HELP | MB_ERROR | MB_MOVEABLE);
  1780.          break;
  1781.  
  1782.       case MCIERR_INVALID_DEVICE_ID:
  1783.       case MCIERR_OUTOFRANGE:
  1784.       case MCIERR_INVALID_BUFFER:
  1785.       default:
  1786.          DuetMessageBox( IDS_DUET_PLAYER_ERROR,
  1787.                          IDS_UNKNOWN,
  1788.                          MB_CANCEL | MB_HELP | MB_ERROR | MB_MOVEABLE);
  1789.          break;
  1790.    }
  1791.  
  1792.    return;
  1793.  
  1794. }  /* end of ShowMCIErrorMessage */
  1795.  
  1796.  
  1797.  
  1798. /*************************************************************************
  1799.  * Name         :  DoesFileExist
  1800.  *
  1801.  * Description  :  This helper function determines if a file with a given
  1802.  *                filename exists.
  1803.  *
  1804.  * Concepts     :  Using MMIO interface to access a data file.
  1805.  *
  1806.  * MMPM/2 API's :  mmioOpen
  1807.  *                 mmioClose
  1808.  *
  1809.  * Parameters   :  pszFilename -  The filename to be tested
  1810.  *
  1811.  * Return       :  TRUE  -  if the a file exists matching pszFilename
  1812.  *                 FALSE -  if the file does not exist
  1813.  *
  1814.  *************************************************************************/
  1815. BOOL DoesFileExist( PSZ pszFilename)
  1816. {
  1817.    BOOL  bReturn;    /* function return value   */
  1818.    HMMIO hFile;      /* handle to file          */
  1819.  
  1820.    /*
  1821.     * Notice that these MMIO functions are analogous to the standard
  1822.     * C functions, fopen and fclose.
  1823.     */
  1824.  
  1825.    hFile = mmioOpen( pszFilename, (PMMIOINFO) NULL, MMIO_READ);
  1826.  
  1827.    if (hFile != (HMMIO) NULL)
  1828.    {
  1829.       mmioClose( hFile, 0);
  1830.       bReturn = TRUE;
  1831.    }
  1832.    else
  1833.       bReturn = FALSE;
  1834.  
  1835.    return( bReturn);
  1836. }
  1837.  
  1838.  
  1839.  
  1840. /*************************************************************************
  1841.  * Name         :  SetDuetVolume
  1842.  *
  1843.  * Description  :  This helper function sets the duet volume based upon the
  1844.  *                 position of the volume slider.  The slider will be queried
  1845.  *                 and the duet volume will be set.
  1846.  *
  1847.  * Concepts     :  Setting the volume of a group.
  1848.  *
  1849.  * MMPM/2 API's :  mciSendCommand    MCI_SET
  1850.  *
  1851.  * Parameters   :  hwnd - Handle for the Main dialog box.
  1852.  *
  1853.  * Return       :  nothing.
  1854.  *
  1855.  *************************************************************************/
  1856. VOID SetDuetVolume( HWND hwnd)
  1857. {
  1858.    ULONG                ulError;       /* error value for mci returns   */
  1859.    MCI_WAVE_SET_PARMS   mspSet;        /* set values for volume, etc.   */
  1860.  
  1861.  
  1862.    if ((!fPassedDuet) && (eState==ST_PLAYING || eState==ST_PAUSED))
  1863.    {
  1864.       /*
  1865.        * To set the volume,  first, the MCI_SET_PARMS structure must be
  1866.        * filled with the necessary values.  Then an MCI_SET command
  1867.        * should be issued to each device to perform the volume change.
  1868.        */
  1869.       mspSet.hwndCallback = hwnd;
  1870.       mspSet.ulAudio    = MCI_SET_AUDIO_ALL;    /* set all channels     */
  1871.       mspSet.ulLevel    = (ULONG) sVolumeLevel; /* volume level desired */
  1872.  
  1873.       ulError = mciSendCommand( usDuetPart1ID,
  1874.                                 MCI_SET,
  1875.                                 MCI_NOTIFY | MCI_SET_AUDIO | MCI_SET_VOLUME,
  1876.                                 (PVOID) &mspSet,
  1877.                                 UP_VOLUME);
  1878.  
  1879.       ulError = mciSendCommand( usDuetPart2ID,
  1880.                                 MCI_SET,
  1881.                                 MCI_NOTIFY | MCI_SET_AUDIO | MCI_SET_VOLUME,
  1882.                                 (PVOID) &mspSet,
  1883.                                 UP_VOLUME);
  1884.       if (ulError)
  1885.          ShowMCIErrorMessage( ulError);
  1886.    }
  1887.  
  1888.    return;
  1889.  
  1890. }  /* end of SetDuetVolume */
  1891.