home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / mmpm2tk / mmpmtlk2 / admct / audiosub.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  97.6 KB  |  3,194 lines

  1. /******************
  2. *
  3. * SOURCE FILE NAME:             AUDIOSUB.C
  4. *
  5. * DESCRIPTIVE NAME:     Support functions for waveaudio MCI Driver.
  6. *
  7. *              Copyright (c) IBM Corporation  1991
  8. *                        All Rights Reserved
  9. *
  10. * STATUS: MM Extensions 1.0
  11. *
  12. * NOTES:    THIS MODULE RESIDES AT RING 3
  13. *
  14. *    DEPENDENCIES: NONE
  15. *    RESTRICTIONS: NONE
  16. *
  17. * MODIFICATION HISTORY:
  18. * DATE      DEVELOPER         CHANGE DESCRIPTION
  19. *********************** END OF SPECIFICATIONS ********************************/
  20. #define INCL_BASE
  21. #define INCL_DOSMODULEMGR
  22. #define INCL_DOSSEMAPHORES
  23.  
  24. #include <os2.h>                        // OS2 defines.
  25. #include <string.h>                     // String functions.
  26. #include <os2medef.h>                   // MME includes files.
  27. #include <math.h>                       // Standard Math Lib
  28. #include <stdlib.h>                     // Standard Library
  29. #include <audio.h>                      // Audio Device defines
  30. #include <ssm.h>                        // SSM spi includes.
  31. #include <meerror.h>                    // MM Error Messages.
  32. #include <mmsystem.h>                   // MM System Include.
  33. #include <mcidrv.h>                     // MCI Driver include.
  34. #include <mmio.h>                       // MMIO Include.
  35. #include <mcd.h>                        // AudioIFDriverInterface.
  36. #include <hhpheap.h>                    // Heap Manager Definitions
  37. #include <admcdat.h>                    // Data Format defines
  38. #include <audiomcd.h>                   // Component Definitions.
  39. #include <admcfunc.h>
  40.  
  41. /********************* START OF SPECIFICATIONS *******************************
  42. *
  43. * SUBROUTINE NAME: DestroyStream()
  44. *
  45. * DESCRIPTIVE NAME:
  46. *
  47. * FUNCTION: call SpiDestroyStream
  48. *
  49. *
  50. * NOTES:
  51. * ENTRY POINTS:
  52. *     LINKAGE:   CALL FAR
  53. *
  54. * INPUT:
  55. *
  56. * EXIT-NORMAL: Return Code 0.
  57. *
  58. * EXIT_ERROR:  Error Code.
  59. *
  60. * EFFECTS:
  61. *
  62. * INTERNAL REFERENCES: None
  63. *
  64. * EXTERNAL REFERENCES: None
  65. *
  66. *********************** END OF SPECIFICATIONS *******************************/
  67.  
  68. RC DestroyStream (HSTREAM hStream)
  69. {
  70.  
  71.   ULONG ulrc;
  72.   /************************************
  73.   * Call SpiDestroyStream
  74.   *************************************/
  75.   ulrc = SpiDestroyStream (hStream);
  76.  
  77.   return ulrc;
  78. }
  79.  
  80. /********************* START OF SPECIFICATIONS *******************************
  81. *
  82. * SUBROUTINE NAME: SetAmpDefaults ()
  83. *
  84. * DESCRIPTIVE NAME:
  85. *
  86. * FUNCTION: Set AMP Mixer default values for treble, bass and so on.
  87. *
  88. *
  89. * NOTES:
  90. * ENTRY POINTS:
  91. *     LINKAGE:   CALL FAR
  92. *
  93. * INPUT:
  94. *
  95. * EXIT-NORMAL: Return Code 0.
  96. *
  97. * EXIT_ERROR:  Error Code.
  98. *
  99. * EFFECTS:
  100. *
  101. * INTERNAL REFERENCES: None
  102. *
  103. * EXTERNAL REFERENCES: None
  104. *
  105. *********************** END OF SPECIFICATIONS *******************************/
  106.  
  107. RC  SetAmpDefaults (INSTANCE * ulpInstance)
  108. {
  109.  
  110.    /*********************************
  111.    * Amp/Mixer Default Audio levels
  112.    **********************************/
  113.  
  114.    AMPMIX.usMasterVolume = 50;
  115.    AMPMIX.lVolumeDelay = 0L;
  116.    AMPMIX.lBalanceDelay = 0L;
  117.    AMPMIX.lPitch = 50L;
  118.  
  119.    /************************************************************
  120.    * Check to see if volume, bass, treble, and balance levels
  121.    * have been explicitly set by the user. If they have not
  122.    * been intialized then the default values are set
  123.    **************************************************************/
  124.    if (AMPMIX.lLeftVolume == NOT_INTIALIZED)
  125.        AMPMIX.lLeftVolume = 100L;
  126.  
  127.    if (AMPMIX.lRightVolume == NOT_INTIALIZED)
  128.        AMPMIX.lRightVolume = 100L;
  129.  
  130.    if (AMPMIX.lBass == NOT_INTIALIZED)
  131.        AMPMIX.lBass = 50L;
  132.  
  133.    if (AMPMIX.lBalance == NOT_INTIALIZED)
  134.        AMPMIX.lBalance = 50L;
  135.  
  136.    if (AMPMIX.lBass == NOT_INTIALIZED)
  137.        AMPMIX.lBass = 50L;
  138.  
  139.    if (AMPMIX.lTreble == NOT_INTIALIZED)
  140.        AMPMIX.lTreble = 100L;
  141.  
  142.    return (MCIERR_SUCCESS);
  143. }
  144.  
  145. /********************* START OF SPECIFICATIONS *******************************
  146. *
  147. * SUBROUTINE NAME: CheckFlags()
  148. *
  149. * DESCRIPTIVE NAME:
  150. *
  151. * FUNCTION: Check for illegal combination of flags
  152. *
  153. *
  154. * NOTES:
  155. * ENTRY POINTS:
  156. *     LINKAGE:   CALL FAR
  157. *
  158. * INPUT:
  159. *
  160. * EXIT-NORMAL: Return Code 0.
  161. *
  162. * EXIT_ERROR:  Error Code.
  163. *
  164. * EFFECTS:
  165. *
  166. * INTERNAL REFERENCES: None
  167. *
  168. * EXTERNAL REFERENCES: None
  169. *
  170. *********************** END OF SPECIFICATIONS *******************************/
  171. RC  CheckFlags (ULONG ulParam1)
  172. {
  173.   if ((ulParam1 & MCI_WAIT) && (ulParam1 & MCI_NOTIFY))
  174.       return MCIERR_FLAGS_NOT_COMPATIBLE;
  175.  
  176.   return (MCIERR_SUCCESS);
  177. }
  178.  
  179.  
  180. /************************** START OF SPECIFICATIONS *************************/
  181. /*                                                                          */
  182. /* SUBROUTINE NAME: CheckMem                                                */
  183. /*                                                                          */
  184. /* DESCRIPTIVE NAME: Memory Check                                           */
  185. /*                                                                          */
  186. /* FUNCTION: Tests memory at specified address and length to see if it      */
  187. /*           exists for the application and if it has the right access.     */
  188. /*                                                                          */
  189. /* NOTES:    This routine contains OS/2 system specific functions.          */
  190. /*           DosQueryMem                                                    */
  191. /*                                                                          */
  192. /* INPUT:    pmem      - Address of memory to test                          */
  193. /*           ulLength  - Length of memory to test                           */
  194. /*           ulFlags   - Memory flags where:                                */
  195. /*                          PAG_EXECUTE                                     */
  196. /*                          PAG_READ                                        */
  197. /*                          PAG_WRITE                                       */
  198. /*                                                                          */
  199. /* OUTPUT:   rc = error return code.                                        */
  200. /*                                                                          */
  201. /* SIDE EFFECTS:                                                            */
  202. /*                                                                          */
  203. /*************************** END OF SPECIFICATIONS **************************/
  204.  
  205. RC CheckMem ( PVOID pMem,
  206.               ULONG ulLength,
  207.               ULONG ulFlags )
  208. {
  209.  
  210.   RC rc = NO_ERROR;                       // local return code
  211.   ULONG ulLengthLeft;                     // length left to check
  212.   ULONG ulTotLength = 0L;                 // Total length checked
  213.   ULONG ulRetFlags = (ULONG)NULL;         // Flags returned from Dos call
  214.  
  215.   /**************************************************************************/
  216.   /*                                                                        */
  217.   /*   Set up to check memory.                                              */
  218.   /*                                                                        */
  219.   /**************************************************************************/
  220.  
  221.   ulLengthLeft = ulLength;
  222.   while ((!rc) && (ulTotLength < ulLength))
  223.     {                                             // Call OS to check mem
  224.       if (!(rc = DosQueryMem(pMem, &ulLengthLeft, &ulRetFlags)))
  225.         {                                         // We have the flags
  226.           if ((ulRetFlags & PAG_FREE) ||          // if free then error
  227.               !(ulRetFlags & PAG_COMMIT) ||       // if not committed then error
  228.                                                   // if execute only
  229.               ((ulRetFlags & ulFlags) != ulFlags))
  230.             {
  231.               rc = ERROR_INVALID_BLOCK;
  232.             }
  233.           else
  234.             {
  235.               pMem =(PVOID)((ULONG)pMem + ulLengthLeft);
  236.               ulTotLength += ulLengthLeft;
  237.               ulLengthLeft = ulLength - ulTotLength;
  238.             }
  239.         }
  240.     }
  241.   return(rc);
  242. }
  243.  
  244. /********************* START OF SPECIFICATIONS *******************************
  245. *
  246. * SUBROUTINE NAME:              PostMDMMessage()
  247. *
  248. * DESCRIPTIVE NAME:
  249. *
  250. * FUNCTION: Post The appropriate Notification message using mdmDriverNotify ()
  251. *
  252. *
  253. * NOTES:
  254. * ENTRY POINTS:
  255. *     LINKAGE:   CALL FAR
  256. *
  257. * INPUT:
  258. *
  259. * EXIT-NORMAL: Return Code 0.
  260. *
  261. * EXIT_ERROR:  Error Code.
  262. *
  263. * EFFECTS:
  264. *
  265. * INTERNAL REFERENCES:  Post_MDM_Message()
  266. *
  267. * EXTERNAL REFERENCES:
  268. *
  269. *********************** END OF SPECIFICATIONS *******************************/
  270.  
  271. RC PostMDMMessage (ULONG ulErrCode, USHORT usMessage,
  272.                       FUNCTION_PARM_BLOCK *pFuncBlock)
  273. {
  274.  
  275.   ULONG   ulrc = MCIERR_SUCCESS;
  276.   USHORT  usNotifyType;
  277.   USHORT  usUserParm;
  278.   HWND    hWnd;
  279.  
  280.  
  281.  
  282.   usNotifyType = MCI_NOTIFY_SUCCESSFUL;        // Intialize as success
  283.  
  284.   /***************************************************************
  285.   * Determine the MCI Notification Code for this message
  286.   ****************************************************************/
  287.  
  288.   switch (DWORD_LOWD(ulErrCode))
  289.   {
  290.  
  291.   case MCI_NOTIFY_SUCCESSFUL:
  292.         usNotifyType = MCI_NOTIFY_SUCCESSFUL;
  293.        break;
  294.  
  295.   case MCI_NOTIFY_SUPERSEDED:
  296.         usNotifyType = MCI_NOTIFY_SUPERSEDED;
  297.        break;
  298.  
  299.   case MCI_NOTIFY_ABORTED:
  300.         usNotifyType = MCI_NOTIFY_ABORTED;
  301.        break;
  302.  
  303.   default:
  304.         usNotifyType = (USHORT)ulErrCode;
  305.        break;
  306.   }
  307.   /*******************************************************************
  308.   * MCI Messages PLAY and RECORD call this routine to notify the
  309.   * application asynchronously. The user parameter from the instance
  310.   * block is used for notifying play/record message status. All
  311.   * other messages use the function block user parameter.
  312.   *******************************************************************/
  313.   if (usMessage != MCI_PLAY && usMessage != MCI_RECORD)
  314.      {
  315.      usUserParm = pFuncBlock->usUserParm;
  316.      hWnd = pFuncBlock->dwCallback;
  317.      }
  318.   else
  319.      {
  320.      usUserParm = pFuncBlock->pInstance->usUserParm;
  321.      hWnd = pFuncBlock->pInstance->dwCallback;
  322.      }
  323.  
  324.   /******************************************************************
  325.   * If Incoming message is a play and it is from an async play then
  326.   * do not call driver notify.
  327.   *******************************************************************/
  328.  
  329.   ulrc = mdmDriverNotify ((WORD)pFuncBlock->pInstance->wWaveDeviceID,
  330.                           (HWND)hWnd,
  331.                           MM_MCINOTIFY,
  332.                           usUserParm,
  333.                           MAKEULONG (usMessage, usNotifyType));
  334.  
  335.  
  336.   return (MCIERR_SUCCESS);
  337. }
  338.  
  339.  
  340.  
  341. /********************* START OF SPECIFICATIONS *******************************
  342. *
  343. * SUBROUTINE NAME:              MCDCAPS
  344. *
  345. * DESCRIPTIVE NAME: Waveform and MIDI Audio Device Capabilities.
  346. *
  347. * FUNCTION: Get Waveform and MIDI Audio Device Static Capabilities.
  348. *
  349. * NOTES:
  350. *
  351. * ENTRY POINTS:
  352. *     LINKAGE:   CALL FAR
  353. *
  354. * INPUT: MCI_GETDEVCAPS message.
  355. *
  356. * EXIT-NORMAL: Return Code 0.
  357. *
  358. * EXIT_ERROR:  Error Code.
  359. *
  360. * EFFECTS:
  361. *
  362. * INTERNAL REFERENCES:
  363. *
  364. * EXTERNAL REFERENCES: None.
  365. *
  366. *********************** END OF SPECIFICATIONS ********************************/
  367.  
  368. RC MCICaps( FUNCTION_PARM_BLOCK *pFuncBlock, ULONG ulDeviceType)
  369. {
  370.   ULONG                  ulrc;                // MME Error Value
  371.   ULONG                  ulParam1;            // Msg Flags
  372.   ULONG                  ulParam2;            // Msg Data
  373.   INSTANCE               * ulpInstance;       // Local Instance
  374.   LPMCI_GETDEVCAPS_PARMS pParams;             // Msg Data Ptr
  375.   ULONG                  ulType;              // Msgs supported.
  376.   DWORD                  dwCapsFlags;         // Mask for Incoming MCI Flags
  377.  
  378.   /**************************************
  379.   * Derefernce Pointers.
  380.   **************************************/
  381.   ulParam1 =   pFuncBlock->ulParam1;
  382.   ulrc = MCIERR_SUCCESS;
  383.   dwCapsFlags = 0;
  384.   ulParam2 =   pFuncBlock->ulParam2;
  385.   ulpInstance= (INSTANCE *)(pFuncBlock->ulpInstance);
  386.   dwCapsFlags = ulParam1;
  387.  
  388.   /***********************************
  389.   * Check incoming MCI Flags.
  390.   ************************************/
  391.   dwCapsFlags &= ~MCI_WAIT;
  392.   dwCapsFlags &= ~MCI_NOTIFY;
  393.  
  394.   /*****************************************
  395.   * Check for Invalid Flags
  396.   *****************************************/
  397.   dwCapsFlags &= ~(MCI_GETDEVCAPS_MESSAGE + MCI_GETDEVCAPS_ITEM);
  398.   if (dwCapsFlags > 0 )
  399.       return MCIERR_INVALID_FLAG;
  400.  
  401.   /********************************************
  402.   * Check for Invalid Combination of flags
  403.   ********************************************/
  404.  
  405.   if (ulParam1 & MCI_GETDEVCAPS_ITEM && ulParam1 & MCI_GETDEVCAPS_MESSAGE)
  406.       return MCIERR_FLAGS_NOT_COMPATIBLE;
  407.  
  408.   /*********************************************
  409.   * Check Pointer to Return Information
  410.   **********************************************/
  411.   ulrc = CheckMem ((PVOID)pFuncBlock->ulParam2,
  412.                    sizeof (MCI_GETDEVCAPS_PARMS), PAG_READ | PAG_WRITE );
  413.  
  414.   if (ulrc != MCIERR_SUCCESS)
  415.       return MCIERR_MISSING_PARAMETER;
  416.  
  417.   ulType = ulParam1 & (MCI_GETDEVCAPS_MESSAGE | MCI_GETDEVCAPS_ITEM);
  418.  
  419.   /************************************
  420.   * Check for missing flags
  421.   *************************************/
  422.   if (!ulType)
  423.       return (MCIERR_MISSING_FLAG);
  424.  
  425.   pParams = (LPMCI_GETDEVCAPS_PARMS )ulParam2;    // Dereference Pointers.
  426.  
  427.   switch (ulType)
  428.   {
  429.  
  430.   case MCI_GETDEVCAPS_MESSAGE:
  431.        {
  432.  
  433.        switch (pParams->wMessage)
  434.        {
  435.  
  436.  
  437.        case MCI_RELEASEDEVICE: case MCI_ACQUIREDEVICE:
  438.        case MCI_OPEN:        case MCI_PLAY:       case MCI_PAUSE:
  439.        case MCI_SEEK:        case MCI_RECORD:     case MCI_CLOSE:
  440.        case MCI_INFO:        case MCI_GETDEVCAPS: case MCI_SET:
  441.        case MCI_STATUS:      case MCI_MASTERAUDIO:case MCI_CUE:
  442.        case MCI_STOP:        case MCI_LOAD:       case MCI_RESUME:
  443.        case MCI_SET_POSITION_ADVISE:      case MCI_SET_CUEPOINT:
  444.        case MCI_CONNECTOR: case MCI_SET_SYNC_OFFSET:case MCI_SAVE:
  445.  
  446.             pParams->dwReturn = MCI_TRUE;
  447.  
  448.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  449.            break;
  450.  
  451.        /******************************
  452.         * List Unsupported Functions
  453.        ******************************/
  454.  
  455.       case MCI_DEVICESETTINGS:
  456.       case MCI_STEP:            case MCI_SYSINFO:
  457.       case MCI_UPDATE:          case MCI_GETTOC:
  458.       case MCI_SPIN:            case MCI_ESCAPE:
  459.            pParams->dwReturn = MCI_FALSE;
  460.  
  461.            ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  462.           break;
  463.  
  464.       default: return MCIERR_UNRECOGNIZED_COMMAND;
  465.  
  466.       } /* Message Switch */
  467.   } /* Item Switch */
  468.   break;                                     // Message case
  469.  
  470.   case MCI_GETDEVCAPS_ITEM:
  471.   {
  472.        switch (pParams->dwItem)
  473.        {
  474.  
  475.        case MCI_GETDEVCAPS_DEVICE_TYPE:
  476.             pParams->dwReturn = ulDeviceType;
  477.             ulrc = MAKEULONG (ulrc, MCI_DEVICENAME_RETURN);
  478.            break;
  479.  
  480.        case MCI_GETDEVCAPS_CAN_RECORD:
  481.             if (ulDeviceType == MCI_DEVTYPE_WAVEFORM_AUDIO)
  482.               {
  483.               if ( ulpInstance->ulCanRecord )
  484.                 {
  485.                 pParams->dwReturn = MCI_TRUE;
  486.                 }
  487.               else
  488.                 {
  489.                 pParams->dwReturn = MCI_FALSE;
  490.                 }
  491.               }
  492.             else
  493.             {
  494.                 pParams->dwReturn = MCI_FALSE;
  495.             }
  496.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  497.            break;
  498.  
  499.  
  500.        case MCI_GETDEVCAPS_HAS_AUDIO:
  501.             pParams->dwReturn = MCI_TRUE;
  502.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  503.            break;
  504.  
  505.        case MCI_GETDEVCAPS_HAS_VIDEO:
  506.             pParams->dwReturn = MCI_FALSE;
  507.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  508.            break;
  509.  
  510.        case MCI_GETDEVCAPS_USES_FILES:
  511.             pParams->dwReturn = MCI_TRUE;
  512.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  513.            break;
  514.  
  515.        case MCI_GETDEVCAPS_CAN_PLAY:
  516.             pParams->dwReturn = MCI_TRUE;
  517.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  518.            break;
  519.  
  520.        case MCI_GETDEVCAPS_CAN_SAVE:
  521.              if ( ulpInstance->ulCanSave )
  522.                {
  523.                pParams->dwReturn = MCI_TRUE;
  524.                }
  525.              else
  526.                {
  527.                pParams->dwReturn = MCI_FALSE;
  528.                }
  529.              ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  530.             break;
  531.  
  532. case MCI_GETDEVCAPS_CAN_RECORD_INSERT:
  533.              if ( ulpInstance->ulCanInsert )
  534.                {
  535.                pParams->dwReturn = MCI_TRUE;
  536.                }
  537.              else
  538.                {
  539.                pParams->dwReturn = MCI_FALSE;
  540.                }
  541.  
  542.              ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  543.             break;
  544.  
  545.        case MCI_GETDEVCAPS_CAN_EJECT:
  546.              pParams->dwReturn = MCI_FALSE;
  547.              ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  548.             break;
  549.  
  550.        case MCI_GETDEVCAPS_CAN_STREAM:
  551.              pParams->dwReturn = MCI_TRUE;
  552.              ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  553.              break;
  554.  
  555.        case MCI_GETDEVCAPS_CAN_PROCESS_INTERNAL:
  556.              pParams->dwReturn = MCI_FALSE;
  557.              ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  558.              break;
  559.  
  560.        case MCI_GETDEVCAPS_CAN_LOCKEJECT:
  561.             pParams->dwReturn = MCI_FALSE;
  562.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  563.             break;
  564.  
  565.        case MCI_GETDEVCAPS_CAN_SETVOLUME:
  566.             pParams->dwReturn = MCI_TRUE;
  567.             ulrc = MAKEULONG (ulrc, MCI_TRUE_FALSE_RETURN);
  568.             break;
  569.  
  570.        case MCI_GETDEVCAPS_PREROLL_TYPE:
  571.             pParams->dwReturn = MCI_PREROLL_NOTIFIED;
  572.              ulrc = MAKEULONG (ulrc, MCI_INTEGER_RETURNED);
  573.             break;
  574.  
  575.        case MCI_GETDEVCAPS_PREROLL_TIME:
  576.             pParams->dwReturn = 0;    // This is to be corrected
  577.             ulrc = MAKEULONG (ulrc, MCI_INTEGER_RETURNED);
  578.             break;
  579.  
  580.        default:  return MCIERR_UNSUPPORTED_FLAG;
  581.               break;
  582.  
  583.  
  584.        }       /* items of item */
  585.   }       /* case of item flag */
  586.   break;
  587.  
  588.   default: return MCIERR_FLAGS_NOT_COMPATIBLE;
  589.  
  590.   }        /* All Inclusive */
  591.  
  592.   return (ULONG)(ulrc);
  593.  
  594. }
  595.  
  596.  
  597. /********************* START OF SPECIFICATIONS *********************
  598. *
  599. * SUBROUTINE NAME:              MCDINFO
  600. *
  601. * DESCRIPTIVE NAME: Information about Waveform Device.
  602. *
  603. * FUNCTION: Obtain Info about a  Waveform Device.
  604. *
  605. * NOTES:
  606. *
  607. * ENTRY POINTS:
  608. *     LINKAGE:   CALL FAR
  609. *
  610. * INPUT: MCI_INFO message.
  611. *
  612. * EXIT-NORMAL: Return Code 0.
  613. *
  614. * EXIT_ERROR:  Error Code.
  615. *
  616. * EFFECTS:
  617. *
  618. * INTERNAL REFERENCES:
  619. *
  620. * EXTERNAL REFERENCES:
  621. *
  622. *********************** END OF SPECIFICATIONS **********************/
  623.  
  624. RC MCIInfo (FUNCTION_PARM_BLOCK *pFuncBlock)
  625. {
  626.  
  627.   ULONG            ulrc;               // Propogated MME Error Value
  628.   ULONG            ulParam1;           // Incoming MCI Msg Flags
  629.   ULONG            ulParam2;           // Msg Data
  630.   DWORD            dwInfoFlags;        // Mask for Incoming Flags
  631.   INSTANCE         * ulpInstance;      // Local Instance
  632.   LPMCI_INFO_PARMS lpInfoParms;        // Msg Data Ptr
  633.  
  634.   ulrc = MCIERR_SUCCESS;
  635.   dwInfoFlags = 0;
  636.  
  637.   ulParam1 = pFuncBlock->ulParam1 & NOTIFY_MASK;
  638.   ulParam2 = pFuncBlock->ulParam2;
  639.  
  640.   dwInfoFlags = ulParam1;
  641.  
  642.   /*******************************************
  643.   * Turn off Expected Flags Bits
  644.   ********************************************/
  645.   dwInfoFlags &= ~( MCI_INFO_FILE + MCI_INFO_PRODUCT);
  646.  
  647.   /************************************************/
  648.   // Return Error if any bits are still set
  649.   /************************************************/
  650.   if (dwInfoFlags > 0 )
  651.       return MCIERR_INVALID_FLAG;
  652.  
  653.   /****************************************************
  654.    * Check For Valid Flags but Invalid combination
  655.   *****************************************************/
  656.   if (ulParam1 & MCI_INFO_FILE && ulParam1 & MCI_INFO_PRODUCT)
  657.       return (MCIERR_FLAGS_NOT_COMPATIBLE);
  658.  
  659.   if (!(ulParam1 & MCI_INFO_FILE || ulParam1 & MCI_INFO_PRODUCT))
  660.       return (MCIERR_MISSING_FLAG);
  661.  
  662.   /******************************************************
  663.   * Derefernce Instance pointer from the function block
  664.   ******************************************************/
  665.   ulpInstance = (INSTANCE *)pFuncBlock->ulpInstance;
  666.  
  667.   /*************************************************
  668.   * Check For valid MCI Data Struct pointer
  669.   *************************************************/
  670.   if (ulrc = CheckMem ((PVOID)pFuncBlock->ulParam2,
  671.                        sizeof (MCI_INFO_PARMS),
  672.                        PAG_READ | PAG_WRITE) )
  673.  
  674.       return (MCIERR_MISSING_PARAMETER);
  675.  
  676.   lpInfoParms = (LPMCI_INFO_PARMS)ulParam2;
  677.  
  678.   /***************************************
  679.   * Check for valid Instance
  680.   ***************************************/
  681.   if (ulpInstance == (ULONG)NULL )
  682.       return MCIERR_INSTANCE_INACTIVE;
  683.  
  684.   if (ulpInstance->ulInstanceSignature != ACTIVE)
  685.       return MCIERR_INSTANCE_INACTIVE;
  686.  
  687.  
  688.   if (ulParam1 & MCI_INFO_FILE) {
  689.       if (ulpInstance->usFileExists == UNUSED ||
  690.           ulpInstance->usFileExists == FALSE )
  691.  
  692.           return MCIERR_FILE_NOT_FOUND;
  693.  
  694.       /************************************
  695.       * Ensure the size of the buffer the
  696.       * user passed is valid
  697.       *************************************/
  698.        if (ulrc = CheckMem ((PVOID)lpInfoParms->lpstrReturn,
  699.                             lpInfoParms->dwRetSize,
  700.                             PAG_READ | PAG_WRITE) )
  701.  
  702.          {
  703.          return (MCIERR_INVALID_BUFFER);
  704.          }
  705.  
  706.       if (strlen(ulpInstance->lpstrAudioFile) > lpInfoParms->dwRetSize)
  707.         {
  708.         lpInfoParms->dwRetSize = strlen (ulpInstance->lpstrAudioFile);
  709.         return (MCIERR_INVALID_BUFFER);
  710.         }
  711.       else
  712.         {
  713.         strcpy((PSZ)lpInfoParms->lpstrReturn, ulpInstance->lpstrAudioFile);
  714.         }
  715.  
  716.   }  /* If File Info was Requested */
  717.  
  718.   /**********************************
  719.   * Product Information
  720.   ***********************************/
  721.   if (ulParam1 & MCI_INFO_PRODUCT) {
  722.  
  723.       /*******************************
  724.       * Get Product Information
  725.       * From AudioIF which is the
  726.       * device specific component.
  727.       ********************************/
  728.       ulrc = ulpInstance->pfnVSD (&MIX,
  729.                                   MCI_INFO,
  730.                                   ulParam1,
  731.                                   (ULONG)lpInfoParms,
  732.                                   0L);
  733.   }  /* INFO Product */
  734.  
  735.   return (ulrc);
  736.  }
  737.  
  738.  
  739. /********************* START OF SPECIFICATIONS *******************************
  740. *
  741. * SUBROUTINE NAME:      InitAudioDevice
  742. *
  743. * DESCRIPTIVE NAME:     ""
  744. *
  745. * FUNCTION: Open and Intialize the VSD Device.
  746. *
  747. *
  748. * NOTES:
  749. * ENTRY POINTS:
  750. *     LINKAGE:   CALL FAR
  751. *
  752. * INPUT:
  753. *
  754. * EXIT-NORMAL: Return Code 0.
  755. *
  756. * EXIT_ERROR:  Error Code.
  757. *
  758. * EFFECTS:
  759. *
  760. * INTERNAL REFERENCES: AudioIFDriverEntry().
  761. *
  762. * EXTERNAL REFERENCES:
  763. *
  764. *********************** END OF SPECIFICATIONS *******************************/
  765.  
  766. RC  InitAudioDevice (INSTANCE *ulpInstance, ULONG ulOperation)
  767. {
  768.  
  769.   ULONG   ulrc    = MCIERR_SUCCESS;
  770.   USHORT  usFound = 0;
  771.   USHORT  i;
  772.  
  773.   /***************************
  774.   * Intialize Defaults
  775.   * if unIntialized
  776.   ***************************/
  777.   if (AMPMIX.sMode == NOT_INTIALIZED)
  778.       AMPMIX.sMode = DEFAULT_MODE;
  779.  
  780.   if (AMPMIX.sChannels == NOT_INTIALIZED)
  781.       AMPMIX.sChannels = DEFAULT_CHANNELS;
  782.  
  783.   if (AMPMIX.lSRate == NOT_INTIALIZED)
  784.       AMPMIX.lSRate = DEFAULT_SAMPLERATE;
  785.  
  786.   if (AMPMIX.lBitsPerSRate == 0)
  787.       AMPMIX.lBitsPerSRate = DEFAULT_BITSPERSAMPLE;
  788.  
  789.   if (AMPMIX.ulBlockAlignment == NOT_INTIALIZED)
  790.       AMPMIX.ulBlockAlignment = DEFAULT_BLOCK_ALIGN;
  791.   if ( ulpInstance->ulAverageBytesPerSec == NOT_INTIALIZED )
  792.  
  793.       ulpInstance->ulAverageBytesPerSec = DEFAULT_CHANNELS *
  794.                                           DEFAULT_SAMPLERATE *
  795.                                           ( DEFAULT_BITSPERSAMPLE / 8 );
  796.   /******************************************
  797.   * Do a Table Look up mainly to
  798.   * determine data type and subtype
  799.   * once a match is found, SPCB KEY
  800.   * used for stream creation is set
  801.   * and the Device Dependant flags are
  802.   * built in this routine
  803.   *******************************************/
  804.   if (AMPMIX.sMode != DATATYPE_MIDI)    {
  805.       for (i = 0; i < NUM_DATATYPES; i++) {
  806.            if (DataFormat[i].channels == AMPMIX.sChannels)
  807.                if (DataFormat[i].srate == AMPMIX.lSRate)
  808.                    if (DataFormat[i].ulDataType == (ULONG)AMPMIX.sMode)
  809.                        if (DataFormat[i].bits_per_sample == AMPMIX.lBitsPerSRate){
  810.                            STREAM.SpcbKey.ulDataType = DataFormat[i].ulDataType;
  811.                            STREAM.SpcbKey.ulDataSubType = DataFormat[i].ulDataSubType;
  812.                            AMPMIX.sMode = (SHORT)DataFormat[i].ulDataType;
  813.                            ulpInstance->usModeIndex = i;
  814.                            AMPMIX.ulFlags = FIXED|VOLUME|TREBLE|BASS;
  815.                            usFound = 1;
  816.                            break;
  817.  
  818.                        }  /* BitsPersample Matches */
  819.  
  820.       }  /* For Loop */
  821.  
  822.       if (!usFound)
  823.           return (MCIERR_DEVICE_NOT_READY);
  824.   } /* Data Type != MIDI */
  825.  
  826.   AMPMIX.ulOperation = ulOperation;
  827.  
  828.   /*********************************************
  829.   * Update Device and Driver Names
  830.   *********************************************/
  831.   strcpy ((PSZ)AMPMIX.szDriverName,
  832.           ulpInstance->szDevDLL);
  833.  
  834.   strcpy ((PSZ)AMPMIX.szDeviceName,
  835.           ulpInstance->szAudioDevName);
  836.  
  837.   strcpy (STREAM.AudioDCB.szDevName,
  838.           ulpInstance->szAudioDevName);
  839.  
  840.   /*************************
  841.   * Set Init Flag to true
  842.   *************************/
  843.   ulpInstance->usVSDInit = TRUE;
  844.  
  845.   return (ulrc);
  846.  
  847. }
  848.  
  849.  
  850. /********************* START OF SPECIFICATIONS *******************************
  851. *
  852. * SUBROUTINE NAME:              SetAudioDevice()
  853. *
  854. * DESCRIPTIVE NAME:
  855. *
  856. * FUNCTION: Set AudioDevice Attributes
  857. *
  858. *
  859. * NOTES:   This Request is Routed to the Audio Device Via
  860. *          the AudioIf Interface.
  861. *
  862. * ENTRY POINTS:
  863. *     LINKAGE:   CALL FAR
  864. *
  865. * INPUT:
  866. *
  867. * EXIT-NORMAL: Return Code 0.
  868. *
  869. * EXIT_ERROR:  Error Code.
  870. *
  871. * EFFECTS:
  872. *
  873. * INTERNAL REFERENCES: AudioIFDriverEntry().
  874. *
  875. * EXTERNAL REFERENCES:
  876. *
  877. *********************** END OF SPECIFICATIONS *******************************/
  878.  
  879. RC SetAudioDevice (INSTANCE             *ulpInstance,
  880.                    LPMCI_WAVE_SET_PARMS lpSetParms,
  881.                    ULONG                ulParam1 )
  882.  
  883. {
  884.  
  885.   ULONG ulrc = MCIERR_SUCCESS;
  886.  
  887.   /*********************************
  888.    * Send A Set Across the AudioIF
  889.    * Driver Interface
  890.    ********************************/
  891.  
  892.    ulrc = ulpInstance->pfnVSD (&MIX,
  893.                                MCI_SET,
  894.                                ulParam1,
  895.                                (LONG)lpSetParms,
  896.                                0L);
  897.  
  898.    return (ulrc);
  899.  
  900. }
  901.  
  902.  
  903. /********************* START OF SPECIFICATIONS *********************
  904. *
  905. * SUBROUTINE NAME:              AbortWait
  906. *
  907. * DESCRIPTIVE NAME: Release a Wait Thread
  908. *
  909. * FUNCTION: Release a wait Thread
  910. *
  911. * NOTES:
  912. *
  913. * ENTRY POINTS:
  914. *     LINKAGE:   CALL FAR
  915. *
  916. * INPUT: MCI_INFO message.
  917. *
  918. * EXIT-NORMAL: Return Code 0.
  919. *
  920. * EXIT_ERROR:  Error Code.
  921. *
  922. * EFFECTS:
  923. *
  924. * INTERNAL REFERENCES:
  925. *
  926. * EXTERNAL REFERENCES:
  927. *
  928. *********************** END OF SPECIFICATIONS **********************/
  929. RC AbortWaitOperation (INSTANCE * ulpInstance)
  930.  {
  931.  
  932.   ULONG           ulrc;
  933.   ULONG           lCnt;
  934.  
  935.   ulrc = MCIERR_SUCCESS;
  936.   lCnt = 0;
  937.   /*******************************************************
  938.   * Check to see if the wait pending flag is set.
  939.   * If it is then release the wait block by
  940.   * a SpiStopStream request. The Stop will
  941.   * generate a EVENT_STREAM_STOPPED event, which will
  942.   * post the event semaphore. The posting of the event
  943.   * semaphore will unblock the wait thread which will
  944.   * return to the application.
  945.   ********************************************************/
  946.  
  947.   if (ulpInstance->usWaitPending == TRUE) {
  948.       DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  949.  
  950.       ulrc = SpiStopStream (STREAM.hStream, SPI_STOP_DISCARD);
  951.  
  952.       /*********************************************
  953.       * Wait for the Stopped event . Notice that
  954.       * more than one thread will be released and
  955.       * free to run as a result of the stop event
  956.       *********************************************/
  957.       if (!ulrc)
  958.           DosWaitEventSem (ulpInstance->hEventSem, -1);
  959.   }
  960.   return MCIERR_SUCCESS;
  961.  
  962.  }
  963.  
  964. /********************* START OF SPECIFICATIONS *********************
  965. *
  966. * SUBROUTINE NAME:      GetAudioHeader
  967. *
  968. * DESCRIPTIVE NAME: Get Audio Header From The IO Proc.
  969. *
  970. * FUNCTION: Obtain Wave Header information.
  971. *
  972. * NOTES:
  973. *
  974. * ENTRY POINTS:
  975. *     LINKAGE:   CALL FAR
  976. *
  977. * INPUT: MCI_INFO message.
  978. *
  979. * EXIT-NORMAL: Return Code 0.
  980. *
  981. * EXIT_ERROR:  Error Code.
  982. *
  983. * EFFECTS:
  984. *
  985. * INTERNAL REFERENCES:
  986. *
  987. * EXTERNAL REFERENCES: mmioGetHeader ()   -  MMIO API
  988. *
  989. *********************** END OF SPECIFICATIONS **********************/
  990. RC   GetAudioHeader (INSTANCE * ulpInstance)
  991. {
  992.   ULONG  ulrc;
  993.   LONG   BytesRead;
  994.  
  995.   ulrc = MCIERR_SUCCESS;
  996.  
  997.   if (ulpInstance->hmmio == (ULONG)NULL)
  998.       return MCIERR_FILE_NOT_FOUND;
  999.  
  1000.   /**************************************
  1001.   * Make the Get header Call to the
  1002.   * I/O Proc concerned.
  1003.   ***************************************/
  1004.  
  1005.   ulrc = mmioGetHeader (ulpInstance->hmmio,
  1006.                         (PVOID)&(ulpInstance->mmAudioHeader),
  1007.                         sizeof(ulpInstance->mmAudioHeader),
  1008.                         (PLONG)&BytesRead,
  1009.                         (ULONG)NULL,
  1010.                         (ULONG)NULL);
  1011.  
  1012.   if ( ulrc == MMIO_SUCCESS ) {
  1013.  
  1014.       /******************************************
  1015.           * Intialize AudioIF members
  1016.       ******************************************/
  1017.       AMPMIX.sMode =       WAVEHDR.usFormatTag;
  1018.       AMPMIX.sChannels = WAVEHDR.usChannels;
  1019.       AMPMIX.lSRate =     WAVEHDR.ulSamplesPerSec;
  1020.       AMPMIX.lBitsPerSRate = WAVEHDR.usBitsPerSample;
  1021.       ulpInstance->mmckinfo.ckSize =  XWAVHDR.ulAudioLengthInBytes;
  1022.       AMPMIX.ulBlockAlignment = ( ULONG )WAVEHDR.usBlockAlign;
  1023.       ulpInstance->ulAverageBytesPerSec = WAVEHDR.ulAvgBytesPerSec;
  1024.       if ( ulpInstance->ulAverageBytesPerSec == 0 )
  1025.          {
  1026.  
  1027.          ulpInstance->ulAverageBytesPerSec = WAVEHDR.usChannels * WAVEHDR.ulSamplesPerSec * ( WAVEHDR.usBitsPerSample / 8 );
  1028.          }
  1029.  
  1030.   } /* SuccesFul GetHeader */
  1031.  
  1032.  
  1033.         return (ulrc);
  1034. }
  1035.  
  1036. /********************* START OF SPECIFICATIONS *********************
  1037. *
  1038. * SUBROUTINE NAME:      GetAudioHeader
  1039. *
  1040. * DESCRIPTIVE NAME: Get Audio Header From The IO Proc.
  1041. *
  1042. * FUNCTION: Obtain Wave Header information.
  1043. *
  1044. * NOTES:
  1045. *
  1046. * ENTRY POINTS:
  1047. *     LINKAGE:   CALL FAR
  1048. *
  1049. * INPUT: MCI_INFO message.
  1050. *
  1051. * EXIT-NORMAL: Return Code 0.
  1052. *
  1053. * EXIT_ERROR:  Error Code.
  1054. *
  1055. * EFFECTS:
  1056. *
  1057. * INTERNAL REFERENCES:
  1058. *
  1059. * EXTERNAL REFERENCES: mmioGetHeader ()   -  MMIO API
  1060. *
  1061. *********************** END OF SPECIFICATIONS **********************/
  1062. RC   SetAudioHeader (INSTANCE * ulpInstance)
  1063. {
  1064.   ULONG  ulrc;
  1065.   LONG  lBogus;
  1066.  
  1067.   ulrc = MCIERR_SUCCESS;
  1068.  
  1069.   if (ulpInstance->hmmio == (ULONG)NULL)
  1070.       return MCIERR_FILE_NOT_FOUND;
  1071.  
  1072.   WAVEHDR.usFormatTag = AMPMIX.sMode;
  1073.   WAVEHDR.usChannels = AMPMIX.sChannels;
  1074.   WAVEHDR.ulSamplesPerSec = AMPMIX.lSRate;
  1075.   XWAVHDR.ulAudioLengthInMS = 0;
  1076.   WAVEHDR.usBitsPerSample = (USHORT)AMPMIX.lBitsPerSRate;
  1077.   WAVEHDR.usBlockAlign = (USHORT)AMPMIX.ulBlockAlignment;
  1078.  
  1079.   /********************************************
  1080.   * Send Set Header Info MSg to WAVE IO Proc
  1081.   ********************************************/
  1082.   ulrc = mmioSetHeader( ulpInstance->hmmio,
  1083.                         &ulpInstance->mmAudioHeader,
  1084.                         sizeof( MMAUDIOHEADER ),
  1085.                         &lBogus,
  1086.                         0,
  1087.                         0 );
  1088.  
  1089.   if (ulrc)
  1090.       return (MCIERR_DRIVER_INTERNAL);
  1091.  
  1092.  
  1093.  
  1094.         return (ulrc);
  1095. }
  1096.  
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103. /********************* START OF SPECIFICATIONS *******************************
  1104. *
  1105. * SUBROUTINE NAME: SetWaveDeviceDefaults()
  1106. *
  1107. * DESCRIPTIVE NAME:
  1108. *
  1109. * FUNCTION: Allocate Memory for MCI Message parameter.
  1110. *
  1111. *
  1112. * NOTES:
  1113. * ENTRY POINTS:
  1114. *     LINKAGE:   CALL FAR
  1115. *
  1116. * INPUT:
  1117. *
  1118. * EXIT-NORMAL: Return Code 0.
  1119. *
  1120. * EXIT_ERROR:  Error Code.
  1121. *
  1122. * EFFECTS:
  1123. *
  1124. * INTERNAL REFERENCES: HhpAllocMem().
  1125. *
  1126. * EXTERNAL REFERENCES:
  1127. *
  1128. *********************** END OF SPECIFICATIONS *******************************/
  1129. VOID SetWaveDeviceDefaults (INSTANCE * ulpInstance, ULONG ulOperation)
  1130. {
  1131.  
  1132.   AMPMIX.sMode = DEFAULT_MODE;                  // DATATYPE_WAVEFORM
  1133.   AMPMIX.lSRate =DEFAULT_SAMPLERATE;            // 22 Khz
  1134.   AMPMIX.ulOperation =ulOperation;              // Play or Record
  1135.   AMPMIX.sChannels = DEFAULT_CHANNELS;          // Stereo
  1136.   AMPMIX.lBitsPerSRate = DEFAULT_BITSPERSAMPLE; // 8 bits/sam
  1137.   AMPMIX.ulBlockAlignment = DEFAULT_BLOCK_ALIGN;// 8 bits/sam
  1138.   ulpInstance->ulAverageBytesPerSec = DEFAULT_CHANNELS * ( DEFAULT_BITSPERSAMPLE / 8 ) * DEFAULT_SAMPLERATE;
  1139.  
  1140. }
  1141.  
  1142. /********************* START OF SPECIFICATIONS *******************************
  1143. *
  1144. * SUBROUTINE NAME: VSDInstToWaveSetParms
  1145. *
  1146. * DESCRIPTIVE NAME:
  1147. *
  1148. * FUNCTION: copy parameters from VSD Instance struct to MCI_WAVE_SET_PARMS
  1149. *
  1150. *
  1151. * NOTES:
  1152. * ENTRY POINTS:
  1153. *     LINKAGE:   CALL FAR
  1154. *
  1155. * INPUT:
  1156. *
  1157. * EXIT-NORMAL: Return Code 0.
  1158. *
  1159. * EXIT_ERROR:  Error Code.
  1160. *
  1161. * EFFECTS:
  1162. *
  1163. * INTERNAL REFERENCES: HhpAllocMem().
  1164. *
  1165. * EXTERNAL REFERENCES:
  1166. *
  1167. *********************** END OF SPECIFICATIONS *******************************/
  1168. VOID VSDInstToWaveSetParms (LPMCI_WAVE_SET_PARMS lpWaveSetParms, INSTANCE * ulpInstance)
  1169. {
  1170.  
  1171.   lpWaveSetParms->nChannels =    AMPMIX.sChannels;
  1172.   lpWaveSetParms->wFormatTag =   AMPMIX.sMode;
  1173.   lpWaveSetParms->nSamplesPerSec = AMPMIX.lSRate;
  1174.   lpWaveSetParms->wBitsPerSample = (WORD)AMPMIX.lBitsPerSRate;
  1175. }
  1176. /********************* START OF SPECIFICATIONS *******************************
  1177. *
  1178. * SUBROUTINE NAME:AssocMemPlayToAudioStrm ()
  1179. *
  1180. * DESCRIPTIVE NAME:
  1181. *
  1182. * FUNCTION: Associate The Memory Play List Stream Handler with its Data Object.
  1183. *
  1184. *
  1185. * NOTES:
  1186. * ENTRY POINTS:
  1187. *     LINKAGE:   CALL FAR
  1188. *
  1189. * INPUT:
  1190. *
  1191. * EXIT-NORMAL: Return Code 0.
  1192. *
  1193. * EXIT_ERROR:  Error Code.
  1194. *
  1195. * EFFECTS:
  1196. *
  1197. * INTERNAL REFERENCES:SpiAssociate()
  1198. *
  1199. * EXTERNAL REFERENCES:
  1200. *
  1201. *********************** END OF SPECIFICATIONS *******************************/
  1202. RC AssocMemPlayToAudioStrm (INSTANCE * ulpInstance, ULONG Operation)
  1203. {
  1204.   ULONG ulrc = MCIERR_SUCCESS;
  1205.  
  1206.   /******************************************************
  1207.   * Fill in the Play List ACB with the right info
  1208.   ******************************************************/
  1209.   STREAM.acbPlayList.ulObjType = ACBTYPE_MEM_PLAYL;
  1210.   STREAM.acbPlayList.ulACBLen = sizeof(ACB_MEM_PLAYL);
  1211.   STREAM.acbPlayList.pMemoryAddr= (PVOID)ulpInstance->pPlayList;
  1212.  
  1213.   if (Operation == PLAY_STREAM) {
  1214.       ulrc = SpiAssociate (STREAM.hStream,
  1215.                            STREAM.hidASource,
  1216.                            (PVOID) &(STREAM.acbPlayList));
  1217.   }
  1218.   else
  1219.  
  1220.       if (Operation == RECORD_STREAM) {
  1221.           ulrc = SpiAssociate (STREAM.hStream,
  1222.                                STREAM.hidATarget,
  1223.                                (PVOID)&(STREAM.acbPlayList));
  1224.       }
  1225.  
  1226.   return (ulrc);
  1227.  
  1228. }
  1229.  
  1230. /************************** START OF SPECIFICATIONS *************************/
  1231. /*                                                                          */
  1232. /* SUBROUTINE NAME: MCD_EnterCrit                                           */
  1233. /*                                                                          */
  1234. /* FUNCTION: This routine acquires access to the common areas via a         */
  1235. /*           system semaphore.                                              */
  1236. /*                                                                          */
  1237. /* NOTES:    This routine contains OS/2 system specific functions.          */
  1238. /*           DosRequestMutexSem                                             */
  1239. /*                                                                          */
  1240. /* INPUT:    None.                                                          */
  1241. /*                                                                          */
  1242. /* OUTPUT:   rc = error return code is failure to acquire semaphore.        */
  1243. /*                                                                          */
  1244. /* SIDE EFFECTS: Access acquired.                                           */
  1245. /*                                                                          */
  1246. /*************************** END OF SPECIFICATIONS **************************/
  1247.  
  1248. DWORD MCD_EnterCrit (INSTANCE * ulpInstance )
  1249. {
  1250.   /**************************************************************************/
  1251.   /*                                                                        */
  1252.   /*   Request the system semaphore for the common data area.               */
  1253.   /*                                                                        */
  1254.   /**************************************************************************/
  1255.   return((DWORD)DosRequestMutexSem (ulpInstance->hmtxDataAccess, -1));  // wait for semaphore
  1256. }
  1257.  
  1258.  
  1259.  
  1260.  
  1261.  
  1262. /************************** START OF SPECIFICATIONS *************************/
  1263. /*                                                                          */
  1264. /* SUBROUTINE NAME: MCD_ExitCrit                                           */
  1265. /*                                                                          */
  1266. /* FUNCTION: This routine releases access to the common areas via a         */
  1267. /*           system semaphore.                                              */
  1268. /*                                                                          */
  1269. /* NOTES:    This routine contains OS/2 system specific functions.          */
  1270. /*           DosReleaseMutexSem                                             */
  1271. /*                                                                          */
  1272. /* INPUT:    None.                                                          */
  1273. /*                                                                          */
  1274. /* OUTPUT:   rc = error return code is failure to release semaphore.        */
  1275. /*                                                                          */
  1276. /* SIDE EFFECTS: Access released.                                           */
  1277. /*                                                                          */
  1278. /*************************** END OF SPECIFICATIONS **************************/
  1279.  
  1280. DWORD MCD_ExitCrit (INSTANCE * ulpInstance)
  1281. {
  1282.   /**************************************************************************/
  1283.   /*                                                                        */
  1284.   /*   Release the system semaphore for the common data area.               */
  1285.   /*                                                                        */
  1286.   /**************************************************************************/
  1287.  
  1288.   return((DWORD)DosReleaseMutexSem (ulpInstance->hmtxDataAccess));
  1289.      // release semaphore
  1290. }
  1291.  
  1292.  
  1293. /************************** START OF SPECIFICATIONS *************************/
  1294. /*                                                                          */
  1295. /* SUBROUTINE NAME: AcquireProcSem                                          */
  1296. /*                                                                          */
  1297. /* FUNCTION: This routine acquires access to the common areas via a         */
  1298. /*           system semaphore.                                              */
  1299. /*                                                                          */
  1300. /* NOTES:    This routine contains OS/2 system specific functions.          */
  1301. /*           DosRequestMutexSem                                             */
  1302. /*                                                                          */
  1303. /* INPUT:    None.                                                          */
  1304. /*                                                                          */
  1305. /* OUTPUT:   rc = error return code is failure to acquire semaphore.        */
  1306. /*                                                                          */
  1307. /* SIDE EFFECTS: Access acquired.                                           */
  1308. /*                                                                          */
  1309. /*************************** END OF SPECIFICATIONS **************************/
  1310.  
  1311. DWORD AcquireProcSem ()
  1312. {
  1313.   extern HMTX   hmtxProcSem;
  1314.   /**************************************************************************/
  1315.   /*                                                                        */
  1316.   /*   Request the system semaphore for the common data area.               */
  1317.   /*                                                                        */
  1318.   /**************************************************************************/
  1319.  
  1320.   return((DWORD)DosRequestMutexSem (hmtxProcSem, -1));  // wait for semaphore
  1321. }
  1322.  
  1323. /************************** START OF SPECIFICATIONS *************************/
  1324. /*                                                                          */
  1325. /* SUBROUTINE NAME: ReleaseProcSem                                          */
  1326. /*                                                                          */
  1327. /* FUNCTION: This routine releases access to the common areas via a         */
  1328. /*           system semaphore.                                              */
  1329. /*                                                                          */
  1330. /* NOTES:    This routine contains OS/2 system specific functions.          */
  1331. /*           DosReleaseMutexSem                                             */
  1332. /*                                                                          */
  1333. /* INPUT:    None.                                                          */
  1334. /*                                                                          */
  1335. /* OUTPUT:   rc = error return code is failure to release semaphore.        */
  1336. /*                                                                          */
  1337. /* SIDE EFFECTS: Access released.                                           */
  1338. /*                                                                          */
  1339. /*************************** END OF SPECIFICATIONS **************************/
  1340.  
  1341. DWORD ReleaseProcSem ()
  1342. {
  1343.    extern HMTX  hmtxProcSem;
  1344.   /**************************************************************************/
  1345.   /*                                                                        */
  1346.   /*   Release the system semaphore for the common data area.               */
  1347.   /*                                                                        */
  1348.   /**************************************************************************/
  1349.  
  1350.   return((DWORD)DosReleaseMutexSem (hmtxProcSem));// release semaphore
  1351. }
  1352.  
  1353. /********************* START OF SPECIFICATIONS *******************************
  1354. *
  1355. * SUBROUTINE NAME: CleanUp ()
  1356. *
  1357. * DESCRIPTIVE NAME:
  1358. *
  1359. * FUNCTION: Call HhpFreeMem to dealocatte memory from global heap.
  1360. *
  1361. *
  1362. * NOTES:    Release Memory.
  1363. * ENTRY POINTS:
  1364. *     LINKAGE:   CALL FAR
  1365. *
  1366. * INPUT:
  1367. *
  1368. * EXIT-NORMAL: Return Code 0.
  1369. *
  1370. * EXIT_ERROR:  Error Code.
  1371. *
  1372. * EFFECTS:
  1373. *
  1374. * INTERNAL REFERENCES: HhpFreeMem().
  1375. *
  1376. * EXTERNAL REFERENCES:
  1377. *
  1378. *********************** END OF SPECIFICATIONS *******************************/
  1379.  
  1380. RC CleanUp (PVOID MemToFree)
  1381. {
  1382.   extern HHUGEHEAP heap;
  1383.   /****************************
  1384.   * Enter Data Critical Section
  1385.   *****************************/
  1386.   AcquireProcSem ();
  1387.  
  1388.   /***************************
  1389.   * Free Memory off heap
  1390.   ****************************/
  1391.  
  1392.   HhpFreeMem (heap, MemToFree);
  1393.  
  1394.   /****************************
  1395.   * Exit Data Critical Section
  1396.   *****************************/
  1397.  
  1398.   ReleaseProcSem ();
  1399.  
  1400.   return (ULONG)(MCIERR_SUCCESS);
  1401.  
  1402. }
  1403.  
  1404.  
  1405. /********************* START OF SPECIFICATIONS *******************************
  1406. *
  1407. * SUBROUTINE NAME: ReleaseInstanceMemory ()
  1408. *
  1409. * DESCRIPTIVE NAME:
  1410. *
  1411. * FUNCTION: Call CleanUp to dealocatte Instance memory from global heap.
  1412. *
  1413. *
  1414. * NOTES:    Release Memory.
  1415. * ENTRY POINTS:
  1416. *     LINKAGE:   CALL FAR
  1417. *
  1418. * INPUT:
  1419. *
  1420. * EXIT-NORMAL: Return Code 0.
  1421. *
  1422. * EXIT_ERROR:  Error Code.
  1423. *
  1424. * EFFECTS:
  1425. *
  1426. * INTERNAL REFERENCES: HhpFreeMem().
  1427. *
  1428. * EXTERNAL REFERENCES:
  1429. *
  1430. *********************** END OF SPECIFICATIONS *******************************/
  1431.  
  1432. RC ReleaseInstanceMemory (FUNCTION_PARM_BLOCK * pThreadBlock)
  1433. {
  1434.  
  1435.   /******************************************
  1436.   * Free Thread Parm Block & Assoc Pointers
  1437.   *******************************************/
  1438.   CleanUp ((PVOID) pThreadBlock->pInstance);
  1439.   CleanUp ((PVOID)pThreadBlock);
  1440.  
  1441.   return (ULONG)(MCIERR_SUCCESS);
  1442.  
  1443. }
  1444. /********************* START OF SPECIFICATIONS *******************************
  1445. *
  1446. * SUBROUTINE NAME: InstallIOProc
  1447. *
  1448. * DESCRIPTIVE NAME: ""
  1449. *
  1450. * FUNCTION: Install Customized IO Procs Like AVC IO Proc and WAVE IO Proc.
  1451. *
  1452. * ENTRY POINTS:
  1453. *     LINKAGE:   CALL FAR
  1454. *
  1455. * INPUT:
  1456. *
  1457. * EXIT-NORMAL: Return Code 0.
  1458. *
  1459. * EXIT_ERROR:  Error Code.
  1460. *
  1461. * EFFECTS:
  1462. *
  1463. * INTERNAL REFERENCES: WAVE IO Proc
  1464. *
  1465. * EXTERNAL REFERENCES: DosQueryProcAddr - OS/2 API.
  1466. *
  1467. *********************** END OF SPECIFICATIONS *******************************/
  1468. RC InstallIOProc (ULONG ulIOProc, MMIOINFO * pmmioinfo)
  1469.   {
  1470.  
  1471.  
  1472.   CHAR             Failure[ 100 ];
  1473.   CHAR             ModuleName[124];
  1474.   CHAR             EntryPoint[124];
  1475.   ULONG            rc;
  1476.   HMODULE          hMod;
  1477.   LPMMIOPROC       pIoProc, pAnswer;
  1478.  
  1479.   /**********************************************
  1480.   * Clear structures used off the stack
  1481.   ***********************************************/
  1482.   memset (&ModuleName, '\0', sizeof(ModuleName));
  1483.   memset (&EntryPoint, '\0', sizeof(EntryPoint));
  1484.   memset (&Failure, '\0', sizeof(Failure));
  1485.  
  1486.   if (ulIOProc == WAVE_IO_PROC) {
  1487.  
  1488.       /***************************************************
  1489.       * Fill in FOURCC, ModuleName and EntryPoint Info
  1490.       ****************************************************/
  1491.  
  1492.       pmmioinfo->fccIOProc = mmioFOURCC( 'W', 'A', 'V', 'E' ) ;
  1493.       strcpy( ModuleName, "WAVEPROC" );
  1494.       strcpy( EntryPoint, "WAVEIOProc");
  1495.   }
  1496.   else
  1497.       if (ulIOProc == AVC_IO_PROC) {
  1498.  
  1499.       /***************************************************
  1500.        * Fill in FOURCC, ModuleName and EntryPoint Info
  1501.       ****************************************************/
  1502.            pmmioinfo->fccIOProc = mmioFOURCC( 'A', 'V', 'C', 'A' ) ;
  1503.            strcpy( ModuleName, "AVCAPROC" );
  1504.            strcpy( EntryPoint, "AVCAIOProc");
  1505.        }
  1506.   /******************************************
  1507.   * See if it is a known IO Proc
  1508.   *******************************************/
  1509.   pAnswer = mmioInstallIOProc(pmmioinfo->fccIOProc,
  1510.                               NULL, MMIO_FINDPROC );
  1511.   if (!pAnswer ) {
  1512.       /*************************************
  1513.       * Load The IO Proc
  1514.       *************************************/
  1515.       rc = DosLoadModule( Failure, 100L, ModuleName, &(hMod));
  1516.       if (rc)
  1517.           return (MCIERR_CANNOT_LOAD_DRIVER);
  1518.  
  1519.       /**************************************
  1520.       * Obtain Procedure Entry Point
  1521.       ***************************************/
  1522.       rc = DosQueryProcAddr( hMod, (ULONG)NULL,
  1523.                              EntryPoint, ( PFN *) &pIoProc );
  1524.       if (rc)
  1525.           return(rc);
  1526.       /****************************************
  1527.       * Install the IO Proc
  1528.       *****************************************/
  1529.       pAnswer = mmioInstallIOProc(pmmioinfo->fccIOProc,
  1530.                                   pIoProc, MMIO_INSTALLPROC );
  1531.  
  1532.   }
  1533.  
  1534.  
  1535.  
  1536.    return MCIERR_SUCCESS;
  1537. }
  1538.  
  1539. /********************* START OF SPECIFICATIONS *******************************
  1540. *
  1541. * SUBROUTINE NAME: OpenFile
  1542. *
  1543. * DESCRIPTIVE NAME: OpenFile
  1544. *
  1545. * FUNCTION: Open Element , Install IO Procs, Get Header Information
  1546. *
  1547. *
  1548. * NOTES:
  1549. * ENTRY POINTS:
  1550. *     LINKAGE:   CALL FAR
  1551. *
  1552. * INPUT:
  1553. *
  1554. * EXIT-NORMAL: Return Code 0.
  1555. *
  1556. * EXIT_ERROR:  Error Code.
  1557. *
  1558. * EFFECTS:
  1559. *
  1560. * INTERNAL REFERENCES: None
  1561. *
  1562. * EXTERNAL REFERENCES: None
  1563. *
  1564. *********************** END OF SPECIFICATIONS *******************************/
  1565. RC OpenFile(INSTANCE * pInstance, DWORD dwFlags )
  1566. {
  1567.  
  1568.   MMIOINFO         mmioinfo;             // mmioInfo Structure
  1569.   MMIOINFO         mmioinfoCopy;         // Copy of struct if we need to retry
  1570.   MMFORMATINFO     mmformatinfo;         // Format information
  1571.   FOURCC           fccStorageSystem;     // FCC Storage System
  1572.   PSZ              pFileName;            // Element Name
  1573.   USHORT           useAvcProc;           // Use AVCA IO Proc
  1574.  
  1575.  
  1576.   /********************************
  1577.   * Intialize Data Structs
  1578.   ********************************/
  1579.   ULONG ulrc = MCIERR_SUCCESS;
  1580.   useAvcProc = FALSE;
  1581.   memset( &mmioinfo, '\0', sizeof( MMIOINFO ));
  1582.  
  1583.   /**************************************
  1584.   * By Default install wave IO Proc
  1585.   * If already installed function
  1586.   * just returns success
  1587.   **************************************/
  1588.   ulrc = InstallIOProc(WAVE_IO_PROC,
  1589.                       (MMIOINFO *)&mmioinfo);
  1590.  
  1591.   if (ulrc)
  1592.      return (MCIERR_CANNOT_LOAD_DRIVER);
  1593.  
  1594.   /************************************
  1595.   * Set Header Translation Flag on
  1596.   *************************************/
  1597.   mmioinfo.dwTranslate = MMIO_TRANSLATEHEADER;
  1598.  
  1599.   if ( pInstance->mmioHndlPrvd == TRUE) {
  1600.       pFileName = (ULONG)NULL;
  1601.       mmioinfo.hmmio = pInstance->hmmio;
  1602.   }
  1603.   else
  1604.      {
  1605.      pFileName = pInstance->lpstrAudioFile;
  1606.      pInstance->usFileExists = TRUE;
  1607.      }
  1608.  
  1609.   /*************************************
  1610.   * Do the Open. If mmiohandle is
  1611.   * provided a psuedo open is done
  1612.   * Through the WAVE IO Proc with
  1613.   * NULL File Name
  1614.   *************************************/
  1615.   if (pInstance->mmioHndlPrvd != TRUE) {
  1616.  
  1617.       if ( pInstance->ulCreatedName )
  1618.          {
  1619.          mmioinfo.adwInfo[ 0 ] = pInstance->hTempFile;
  1620.          pFileName = ( PSZ ) NULL;
  1621.          }
  1622.  
  1623.       memmove( &mmioinfoCopy, &mmioinfo, sizeof( MMIOINFO ) );
  1624.  
  1625.       /*********************************************************
  1626.       * Default is to allow saves to be performed without a file
  1627.       * name unless otherwise indicated
  1628.       **********************************************************/
  1629.       pInstance->ulNoSaveWithoutName = FALSE;
  1630.  
  1631.       pInstance->hmmio = mmioOpen ( pFileName,
  1632.                                     &mmioinfo,
  1633.                                     dwFlags );
  1634.  
  1635.       /*********************************************************
  1636.        * Find RIFF Chunk with Form Type WAVE for speed reasons
  1637.       **********************************************************/
  1638.       if ( pInstance->hmmio == (ULONG)NULL ) {
  1639.  
  1640.           if (mmioinfo.dwErrorRet == ERROR_ACCESS_DENIED ||
  1641.               mmioinfo.dwErrorRet == ERROR_SHARING_VIOLATION )
  1642.               {
  1643.               return MCIERR_FILE_ATTRIBUTE;
  1644.  
  1645.               } /* if a file attribute error occurred */
  1646.  
  1647.           if (mmioinfo.dwErrorRet == ERROR_FILE_NOT_FOUND ||
  1648.               mmioinfo.dwErrorRet == ERROR_OPEN_FAILED )
  1649.              {
  1650.              pInstance->ulCanSave   = MCI_TRUE;
  1651.              pInstance->ulCanInsert = MCI_TRUE;
  1652.              pInstance->ulCanRecord = MCI_TRUE;
  1653.  
  1654.              return ERROR_FILE_NOT_FOUND;
  1655.              }        /* Error File Not Found */
  1656.  
  1657.           if (  !pInstance->hmmio )
  1658.              {
  1659.              /*****************************************************
  1660.              * Do autoidentify if main I/O proc can't ID the File
  1661.              ******************************************************/
  1662.  
  1663.              ulrc = InstallIOProc( AVC_IO_PROC,
  1664.                                    (MMIOINFO *) &mmioinfo);
  1665.              useAvcProc = TRUE;
  1666.  
  1667.              if (ulrc)
  1668.                 return (MCIERR_CANNOT_LOAD_DRIVER);
  1669.  
  1670.  
  1671.              ulrc = mmioIdentifyFile( pFileName,
  1672.                                       (ULONG)NULL,
  1673.                                       &mmformatinfo,
  1674.                                       &fccStorageSystem,
  1675.                                       0,
  1676.                                       0 );
  1677.  
  1678.              if ( ulrc == MMIO_SUCCESS )
  1679.  
  1680.                 {
  1681.                 /***********************************************
  1682.                 * if this is a non audio I/O proc, don't open
  1683.                 ************************************************/
  1684.                 if ( mmformatinfo.dwMediaType != MMIO_MEDIATYPE_AUDIO )
  1685.                     {
  1686.                     return MCIERR_INVALID_MEDIA_TYPE;
  1687.                     }
  1688.  
  1689.                 if ( !(mmformatinfo.dwFlags & MMIO_CANSAVETRANSLATED) &&
  1690.                      ( ( dwFlags & MMIO_WRITE ) ||
  1691.                      ( dwFlags & MMIO_READWRITE ) ) )
  1692.                    {
  1693.                    dwFlags &= ~MMIO_WRITE;
  1694.                    dwFlags &= ~MMIO_READWRITE;
  1695.                    dwFlags &= ~MMIO_EXCLUSIVE;
  1696.                    dwFlags |= MMIO_READ | MMIO_DENYNONE;
  1697.                    pInstance->ulOpenTemp = FALSE;
  1698.                    pInstance->dwmmioOpenFlag = dwFlags;
  1699.                    }
  1700.  
  1701.                 memset( &mmioinfo, '\0', sizeof( mmioinfo ) );
  1702.  
  1703.                 // need to find out why a mmioinfo struct cause identify to fail
  1704.  
  1705.                 mmioinfo.dwTranslate = MMIO_TRANSLATEDATA;
  1706.  
  1707.                 if ( pInstance->ulCreatedName )
  1708.                    {
  1709.                    mmioinfo.adwInfo[ 0 ] = pInstance->hTempFile;
  1710.                    pFileName = ( PSZ ) NULL;
  1711.                    }
  1712.  
  1713.                 pInstance->hmmio = mmioOpen ( pFileName,
  1714.                                               &mmioinfo,
  1715.                                               dwFlags);
  1716.  
  1717.  
  1718.                 if (pInstance->hmmio == (ULONG)NULL)
  1719.                   {
  1720.                   if ( mmioinfo.dwErrorRet == ERROR_ACCESS_DENIED ||
  1721.                        mmioinfo.dwErrorRet == ERROR_SHARING_VIOLATION )
  1722.                     {
  1723.                     return MCIERR_FILE_ATTRIBUTE;
  1724.                     }
  1725.  
  1726.                   return  ( mmioinfo.dwErrorRet );
  1727.                   }
  1728.  
  1729.                 pInstance->usFileExists = TRUE;
  1730.  
  1731.                 if (mmformatinfo.dwFlags & MMIO_CANSAVETRANSLATED)
  1732.                    {
  1733.                    pInstance->ulCanSave = MCI_TRUE;
  1734.                    }
  1735.                 else
  1736.                    {
  1737.                    pInstance->ulCanSave = MCI_FALSE;
  1738.                    }
  1739.  
  1740.                 if (mmformatinfo.dwFlags & MMIO_CANINSERTTRANSLATED )
  1741.                    {
  1742.                    pInstance->ulCanInsert = MCI_TRUE;
  1743.                    }
  1744.                 else
  1745.                    {
  1746.                    pInstance->ulCanInsert = MCI_FALSE;
  1747.                    }
  1748.  
  1749.                 if ( mmformatinfo.dwFlags & MMIO_CANWRITETRANSLATED)
  1750.                    {
  1751.                    pInstance->ulCanRecord = MCI_TRUE;
  1752.                    }
  1753.                 else
  1754.                    {
  1755.                    pInstance->ulCanRecord = MCI_FALSE;
  1756.                    }
  1757.                 }
  1758.              else
  1759.                 {
  1760.                 /**********************************
  1761.                 * need an improved error code here
  1762.                 ***********************************/
  1763.                 return ERROR_FILE_NOT_FOUND;
  1764.  
  1765.                 } /* if !success on 2nd open */
  1766.  
  1767.              } /* if !hmmio has not been opened */
  1768.  
  1769.       } /* hmmio == Null */
  1770.  
  1771.    else
  1772.       {
  1773.         pInstance->ulCanSave   = MCI_TRUE;
  1774.         pInstance->ulCanInsert = MCI_TRUE;
  1775.         pInstance->ulCanRecord = MCI_TRUE;
  1776.       }
  1777.   } /* mmio handle Provided not true */
  1778.  
  1779.   /******************************************
  1780.    * Get The Header Information (RIFF + AVC)
  1781.   *******************************************/
  1782.   if (!(dwFlags & MMIO_CREATE))
  1783.      {
  1784.  
  1785.       ulrc = GetAudioHeader (pInstance);
  1786.  
  1787.      } /* Not Create Flag */
  1788.   else
  1789.      {
  1790.      pInstance->mmckinfo.ckSize = 0;
  1791.      }
  1792.  
  1793.   /*******************************************************************
  1794.   * You cannot do the set header immediately after file creation
  1795.   * because future sets on samples, bitpersample, channels may follow
  1796.   ********************************************************************/
  1797.   /*
  1798.   else
  1799.   {
  1800.       ulrc = SetAudioHeader (pInstance);
  1801.   }
  1802.   */
  1803.  
  1804.   return (ULONG)(ulrc);
  1805.   }
  1806.  
  1807.  
  1808.  
  1809.  
  1810. /********************* START OF SPECIFICATIONS *******************************
  1811. *
  1812. * SUBROUTINE NAME: ReportMMPMerrors
  1813. *
  1814. * DESCRIPTIVE NAME: Process Error Conditions for Play and Record
  1815. *
  1816. * FUNCTION: Report Errors, Do PreProcessing for MCI Messages Play
  1817. *           and Record. Preprocessing Includes Pending Notifies and
  1818. *           Element Creation Through WaveIOProc.
  1819. *
  1820. *
  1821. * ENTRY POINTS:
  1822. *     LINKAGE:   CALL FAR
  1823. *
  1824. * INPUT:
  1825. *
  1826. * EXIT-NORMAL: Return Code 0.
  1827. *
  1828. * EXIT_ERROR:  Error Code.
  1829. *
  1830. * EFFECTS:
  1831. *
  1832. * INTERNAL REFERENCES: WaveIOPROC.
  1833. *
  1834. * EXTERNAL REFERENCES: DosQueryProcAddr - OS/2 API.
  1835. *
  1836. *********************** END OF SPECIFICATIONS *******************************/
  1837.  
  1838. RC ReportMMEErrors (USHORT usMessage, FUNCTION_PARM_BLOCK *pFuncBlock)
  1839. {
  1840.  
  1841.   ULONG       ulrc;               // RC
  1842.   ULONG       ulErr;              // Holds error return codes
  1843.   ULONG       lCnt;               // Semaphore Posts
  1844.   ULONG       ulParam1;           // Incoming MCI Flags
  1845.   ULONG       ulAbortNotify = FALSE;
  1846.   USHORT      usAbortType;
  1847.   INSTANCE*   ulpInstance;        // Local Instance
  1848.   DWORD       dwPlayFlags;        // Mask for MCI Play
  1849.   DWORD       dwRecordFlags;      // Mask for MCI Record
  1850.   DWORD       dwMMFileLength = 0; // Length of the File in MMTIME
  1851.   DWORD       dwTemp1 = 0;        // Scratch For z Time Conversion
  1852.   DWORD       dwTemp2 = 0;        // Scratch for Play From
  1853.   DWORD       dwTempTO = 0;       // Scratch for Play Till
  1854.   DWORD       dwFromPosition = 0; // holds where we will play from
  1855.   LPMCI_PLAY_PARMS   lpPlayParms;  // Msg Data Ptr
  1856.   LPMCI_RECORD_PARMS   lpRecordParms;  // Msg Data Ptr
  1857.  
  1858.   /******************************************/
  1859.   // Intialize The local VARS
  1860.   /******************************************/
  1861.   ulrc = MCIERR_SUCCESS;
  1862.   ulParam1 = pFuncBlock->ulParam1;
  1863.   ulpInstance = (INSTANCE *)pFuncBlock->ulpInstance;
  1864.  
  1865.   switch (usMessage)
  1866.   {
  1867.   case MCI_PLAY:
  1868.       {
  1869.       /*********************************/
  1870.       // Check For Illegal Flags
  1871.       /**********************************/
  1872.       dwPlayFlags = pFuncBlock->ulParam1;
  1873.       dwPlayFlags &= ~(MCI_FROM + MCI_TO + MCI_NOTIFY + MCI_WAIT);
  1874.  
  1875.       if (dwPlayFlags > 0)
  1876.           return MCIERR_INVALID_FLAG;
  1877.       /*******************************************/
  1878.       // Checkto see If A Valid Element Specified
  1879.       /*******************************************/
  1880.  
  1881.       if (ulpInstance->usPlayLstStrm == FALSE)
  1882.           if (ulpInstance->usFileExists != TRUE)
  1883.               return MCIERR_FILE_NOT_FOUND;
  1884.  
  1885.       /****************************************/
  1886.        // Do we have a valid Msg Data Struct Ptr
  1887.       /*****************************************/
  1888.       if ((pFuncBlock->ulParam1 & MCI_TO) ||
  1889.           (pFuncBlock->ulParam1 & MCI_FROM) ||
  1890.           (pFuncBlock->ulNotify))
  1891.  
  1892.           ulrc = CheckMem ((PVOID)pFuncBlock->ulParam2,
  1893.                            sizeof (MCI_PLAY_PARMS), PAG_READ);
  1894.  
  1895.  
  1896.           if (ulrc != MCIERR_SUCCESS)
  1897.               return MCIERR_MISSING_PARAMETER;
  1898.  
  1899.       ConvertTimeUnits ( ulpInstance,
  1900.                          &dwMMFileLength,
  1901.                          FILE_LENGTH);
  1902.  
  1903.       dwTemp1 = dwMMFileLength;
  1904.  
  1905.       ConvertToMM( ulpInstance, &dwMMFileLength, dwMMFileLength );
  1906.  
  1907.  
  1908.       /***********************************
  1909.       * Do a Seek to support FROM
  1910.       ***********************************/
  1911.  
  1912.       lpPlayParms= (LPMCI_PLAY_PARMS )pFuncBlock->ulParam2;
  1913.       if (ulParam1 & MCI_FROM)
  1914.          {
  1915.  
  1916.           if (ulpInstance->usPlayLstStrm != TRUE)
  1917.  
  1918.            {
  1919.            if ( lpPlayParms->dwFrom > dwTemp1 && AMPMIX.ulOperation != OPERATION_RECORD )
  1920.               {
  1921.               return MCIERR_OUTOFRANGE;
  1922.               }
  1923.            else
  1924.               {
  1925.                if ( ulpInstance->ulCreateFlag != PREROLL_STATE )
  1926.                   {
  1927.                   if ( lpPlayParms->dwFrom > dwTemp1 )
  1928.                     {
  1929.                     return MCIERR_OUTOFRANGE;
  1930.                     }
  1931.                   return MCIERR_SUCCESS;
  1932.  
  1933.                   } /* if not in preroll state */
  1934.  
  1935.                   ulrc = SpiGetTime( STREAM.hStream,
  1936.                                      ( PMMTIME ) &( STREAM.mmStreamTime ) );
  1937.  
  1938.                   if ( ulrc )
  1939.                     {
  1940.                     return ( ulrc );
  1941.                     }
  1942.  
  1943.                   if ( AMPMIX.ulOperation == OPERATION_RECORD )
  1944.                      {
  1945.  
  1946.                      // if record, then our to point must be less than
  1947.                      // what we have recorded so far
  1948.  
  1949.                      ulrc = ConvertToMM ( ulpInstance,
  1950.                                           (DWORD*) &dwTemp1,
  1951.                                           lpPlayParms->dwFrom );
  1952.  
  1953.                      if ( dwTemp1 > (DWORD ) STREAM.mmStreamTime &&
  1954.                           dwTemp1 > dwMMFileLength )
  1955.                        {
  1956.                        return MCIERR_OUTOFRANGE;
  1957.                        }
  1958.                      }
  1959.                   else
  1960.                     {
  1961.                     // ensure that if the to flag is specified, it will realize that
  1962.                     // the play will start from the from position
  1963.  
  1964.                      ulrc = ConvertToMM ( ulpInstance,
  1965.                                           (DWORD*) &dwFromPosition,
  1966.                                           lpPlayParms->dwFrom );
  1967.                     }
  1968.  
  1969.  
  1970.               }
  1971.            } /* Non PlayList */
  1972.          } /* Play From */
  1973.  
  1974.       /************************************************************
  1975.       * Enable a Single Non Recurring TIme Event to Support MCI_TO
  1976.       ************************************************************/
  1977.  
  1978.       if (ulParam1 & MCI_TO)
  1979.          {
  1980.          if (ulpInstance->usPlayLstStrm != TRUE)
  1981.             {
  1982.             /******************************
  1983.             * Range Checking on TO
  1984.             *******************************/
  1985.  
  1986.             if ( lpPlayParms->dwTo > dwTemp1 && AMPMIX.ulOperation != OPERATION_RECORD )
  1987.                {
  1988.                return MCIERR_OUTOFRANGE;
  1989.                }
  1990.             else
  1991.                {
  1992.                if ( ulParam1 & MCI_FROM )
  1993.                   {
  1994.                   if ( lpPlayParms->dwTo <= lpPlayParms->dwFrom )
  1995.                      {
  1996.                      return MCIERR_OUTOFRANGE;
  1997.                      }
  1998.                   }
  1999.  
  2000.                if ( ulpInstance->ulCreateFlag != PREROLL_STATE )
  2001.                   {
  2002.                   if ( lpPlayParms->dwTo == 0 )
  2003.                     {
  2004.                     return MCIERR_OUTOFRANGE;
  2005.                     }
  2006.                   return MCIERR_SUCCESS;
  2007.                   }
  2008.  
  2009.                ulrc = SpiGetTime( STREAM.hStream,
  2010.                                   ( PMMTIME ) &( STREAM.mmStreamTime ) );
  2011.  
  2012.                if ( ulrc )
  2013.                   {
  2014.                   return ( ulrc );
  2015.                   }
  2016.  
  2017.                // if the to flag was not passed in, then set the from position
  2018.                // to be equivalent to our current position
  2019.  
  2020.                if ( dwFromPosition == 0 &&
  2021.                     !(ulParam1 & MCI_FROM ) )
  2022.                   {
  2023.                   dwFromPosition = ( DWORD ) STREAM.mmStreamTime;
  2024.                   }
  2025.  
  2026.                if ( AMPMIX.ulOperation == OPERATION_RECORD )
  2027.                   {
  2028.  
  2029.                   // if record, then our to point must be less than
  2030.                   // what we have recorded so far
  2031.  
  2032.                   ulrc = ConvertToMM ( ulpInstance,
  2033.                                        (DWORD*) &dwTempTO,
  2034.                                        lpPlayParms->dwTo);
  2035.  
  2036.  
  2037.                   // if we are past what we have recorded so far and past the
  2038.                   // length of the file in case of recording in the middle
  2039.                   // return an error
  2040.  
  2041.                   if ( dwTempTO > (DWORD ) STREAM.mmStreamTime &&
  2042.                        dwTempTO > dwMMFileLength )
  2043.                     {
  2044.                     return MCIERR_OUTOFRANGE;
  2045.                     }
  2046.                   }
  2047.                else
  2048.                   {
  2049.                   ulrc = ConvertToMM ( ulpInstance,
  2050.                                        (DWORD*) &dwTempTO,
  2051.                                        lpPlayParms->dwTo);
  2052.  
  2053.                   if ( dwTempTO <= ( DWORD ) STREAM.mmStreamTime &&
  2054.                        dwTempTO <= dwFromPosition )
  2055.                     {
  2056.                     /********************************************************
  2057.                     * it is possible that we had rounding problems so ensure
  2058.                     * that user did indeed pass in an illegal value
  2059.                     ********************************************************/
  2060.                     if ( ( ulParam1 & MCI_FROM ) &&
  2061.                          !(lpPlayParms->dwTo <= lpPlayParms->dwFrom ) )
  2062.                        {
  2063.                        break;
  2064.                        }
  2065.  
  2066.                     return MCIERR_OUTOFRANGE;
  2067.                     }
  2068.                   }
  2069.                }
  2070.  
  2071.             }
  2072.  
  2073.          } // Of Play Till XXXX
  2074.        } /* Case of MCI Play */
  2075.       break;
  2076.  
  2077.   case MCI_RECORD:
  2078.        {
  2079.  
  2080.        dwRecordFlags = pFuncBlock->ulParam1;
  2081.        /****************************************
  2082.        * Check for Invalid Flags
  2083.        ****************************************/
  2084.        dwRecordFlags &= ~(MCI_FROM + MCI_TO + MCI_RECORD_INSERT +
  2085.                           MCI_RECORD_OVERWRITE + MCI_WAIT + MCI_NOTIFY);
  2086.  
  2087.        if (dwRecordFlags > 0)
  2088.            return MCIERR_INVALID_FLAG;
  2089.  
  2090.        if (ulpInstance == (ULONG)NULL )
  2091.            return MCIERR_INSTANCE_INACTIVE;
  2092.  
  2093.  
  2094.        /************************************************/
  2095.        // Check For Unsupported Flags
  2096.        /************************************************/
  2097.  
  2098.        if( (pFuncBlock->ulParam1 & MCI_RECORD_INSERT) &&
  2099.             (pFuncBlock->ulParam1 & MCI_RECORD_OVERWRITE))
  2100.  
  2101.              return MCIERR_FLAGS_NOT_COMPATIBLE;
  2102.  
  2103.        /************************************************/
  2104.        // Check For Unsupported Flags
  2105.        /************************************************/
  2106.        if (!(pFuncBlock->ulParam1 & MCI_RECORD_INSERT))
  2107.            pFuncBlock->ulParam1 |= MCI_RECORD_OVERWRITE;
  2108.  
  2109.        /***********************************************/
  2110.                   // Check For Valid Element
  2111.        /***********************************************/
  2112.        if (ulpInstance->usFileExists == UNUSED)
  2113.            return MCIERR_FILE_NOT_FOUND;
  2114.  
  2115.        ulrc = CheckMem ( (PVOID)pFuncBlock->ulParam2,
  2116.                          sizeof (MCI_RECORD_PARMS), PAG_READ);
  2117.  
  2118.  
  2119.        if (ulrc != MCIERR_SUCCESS)
  2120.           {
  2121.           return MCIERR_MISSING_PARAMETER;
  2122.           }
  2123.  
  2124.        if ( !ulpInstance->ulUsingTemp && !ulpInstance->usPlayLstStrm )
  2125.           {
  2126.           return MCIERR_UNSUPPORTED_FUNCTION;
  2127.           }
  2128.  
  2129.        lpRecordParms= (LPMCI_RECORD_PARMS )pFuncBlock->ulParam2;
  2130.  
  2131.       ConvertTimeUnits ( ulpInstance,
  2132.                          &dwMMFileLength,
  2133.                          FILE_LENGTH);
  2134.  
  2135.       dwTemp1 = dwMMFileLength;
  2136.  
  2137.       ConvertToMM( ulpInstance, &dwMMFileLength, dwMMFileLength );
  2138.  
  2139.  
  2140. // if future, with playlist we should check to see if the stream is active
  2141. // if it isn't then do a seek to end to determine the length
  2142.  
  2143.        if (ulParam1 & MCI_FROM)
  2144.           {
  2145.           // we cannot perform length checks on play list streams
  2146.  
  2147.           if ( lpRecordParms->dwFrom > dwTemp1 && ulpInstance->usPlayLstStrm != TRUE )
  2148.             {
  2149.             return MCIERR_OUTOFRANGE;
  2150.             }
  2151.  
  2152.           // the play will start from the from position
  2153.  
  2154.           ulrc = ConvertToMM ( ulpInstance,
  2155.                                (DWORD*) &dwFromPosition,
  2156.                                lpRecordParms->dwFrom );
  2157.  
  2158.           }  /* Record From */
  2159.  
  2160.        if (ulParam1 & MCI_TO)
  2161.           {
  2162.  
  2163.           if ( lpRecordParms->dwTo <= 0 )
  2164.             {
  2165.             return MCIERR_OUTOFRANGE;
  2166.             }
  2167.  
  2168.           if ( ulParam1 & MCI_FROM )
  2169.             {
  2170.             // if the user wants to record behind the request return an error
  2171.  
  2172.             if ( lpRecordParms->dwTo <= lpRecordParms->dwFrom )
  2173.                {
  2174.                return MCIERR_OUTOFRANGE;
  2175.                }
  2176.  
  2177.             } /* if the from flag specified */
  2178.  
  2179.           if ( ulpInstance->ulCreateFlag == PREROLL_STATE )
  2180.              {
  2181.              ulrc = SpiGetTime( STREAM.hStream,
  2182.                                 ( PMMTIME ) &( STREAM.mmStreamTime ) );
  2183.  
  2184.              if ( ulrc )
  2185.                 {
  2186.                 return ( ulrc );
  2187.                 }
  2188.  
  2189.              ConvertToMM ( ulpInstance,
  2190.                            (DWORD*) &dwTempTO,
  2191.                            lpRecordParms->dwTo );
  2192.  
  2193.  
  2194.              // if the to flag was not passed in, then set the from position
  2195.              // to be equivalent to our current position
  2196.  
  2197.              if ( dwFromPosition == 0 &&
  2198.                   !(ulParam1 & MCI_FROM ) )
  2199.                 {
  2200.                 dwFromPosition = ( DWORD ) STREAM.mmStreamTime;
  2201.                 }
  2202.  
  2203.              if ( dwTempTO <= STREAM.mmStreamTime &&
  2204.                   dwTempTO <= dwFromPosition         )
  2205.                 {
  2206.                 /********************************************************
  2207.                 * it is possible that we had rounding problems so ensure
  2208.                 * that user did indeed pass in an illegal value
  2209.                 ********************************************************/
  2210.                 if ( ( ulParam1 & MCI_FROM ) &&
  2211.                      !(lpRecordParms->dwTo <= lpRecordParms->dwFrom ) )
  2212.                    {
  2213.                    break;
  2214.                    }
  2215.  
  2216.                 return MCIERR_OUTOFRANGE;
  2217.                 }
  2218.  
  2219.              } /* if stream has been created */
  2220.  
  2221.  
  2222.           }
  2223.  
  2224.  
  2225.        /***********************************************
  2226.        * The Previous Notifies belong here because
  2227.        * File open is done here.
  2228.        ************************************************/
  2229.        DosRequestMutexSem( ulpInstance->hmtxNotifyAccess, -1 );
  2230.  
  2231.        if (ulpInstance->usNotifyPending == TRUE)
  2232.           {
  2233.           ulpInstance->ulNotifyAborted = TRUE;
  2234.           ulpInstance->usNotifyPending = FALSE;
  2235.           ulAbortNotify = TRUE;
  2236.           }
  2237.  
  2238.        DosReleaseMutexSem( ulpInstance->hmtxNotifyAccess);
  2239.  
  2240.        if ( ulAbortNotify == TRUE) {
  2241.            if (ulpInstance->usNotPendingMsg == MCI_RECORD) {
  2242.  
  2243.            if ( ulParam1 & MCI_NOTIFY )
  2244.               {
  2245.               usAbortType = MCI_NOTIFY_SUPERSEDED;
  2246.               }
  2247.            else
  2248.               {
  2249.               usAbortType = MCI_NOTIFY_ABORTED;
  2250.               }
  2251.            PostMDMMessage ( usAbortType,
  2252.                             MCI_RECORD, pFuncBlock);
  2253.  
  2254.            /*******************************************/
  2255.            // Reset UserParm for Current Record
  2256.            /*******************************************/
  2257.            if (ulParam1 & MCI_NOTIFY)
  2258.                ulpInstance->usUserParm = pFuncBlock->usUserParm;
  2259.  
  2260.            /****************************************
  2261.            * Reset Internal Semaphores
  2262.            ****************************************/
  2263.            DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  2264.            DosResetEventSem (ulpInstance->hThreadSem, &lCnt);
  2265.  
  2266.            /***************************
  2267.            * Stop The Stream
  2268.            ***************************/
  2269.            ulrc = SpiStopStream (STREAM.hStream,
  2270.                                  SPI_STOP_DISCARD);
  2271.            if (!ulrc)
  2272.               {
  2273.               /*****************************************
  2274.               * Wait for Previous Thread to Die
  2275.               *****************************************/
  2276.  
  2277.               DosWaitEventSem (ulpInstance->hThreadSem, (ULONG) -1);
  2278.               }
  2279.               if ( !ulpInstance->ulOldStreamPos )
  2280.                  {
  2281.                  ulrc = SpiGetTime( STREAM.hStream,
  2282.                                     ( PMMTIME ) &ulpInstance->ulOldStreamPos );
  2283.  
  2284.                  // if an error occurred, then don't remember our position in the stream
  2285.  
  2286.                  if ( ulrc )
  2287.                    {
  2288.                    ulpInstance->ulOldStreamPos = 0;
  2289.                    }
  2290.                  }
  2291.  
  2292.               STRMSTATE = MCI_STOP;
  2293.  
  2294.               ulrc = MCIERR_SUCCESS;
  2295.  
  2296.               /***********************************
  2297.               * Update Internal States
  2298.               ************************************/
  2299.               ulpInstance->ulCreateFlag = PREROLL_STATE;
  2300.  
  2301.            } /* Superseded */
  2302.           else if ( ulpInstance->usNotPendingMsg == MCI_SAVE )
  2303.              {
  2304.              // Save is a non-interruptible operation
  2305.              // wait for completion
  2306.  
  2307.              DosWaitEventSem( ulpInstance->hThreadSem, ( ULONG ) -1 );
  2308.              }
  2309.            else
  2310.               {
  2311.               PostMDMMessage (MCI_NOTIFY_ABORTED, MCI_PLAY, pFuncBlock);
  2312.               DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  2313.               DosResetEventSem (ulpInstance->hThreadSem, &lCnt);
  2314.  
  2315.               if (ulParam1 & MCI_NOTIFY)
  2316.                   ulpInstance->usUserParm = pFuncBlock->usUserParm;
  2317.               /********************************
  2318.               * Stop The Stream
  2319.               ********************************/
  2320.               ulrc = SpiStopStream (STREAM.hStream,
  2321.                                     SPI_STOP_DISCARD);
  2322.               if (!ulrc)
  2323.                   {
  2324.                   /*****************************************/
  2325.                   // Wait for Previous Thread to Die
  2326.                   /*****************************************/
  2327.                   DosWaitEventSem (ulpInstance->hThreadSem, (ULONG) -1);
  2328.  
  2329.                   if ( !ulpInstance->ulOldStreamPos )
  2330.                     {
  2331.                     ulrc = SpiGetTime( STREAM.hStream,
  2332.                                        ( PMMTIME ) &ulpInstance->ulOldStreamPos );
  2333.  
  2334.                     // if an error occurred, then don't remember our position in the stream
  2335.  
  2336.                     if ( ulrc )
  2337.                       {
  2338.                       ulpInstance->ulOldStreamPos = 0;
  2339.                       }
  2340.                     }
  2341.  
  2342.                   DestroyStream (STREAM.hStream);
  2343.                   ulpInstance->ulCreateFlag = PLAY_STREAM;
  2344.                   }  /* no RC */
  2345.            }  /* Case of Record aborting a Play */
  2346.        }      /* Notify Pending   */
  2347.  
  2348.        /*******************************************/
  2349.        // Element was Open with Read Flag on
  2350.        // at open time.
  2351.        /*******************************************/
  2352.        if (ulpInstance->usPlayLstStrm != TRUE) {
  2353.            if (STREAM.ulState != CUERECD_STATE) {
  2354.                if ( !( ulpInstance->dwmmioOpenFlag & MMIO_WRITE ) &&
  2355.                     !( ulpInstance->dwmmioOpenFlag & MMIO_READWRITE )  &&
  2356.                     !( ulpInstance->mmioHndlPrvd ) ) {
  2357.  
  2358.                       /*******************************************/
  2359.                       // Destroy if a PlayBack Stream was created
  2360.                        /*******************************************/
  2361.                        if (ulpInstance->ulCreateFlag == PREROLL_STATE)
  2362.                            {
  2363.                            if ( !ulpInstance->ulOldStreamPos )
  2364.                              {
  2365.                              ulrc = SpiGetTime( STREAM.hStream,
  2366.                                                 ( PMMTIME ) &ulpInstance->ulOldStreamPos );
  2367.  
  2368.                              // if an error occurred, then don't remember our position in the stream
  2369.  
  2370.                              if ( ulrc )
  2371.                                 {
  2372.                                 ulpInstance->ulOldStreamPos = 0;
  2373.                                 }
  2374.                              }
  2375.  
  2376.                            DestroyStream (STREAM.hStream);
  2377.                            ulpInstance->ulCreateFlag = CREATE_STATE;
  2378.                            }
  2379.  
  2380.                        if (ulpInstance->hmmio != (ULONG)NULL)
  2381.                            ulrc = mmioClose (ulpInstance->hmmio, 0);
  2382.  
  2383.                        ulpInstance->dwmmioOpenFlag &= ~MMIO_READ;
  2384.                        ulpInstance->hmmio = (ULONG)NULL;
  2385.                } /* MMIO_READ Flag on */
  2386.            } /* Cue Record State */
  2387.        } /* Non PlayList */
  2388.  
  2389.  
  2390.        if (ulpInstance->usPlayLstStrm != TRUE) {
  2391.  
  2392.            /**********************************************/
  2393.            // Open The element if not already Open
  2394.            // This always open the element with create
  2395.            // flag on once, at start of record.
  2396.            /**********************************************/
  2397.            if (ulpInstance->hmmio == (ULONG)NULL) {
  2398.  
  2399.                /********************************/
  2400.                   // Update mmioOpen Flags
  2401.                /*******************************/
  2402.                if (ulpInstance->usFileExists == FALSE)
  2403.                    {
  2404.                    ulpInstance->dwmmioOpenFlag = MMIO_CREATE;
  2405.                    }
  2406.  
  2407.                 ulpInstance->dwmmioOpenFlag |= MMIO_READWRITE|MMIO_EXCLUSIVE;
  2408.                 ulpInstance->dwmmioOpenFlag &= ~MMIO_DENYNONE;
  2409.  
  2410.                 /********************************
  2411.                 * Open The Element
  2412.                 *******************************/
  2413.  
  2414.                    ulErr = OpenFile (ulpInstance, ulpInstance->dwmmioOpenFlag);
  2415.  
  2416.                    if ( ulErr )
  2417.                       {
  2418.                       ulpInstance->dwmmioOpenFlag = MMIO_READ | MMIO_DENYNONE;
  2419.  
  2420.                       ulrc = OpenFile ( ulpInstance, ulpInstance->dwmmioOpenFlag );
  2421.                       if ( ulrc )
  2422.                          {
  2423.                          ulpInstance->usFileExists = FALSE;
  2424.                          }
  2425.  
  2426.                       return ( ulErr );
  2427.  
  2428.                       }
  2429.  
  2430.            } /* hmmio != NULL */
  2431.  
  2432.            if (pFuncBlock->ulParam1 & MCI_RECORD_INSERT)
  2433.                {
  2434.                ulpInstance->usRecdInsert = TRUE;
  2435.  
  2436.                }   /* Insert Specified */
  2437.  
  2438.        } /* Non PlayList Case */
  2439.        } /* Case of MCI_RECORD */
  2440.       break;
  2441.   } /* of Switch */
  2442.  
  2443.   return (MCIERR_SUCCESS);
  2444. }
  2445. /********************* START OF SPECIFICATIONS *******************************
  2446. *
  2447. * SUBROUTINE NAME: ConvertToMM ()
  2448. *
  2449. * DESCRIPTIVE NAME:
  2450. *
  2451. * FUNCTION: Convert Time values from MMTIME units to current base.
  2452. *
  2453. *
  2454. * NOTES:    Release Memory.
  2455. * ENTRY POINTS:
  2456. *     LINKAGE:   CALL FAR
  2457. *
  2458. * INPUT:
  2459. *
  2460. * EXIT-NORMAL: Return Code 0.
  2461. *
  2462. * EXIT_ERROR:  Error Code.
  2463. *
  2464. * EFFECTS:
  2465. *
  2466. * INTERNAL REFERENCES:
  2467. *
  2468. * EXTERNAL REFERENCES:
  2469. *
  2470. *********************** END OF SPECIFICATIONS *******************************/
  2471.  
  2472. RC   ConvertToMM (INSTANCE * ulpInstance, DWORD *dwSeekPoint, DWORD value)
  2473. {
  2474.  
  2475.   ULONG      ulBytesPerSample = 0;
  2476.   ULONG      ulTemp1;
  2477.  
  2478.  
  2479.   /***************************
  2480.   * Intialize The Stack Vars
  2481.   ****************************/
  2482.   ulTemp1 = 0;
  2483.  
  2484.   switch (ulpInstance->ulTimeUnits)
  2485.   {
  2486.  
  2487.   case lMMTIME:
  2488.        *dwSeekPoint = value;
  2489.       break;
  2490.  
  2491.   case lMILLISECONDS:
  2492.        *dwSeekPoint = MSECTOMM (value);
  2493.       break;
  2494.  
  2495.   case lSAMPLES:
  2496.        ulBytesPerSample = (AMPMIX.lBitsPerSRate / 8);
  2497.        ulTemp1 = value * ulBytesPerSample;
  2498.  
  2499.        ulTemp1 /= DATATYPE.ulBytes ;
  2500.        *dwSeekPoint = ulTemp1 * DATATYPE.ulMMTime;
  2501.  
  2502.       break;
  2503.  
  2504.   case lBYTES:
  2505.        ulTemp1 = value / DATATYPE.ulBytes ;
  2506.        *dwSeekPoint = ulTemp1 * DATATYPE.ulMMTime;
  2507.  
  2508.       break;
  2509.   }
  2510.  
  2511.   return MCIERR_SUCCESS;
  2512.  
  2513. }
  2514.  
  2515. /********************* START OF SPECIFICATIONS *******************************
  2516. *
  2517. * SUBROUTINE NAME: ConvertTimeUnits ()
  2518. *
  2519. * DESCRIPTIVE NAME:
  2520. *
  2521. * FUNCTION: Convert Time values from the current base to MMTIME units.
  2522. *
  2523. *
  2524. * NOTES:    Release Memory.
  2525. * ENTRY POINTS:
  2526. *     LINKAGE:   CALL FAR
  2527. *
  2528. * INPUT:
  2529. *
  2530. * EXIT-NORMAL: Return Code 0.
  2531. *
  2532. * EXIT_ERROR:  Error Code.
  2533. *
  2534. * EFFECTS:
  2535. *
  2536. * INTERNAL REFERENCES:
  2537. *
  2538. * EXTERNAL REFERENCES:
  2539. *
  2540. *********************** END OF SPECIFICATIONS *******************************/
  2541.  
  2542. RC  ConvertTimeUnits (INSTANCE * ulpInstance, DWORD *dwSeekPoint, DWORD value)
  2543. {
  2544.   ULONG      ulBytesPerSample;
  2545.   ULONG      ulTemp1 = 0;
  2546.  
  2547.  
  2548.   // due to inaccuracies in the conversions, if the request is bytes or samples
  2549.   // simply return the number
  2550.  
  2551.   /**************************************
  2552.   * Computation of Media Element Length
  2553.   * This routine is called with FILE LENGTH
  2554.   * value to signify Total length is
  2555.   * requested.
  2556.   ***************************************/
  2557.   if (value == FILE_LENGTH) {
  2558.  
  2559.       /* due to inaccuracies in the conversions, if the request is bytes or samples
  2560.       *  simply return the number itself
  2561.       */
  2562.       if ( ulpInstance->ulTimeUnits == lBYTES )
  2563.          {
  2564.          *dwSeekPoint = ulpInstance->mmckinfo.ckSize;
  2565.          return MCIERR_SUCCESS;
  2566.          }
  2567.       else if ( ulpInstance->ulTimeUnits == lSAMPLES )
  2568.          {
  2569.          ulBytesPerSample = (AMPMIX.lBitsPerSRate / 8);
  2570.          *dwSeekPoint = ulpInstance->mmckinfo.ckSize / ulBytesPerSample;
  2571.          return MCIERR_SUCCESS;
  2572.          }
  2573.  
  2574.       /***********************************************
  2575.       * Get the number of blocks of audio information the
  2576.       * desired number of bytes consumes.
  2577.       *************************************************/
  2578.       ulTemp1 = ulpInstance->mmckinfo.ckSize / DATATYPE.ulBytes;
  2579.  
  2580.  
  2581.  
  2582.       /***********************************************
  2583.       * Multiply the blocks above by the length in time
  2584.       * of a block.
  2585.       *************************************************/
  2586.  
  2587.       value = ulTemp1 * DATATYPE.ulMMTime;
  2588.   }
  2589.  
  2590.  
  2591.   /****************************
  2592.   * Intialize The Stack Vars
  2593.   *****************************/
  2594.  
  2595.   switch (ulpInstance->ulTimeUnits)
  2596.   {
  2597.   case lMMTIME:
  2598.        *dwSeekPoint = value;
  2599.       break;
  2600.  
  2601.   case lMILLISECONDS:
  2602.        *dwSeekPoint = MSECFROMMM (value);
  2603.       break;
  2604.  
  2605.   case lSAMPLES:
  2606.        ulBytesPerSample = (AMPMIX.lBitsPerSRate / 8);
  2607.  
  2608.        ulTemp1 = value / DATATYPE.ulMMTime ;
  2609.        ulTemp1 *= DATATYPE.ulBytes;
  2610.        *dwSeekPoint = ulTemp1 / ulBytesPerSample;
  2611.       break;
  2612.  
  2613.   case lBYTES:
  2614.        ulTemp1 = value / DATATYPE.ulMMTime ;
  2615.        *dwSeekPoint = ulTemp1 * DATATYPE.ulBytes;
  2616.       break;
  2617.  
  2618.   } /* Of Switch */
  2619.  
  2620.   return MCIERR_SUCCESS;
  2621.  
  2622. }
  2623.  
  2624. /********************* START OF SPECIFICATIONS *******************************
  2625. *
  2626. * SUBROUTINE NAME: CreateNAssocStream ()
  2627. *
  2628. * DESCRIPTIVE NAME:
  2629. *
  2630. * FUNCTION: Create a stream and associate this stream with its data
  2631. *           object.
  2632. *
  2633. *
  2634. * NOTES:
  2635. * ENTRY POINTS:
  2636. *     LINKAGE:   CALL FAR
  2637. *
  2638. * INPUT:
  2639. *
  2640. * EXIT-NORMAL: Return Code 0.
  2641. *
  2642. * EXIT_ERROR:  Error Code.
  2643. *
  2644. * EFFECTS:
  2645. *
  2646. * INTERNAL REFERENCES:
  2647. *
  2648. * EXTERNAL REFERENCES:  SpiCreateStream ()      - SSM SPI
  2649. *                       SpiAssociate ()         - SSM SPI
  2650. *
  2651. *********************** END OF SPECIFICATIONS *******************************/
  2652.  
  2653. RC     CreateNAssocStream (HID hidSrc,           /* Source Handler HID */
  2654.                           HID hidTgt,            /* Target Handler HID */
  2655.                           HSTREAM *hStream,      /* Stream Handle ()   */
  2656.                           INSTANCE * pInstance,  /* Instance Pointer   */
  2657.                           ULONG  Operation,      /* Play or Record     */
  2658.                           PEVFN  EventProc)      /* Event Entry Point  */
  2659. {
  2660.  
  2661.   ULONG     ulrc;
  2662.   ulrc = MCIERR_SUCCESS;
  2663.   /*************************************************/
  2664.   // SpiCreateStream()
  2665.   /*************************************************/
  2666.   ulrc = SpiCreateStream (hidSrc, hidTgt,
  2667.                          (PSPCBKEY)&(pInstance->StreamInfo.SpcbKey),
  2668.                          (PDCB)&(pInstance->StreamInfo.AudioDCB),
  2669.                          (PDCB)&(pInstance->StreamInfo.AudioDCB),
  2670.                          (PIMPL_EVCB)&(pInstance->StreamInfo.Evcb),
  2671.                          (PEVFN)EventProc, (ULONG)NULL,(hStream),
  2672.                          &(pInstance->StreamInfo.hEvent));
  2673.  
  2674.   if (ulrc)
  2675.       return ulrc;
  2676.  
  2677.   /********************
  2678.   * SpiAssociate()
  2679.   *********************/
  2680.   pInstance->StreamInfo.acbmmio.ulObjType = ACBTYPE_MMIO;
  2681.   pInstance->StreamInfo.acbmmio.ulACBLen = sizeof (ACB_MMIO);
  2682.   pInstance->StreamInfo.acbmmio.hmmio = pInstance->hmmio;
  2683.  
  2684.   if (Operation == PLAY_STREAM) {
  2685.  
  2686.       if (ulrc = SpiAssociate ((HSTREAM)*hStream, hidSrc,
  2687.                                (PVOID) &(pInstance->StreamInfo.acbmmio)))
  2688.           return ulrc;
  2689.   }
  2690.   else
  2691.   if (Operation == RECORD_STREAM) {
  2692.       ulrc = SpiAssociate ((HSTREAM)*hStream, hidTgt,
  2693.                            (PVOID)&(pInstance->StreamInfo.acbmmio));
  2694.   }
  2695.   return ulrc;
  2696. }
  2697.  
  2698. /********************* START OF SPECIFICATIONS *******************************
  2699. *
  2700. * SUBROUTINE NAME: DoTillEvent()
  2701. *
  2702. * DESCRIPTIVE NAME:
  2703. *
  2704. * FUNCTION: Enable a Time Event to process MCI_PLAY or MCI_RECORD with
  2705. *           the MCI_TO Flag on.
  2706. *
  2707. * NOTES:   When This Time Event is received The EventProc Signalls
  2708. *          the Blocked Thread by Posting a Semaphore. The Blocked
  2709. *          Thread awakens and stops the stream thereby stopping
  2710. *          MCI_PLAY or MCI_RECORD.
  2711. *
  2712. * ENTRY POINTS:
  2713. *     LINKAGE:   CALL FAR
  2714. *
  2715. * INPUT:
  2716. *
  2717. * EXIT-NORMAL: Return Code 0.
  2718. *
  2719. * EXIT_ERROR:  Error Code.
  2720. *
  2721. * EFFECTS:
  2722. *
  2723. * INTERNAL REFERENCES: SpiEnableEvent()
  2724. *
  2725. * EXTERNAL REFERENCES:
  2726. *
  2727. *********************** END OF SPECIFICATIONS *******************************/
  2728. RC DoTillEvent (INSTANCE *ulpInstance, DWORD dwTo)
  2729. {
  2730.   ULONG ulrc = MCIERR_SUCCESS;
  2731.   /***************************************
  2732.   * Enable a Time Cue Point.
  2733.   ***************************************/
  2734.   /***************************************/
  2735.   /* Set up a  TCP at This location      */
  2736.   /* When Event handler gets controll    */
  2737.   /* stop the stream                     */
  2738.   /***************************************/
  2739.  
  2740.   TIMEEVCB.dwCallback = (HWND)ulpInstance->dwCallback;
  2741.   TIMEEVCB.wDeviceID = ulpInstance->wWaveDeviceID;
  2742.   TIMEEVCB.evcb.ulType = EVENT_CUE_TIME_PAUSE;
  2743.   TIMEEVCB.evcb.ulFlags = EVENT_SINGLE;
  2744.   TIMEEVCB.evcb.hstream = STREAM.hStream;
  2745.   TIMEEVCB.ulpInstance = (ULONG)ulpInstance;
  2746.   TIMEEVCB.evcb.mmtimeStream =dwTo;
  2747.  
  2748.   /**************************************/
  2749.   // Enable A non recurring Time Event
  2750.   /*************************************/
  2751.  
  2752.   ulrc = SpiEnableEvent((PEVCB) &(TIMEEVCB.evcb),
  2753.                         (PHEVENT) &(STREAM.hPlayToEvent));
  2754.  
  2755.   return ulrc;
  2756.  
  2757. }
  2758.  
  2759. /********************* START OF SPECIFICATIONS *********************
  2760. *
  2761. * SUBROUTINE NAME:              GetPDDName
  2762. *
  2763. * DESCRIPTIVE NAME:
  2764. *
  2765. * FUNCTION:     Retrieves the PDD name (AUDIO1$, etc.) based
  2766. *               on which AmpMixer we're connected to
  2767. *
  2768. * NOTES:        DCR 104
  2769. *
  2770. * INPUT:
  2771. *                       ULONG         ulDeviceType
  2772. *                       CHAR          szPDDName [MAX_PDD_NAME]        - OUTPUT
  2773. *
  2774. * EXIT-NORMAL:  NO_ERROR
  2775. *
  2776. * EXIT_ERROR:
  2777. *
  2778. *********************** END OF SPECIFICATIONS *********************************/
  2779.  
  2780. RC GetPDDName (ULONG ulDeviceType, CHAR szPDDName [MAX_PDD_NAME])
  2781. {
  2782.    ULONG                   rc;
  2783.    CHAR                    szIndex[2];
  2784.    CHAR                    szAmpMix[9] = "AMPMIX0";
  2785.    MCI_SYSINFO_PARMS       SysInfo;
  2786.    LPMCI_SYSINFO_LOGDEVICE pSysInfoParm;
  2787.    LPMCI_SYSINFO_QUERY_NAME pQueryNameParm;
  2788.    extern HHUGEHEAP heap;
  2789.  
  2790.    /****************************************************
  2791.    * Get install name for ampmixer based on device type
  2792.    *****************************************************/
  2793.    AcquireProcSem ();
  2794.    if (!(pQueryNameParm = HhpAllocMem (heap,
  2795.                                        sizeof (MCI_SYSINFO_QUERY_NAME))))
  2796.        return (MCIERR_OUT_OF_MEMORY);
  2797.  
  2798.    ReleaseProcSem ();
  2799.    SysInfo.dwItem       = MCI_SYSINFO_QUERY_NAMES;
  2800.    SysInfo.wDeviceType  = LOUSHORT(ulDeviceType);
  2801.    SysInfo.pSysInfoParm = pQueryNameParm;
  2802.  
  2803.    /*********************************
  2804.    * AmpMixer name is AMPMIX01 or 02
  2805.    *********************************/
  2806.    _itoa (HIUSHORT(ulDeviceType), szIndex, 10);
  2807.  
  2808.      szIndex[1] = '\0';
  2809.  
  2810.    strncat (szAmpMix, szIndex, 2);
  2811.    strcpy (pQueryNameParm->szLogicalName, szAmpMix);
  2812.  
  2813.    if (rc = mciSendCommand (0,
  2814.                             MCI_SYSINFO,
  2815.                             MCI_SYSINFO_ITEM | MCI_WAIT,
  2816.                             (DWORD)&SysInfo,
  2817.                             0))
  2818.            return (rc);
  2819.  
  2820.  
  2821.    /*******************************************
  2822.    * Get PDD associated with our AmpMixer
  2823.    * Device name is in pSysInfoParm->szPDDName
  2824.    ********************************************/
  2825.    if (!(pSysInfoParm = HhpAllocMem (heap,
  2826.                                      sizeof (MCI_SYSINFO_LOGDEVICE))))
  2827.        return (MCIERR_OUT_OF_MEMORY);
  2828.  
  2829.    SysInfo.dwItem       = MCI_SYSINFO_QUERY_DRIVER;
  2830.    SysInfo.wDeviceType  = (WORD)ulDeviceType;
  2831.    SysInfo.pSysInfoParm = pSysInfoParm;
  2832.  
  2833.    strcpy (pSysInfoParm->szInstallName, pQueryNameParm->szInstallName);
  2834.  
  2835.    if (rc = mciSendCommand (0,
  2836.                             MCI_SYSINFO,
  2837.                             MCI_SYSINFO_ITEM | MCI_WAIT,
  2838.                             (DWORD)&SysInfo,
  2839.                             0))
  2840.        return (rc);
  2841.  
  2842.    strcpy (szPDDName, pSysInfoParm->szPDDName);
  2843.  
  2844.    //*************
  2845.    // Free memory
  2846.    //*************
  2847.  
  2848.    CleanUp ((PVOID) pSysInfoParm);
  2849.    CleanUp ((PVOID) pQueryNameParm);
  2850.  
  2851.  
  2852.  
  2853. }
  2854. /**************************************************************************
  2855. **   GenerateUniqueFile                                              **
  2856. ***************************************************************************
  2857. *
  2858. * ARGUMENTS:
  2859. *
  2860. * ARGUMENTS:
  2861. *
  2862. *     pszPathName    - Possible path where to create this file.
  2863. *                      Can be empty.  The full path name of the file will
  2864. *                      be returned in this parameter.
  2865. *     pulPathLength  - Length of the path that was passed.  The length
  2866. *                      of the path name will be returned in this parameter.
  2867. *     phfile         - Open dos handle.
  2868. *
  2869. * RETURN:
  2870. *
  2871. *     0 - Success,
  2872. *     1 - Invalid parameter determined by GenerateUniqueFile Routine
  2873. *     Other - Indicates DosOpen Error return.
  2874. *
  2875. * DESCRIPTION:
  2876. *
  2877. *     This routine will attempt to open a new file.  The fully qualified
  2878. *     name of the file and the open DOS handle will be returned if
  2879. *     successful.
  2880. *
  2881. * GLOBAL VARS REFERENCED:
  2882. *
  2883. * GLOBAL VARS MODIFIED:
  2884. *
  2885. * NOTES:
  2886. *
  2887. *     If the path name parameter is specified, it can or cannot have
  2888. *     the trailing / or \ included.  The full path is returned in all
  2889. *     successful cases.
  2890. *
  2891. * SIDE EFFECTS:
  2892. *
  2893. *     A DOS file may be opened.  It is the responsibility of the caller
  2894. *     to handle housekeeping for this file.
  2895. *
  2896. ***************************************************************************/
  2897.  
  2898. #define COLON        ':'
  2899. #define SLASH        '/'
  2900. #define BACKSLASH    '\\'
  2901. #define DOT          '.'
  2902. #define _MAX_PATH       260                 // max. length of full pathname
  2903. #define _MAX_DRIVE      3                   // max. length of drive component
  2904. #define _MAX_DIR        256                 // max. length of path component
  2905. #define _MAX_FNAME      256              // max. length of file name component
  2906. #define _MAX_EXT        256                 // max. length of extension component
  2907. ULONG APIENTRY GenerateUniqueFile( PSZ pszPathName,
  2908.                                    PULONG pulPathLength,
  2909.                                    PHFILE phfile )
  2910. {
  2911. #define MAX_RETRIES     1000000L  // should be enough, 1 million
  2912. #define RADIX_10        10
  2913. #define NAME_8_3        11
  2914. #define DOT_POSITION    8
  2915. #define EXTENSION_LEN   3
  2916.    PEAOP2 pEABuf;
  2917.    ULONG  ulActionTaken;
  2918.    ULONG  ulFileAttribute;
  2919.    ULONG  ulFileSize;
  2920.    ULONG  ulOpenFlags;
  2921.    ULONG  ulOpenMode;
  2922.    ULONG  ulReturnCode;
  2923.  
  2924.    CHAR szDir     [_MAX_DIR];
  2925.    CHAR szDrive   [_MAX_DRIVE + 1];
  2926.    CHAR szExt     [_MAX_EXT];
  2927.    CHAR szName    [_MAX_FNAME];
  2928.    CHAR szTempName[_MAX_FNAME];
  2929.    CHAR szTempPath[_MAX_PATH];
  2930.  
  2931.    ULONG cTries;
  2932.    BOOL  fUnique;
  2933.  
  2934.    ULONG ulCopyLength;
  2935.    ULONG ulDiskNumber;
  2936.    ULONG ulLogicalDriveMap;
  2937.    ULONG ulPathSize;
  2938.    ULONG ulTempNameLength;
  2939.    ULONG ulTempPathLength;
  2940.  
  2941.    if (!pszPathName || !pulPathLength || !phfile)
  2942.       {
  2943.       return (TRUE);
  2944.       }
  2945.  
  2946.    *phfile = 0L;
  2947.  
  2948.    /*
  2949.     * Zap storage.  Copy path.
  2950.     */
  2951.  
  2952.    memset( szDrive, '\0', sizeof(szDrive) );
  2953.    memset( szDir,   '\0', sizeof(szDir) );
  2954.    memset( szName,  '\0', sizeof(szName) );
  2955.    memset( szExt,   '\0', sizeof(szExt) );
  2956.  
  2957.    memset( szTempPath, '\0', sizeof(szTempPath) );
  2958.  
  2959.    ulTempPathLength = strlen( pszPathName );
  2960.  
  2961.    if (ulTempPathLength >= *pulPathLength)
  2962.       {
  2963.       return (TRUE);
  2964.       }
  2965.  
  2966.    /*
  2967.     * Determine if the path contains a / or \ terminator, and if not
  2968.     * tack one on to the end so _splitpath will work correctly.
  2969.     */
  2970.  
  2971.    if ((pszPathName[ulTempPathLength - 1L] != '/') &&
  2972.        (pszPathName[ulTempPathLength - 1L] != '\\'))
  2973.       {
  2974.       pszPathName[ulTempPathLength] = '\\';
  2975.       }
  2976.  
  2977.    /*
  2978.     * Determine if a path was specified.
  2979.     */
  2980.  
  2981.    if (*pulPathLength > 0L)
  2982.       {
  2983.       _splitpath( pszPathName,
  2984.                   szDrive,
  2985.                   szDir,
  2986.                   szName,
  2987.                   szExt );
  2988.       }
  2989.  
  2990.    /*
  2991.     * Fill in missing pieces of the path.
  2992.     */
  2993.  
  2994.    if (*szDrive == (CHAR)NULL)
  2995.       {
  2996.       DosQueryCurrentDisk( &ulDiskNumber,
  2997.                            &ulLogicalDriveMap );
  2998.  
  2999.       szDrive[0] = (CHAR)(ulDiskNumber + 64);
  3000.       szDrive[1] = ':';
  3001.       }
  3002.    else
  3003.       {
  3004.       ulDiskNumber = (CHAR)(szDrive[0] - 64);
  3005.       }
  3006.  
  3007.    strcpy( szTempPath, szDrive );
  3008.  
  3009.    if (*szDir == (CHAR)NULL)
  3010.       {
  3011.       szTempPath[2] = '\\';
  3012.  
  3013.       ulPathSize = _MAX_PATH;
  3014.  
  3015.  
  3016.       DosQueryCurrentDir( ulDiskNumber,
  3017.                           szDir,
  3018.                           &ulPathSize );
  3019.  
  3020.       if ((szDir[0] == '\\') ||
  3021.           (szDir[0] == '/'))
  3022.          {
  3023.          if (strlen( szDir ) > 1L)
  3024.             {
  3025.             strncpy( &szTempPath[3],
  3026.                      &szDir[1],
  3027.                      (USHORT)min( strlen( szTempPath - 3L ),
  3028.                                   _MAX_PATH - 3L ) );
  3029.             }
  3030.          else
  3031.             {
  3032.             strncpy( &szTempPath[3],
  3033.                      szDir,
  3034.                      (USHORT)min( strlen( szTempPath - 3L ),
  3035.                                   _MAX_PATH - 3L ) );
  3036.             }
  3037.          }
  3038.       }
  3039.    else
  3040.       {
  3041.       strncpy( &szTempPath[2],
  3042.                szDir,
  3043.                (USHORT)min( (*pulPathLength - 3L),
  3044.                             _MAX_PATH - 3L ) );
  3045.       }
  3046.  
  3047.    ulTempPathLength = strlen( szTempPath );
  3048.  
  3049.    if (ulTempPathLength >= _MAX_PATH)
  3050.       {
  3051.       return (TRUE);
  3052.       }
  3053.  
  3054.    /*
  3055.     * Make sure there is room for the filename.
  3056.     */
  3057.  
  3058.    if (ulTempPathLength > _MAX_PATH - NAME_8_3 + 1L)
  3059.       {
  3060.       return (TRUE);
  3061.       }
  3062.  
  3063.    /*
  3064.     * Tack on a name.  Go into loop.
  3065.     */
  3066.  
  3067.    fUnique = FALSE;
  3068.  
  3069.    for (cTries = 1L; cTries < MAX_RETRIES; ++cTries)
  3070.       {
  3071.       memset( szTempName,'\0', sizeof(szTempName) );
  3072.       memset( szName,  '\0', sizeof(szName) );
  3073.       strcpy( szName, "00000000.000" );
  3074.  
  3075.       _ltoa( cTries,
  3076.              szTempName,
  3077.              RADIX_10 );
  3078.  
  3079.       if ((ulTempNameLength = strlen( szTempName )) > NAME_8_3)
  3080.          {
  3081.          break;
  3082.          }
  3083.  
  3084.       /*
  3085.        * Make the name 8_3 format.
  3086.        */
  3087.  
  3088.       if (ulTempNameLength >= EXTENSION_LEN)
  3089.          {
  3090.  
  3091.          /*
  3092.           * Copy the extension first, then the name.
  3093.           */
  3094.  
  3095.          strncpy( &szName[DOT_POSITION + 1],
  3096.                   &szTempName[ulTempNameLength - EXTENSION_LEN],
  3097.                   (USHORT)EXTENSION_LEN );
  3098.  
  3099.          ulTempNameLength -= EXTENSION_LEN;
  3100.  
  3101.          if (ulTempNameLength > 0)
  3102.             {
  3103.             strncpy( &szName[DOT_POSITION - ulTempNameLength],
  3104.                      &szTempName[0],
  3105.                      (USHORT)ulTempNameLength );
  3106.             }
  3107.          }
  3108.       else
  3109.          {
  3110.  
  3111.          /*
  3112.           * Copy the extension.
  3113.           */
  3114.  
  3115.          strncpy( &szName[NAME_8_3 + 1 - ulTempNameLength],
  3116.                   &szTempName[0],
  3117.                   (USHORT)ulTempNameLength );
  3118.          }
  3119.  
  3120.       /*
  3121.        * There should be enough room for the name to be copied.
  3122.        * String lengths were verified above.
  3123.        */
  3124.  
  3125.       strcpy( &szTempPath[ulTempPathLength],
  3126.               szName );
  3127.  
  3128.       /*
  3129.        * Attempt to open the file.  If already existing,
  3130.        * stay in the loop.
  3131.        */
  3132.  
  3133.       ulOpenFlags = 0L;
  3134.       ulOpenMode = 0L;
  3135.       ulFileSize = 0L;
  3136.       ulFileAttribute = 0L;
  3137.       pEABuf = NULL;
  3138.  
  3139.       ulFileAttribute |= FILE_NORMAL;
  3140.       ulOpenFlags |= FILE_CREATE | OPEN_ACTION_FAIL_IF_EXISTS;
  3141.       ulOpenMode |= OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE;
  3142.  
  3143.       /*
  3144.        * If Open fails, stay in loop.  Eventually, a failure
  3145.        * will occur.
  3146.        */
  3147.  
  3148.       if ((ulReturnCode = DosOpen( szTempPath,
  3149.                                    phfile,
  3150.                                    &ulActionTaken,
  3151.                                    ulFileSize,
  3152.                                    ulFileAttribute,
  3153.                                    ulOpenFlags,
  3154.                                    ulOpenMode,
  3155.                                    pEABuf )) == 0L)
  3156.          {
  3157.          fUnique = TRUE;
  3158.          break;
  3159.          }
  3160.       else
  3161.          {
  3162.          if (ulReturnCode != ERROR_OPEN_FAILED)
  3163.             {
  3164.             break;
  3165.             }
  3166.          }
  3167.       }
  3168.  
  3169.    /*
  3170.     * If successful, update count and copy name. Also return length of
  3171.     * entire path with temp file name included.
  3172.     * Handle is already set.
  3173.     * Success if a 0.  On Failure the DosOpen is returned at this point.
  3174.     */
  3175.  
  3176.    if (fUnique)
  3177.       {
  3178.       ulCopyLength = min( *pulPathLength, strlen(szTempPath));
  3179.  
  3180.       strncpy( pszPathName,
  3181.                szTempPath,
  3182.                (USHORT)ulCopyLength );
  3183.  
  3184.       if (ulCopyLength < *pulPathLength)
  3185.          {
  3186.          pszPathName[ulCopyLength] = '\0';
  3187.          }
  3188.  
  3189.       *pulPathLength = strlen(szTempPath);
  3190.       }
  3191.  
  3192.    return (((fUnique) ? FALSE : ulReturnCode));
  3193. }
  3194.