home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / audio / acmapp / aafile.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  79KB  |  3,022 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  aafile.c
  13. //
  14. //  Description:
  15. //      Contains routines to deal with the FILE menu - loading and saving
  16. //      files, and also contains some support routines for dealing with
  17. //      RIFF files.
  18. //
  19. //
  20. //==========================================================================;
  21.  
  22. #include <windows.h>
  23. #include <windowsx.h>
  24. #include <mmsystem.h>
  25. #include <memory.h>
  26.  
  27. #include <mmreg.h>
  28. #include <msacm.h>
  29.  
  30. #include "appport.h"
  31. #include "waveio.h"
  32. #include "acmapp.h"
  33.  
  34. #include "debug.h"
  35.  
  36.  
  37.  
  38. //==========================================================================;
  39. //
  40. //
  41. //
  42. //
  43. //==========================================================================;
  44.  
  45. //--------------------------------------------------------------------------;
  46. //  
  47. //  DWORD DosGetFileAttributes
  48. //  
  49. //  Description:
  50. //      INT 21 - DOS 2+ - GET FILE ATTRIBUTES
  51. //          AX = 4300h
  52. //          DS:DX -> ASCIZ file name or directory name without trailing slash
  53. //
  54. //      Return: CF set on error
  55. //              AX = error code (01h,02h,03h,05h) (see AH=59h)
  56. //              CF clear if successful
  57. //              CX = file attributes (see AX=4301h)
  58. //
  59. //      SeeAlso: AX=4301h, INT 2F/AX=110Fh
  60. //
  61. //      --------
  62. //      INT 21 - DOS 2+ - PUT FILE ATTRIBUTES (CHMOD)
  63. //          AX = 4301h
  64. //          CX = file attribute bits
  65. //              bit 0 = read only
  66. //                  1 = hidden file
  67. //                  2 = system file
  68. //                  3 = volume label
  69. //                  4 = subdirectory
  70. //                  5 = written since backup ("archive" bit)
  71. //                  8 = shareable (Novell NetWare)
  72. //          DS:DX -> ASCIZ file name
  73. //
  74. //      Return: CF set on error
  75. //              AX = error code (01h,02h,03h,05h) (see AH=59h)
  76. //          CF clear if successful
  77. //
  78. //      Note:   will not change volume label or directory attributes
  79. //
  80. //      SeeAlso: AX=4300h, INT 2F/AX=110Eh
  81. //  
  82. //  
  83. //  Arguments:
  84. //      LPTSTR pszFilePath:
  85. //  
  86. //  Return (DWORD):
  87. //  
  88. //  
  89. //--------------------------------------------------------------------------;
  90. #ifndef WIN32
  91. #pragma optimize("", off)
  92. DWORD FNGLOBAL DosGetFileAttributes
  93. (
  94.     LPTSTR          pszFilePath
  95. )
  96. {
  97.     WORD        fwDosAttributes;
  98.  
  99.     _asm
  100.     {
  101.         push    ds
  102.         mov     ax, 4300h
  103.         lds     dx, pszFilePath
  104.         int     21h
  105.         jnc     Get_File_Attributes_Continue
  106.  
  107.         xor     cx, cx
  108.  
  109. Get_File_Attributes_Continue:
  110.  
  111.         mov     fwDosAttributes, cx
  112.         pop     ds
  113.     }
  114.  
  115.  
  116.     return ((DWORD)fwDosAttributes);
  117. } // DosGetFileAttributes()
  118. #pragma optimize("", on)
  119. #endif
  120.  
  121.  
  122. //--------------------------------------------------------------------------;
  123. //  
  124. //  DWORD DosGetDateTime
  125. //  
  126. //  Description:
  127. //  
  128. //  Arguments:
  129. //      HFILE hf:
  130. //  
  131. //  Return (DWORD):
  132. //  
  133. //  
  134. //--------------------------------------------------------------------------;
  135. #ifndef WIN32
  136. #pragma optimize("", off)
  137. DWORD FNGLOBAL DosGetDateTime
  138. (
  139.     HFILE       hf
  140. )
  141. {
  142.     WORD        wDosDate;
  143.     WORD        wDosTime;
  144.  
  145.     _asm
  146.     {
  147.         mov     ax, 5700h
  148.         mov     bx, hf
  149.         int     21h
  150.         jnc     Get_Date_Time_Continue
  151.  
  152.         xor     cx, cx
  153.         xor     dx, dx
  154.  
  155. Get_Date_Time_Continue:
  156.  
  157.         mov     wDosDate, dx
  158.         mov     wDosTime, cx
  159.     }
  160.  
  161.  
  162.     return ((DWORD)MAKELONG(wDosDate, wDosTime));
  163. } // DosGetDateTime()
  164. #pragma optimize("", on)
  165. #endif
  166.  
  167.  
  168. //==========================================================================;
  169. //
  170. //
  171. //
  172. //
  173. //==========================================================================;
  174.  
  175. //--------------------------------------------------------------------------;
  176. //
  177. //  BOOL AcmAppFileSaveModified
  178. //
  179. //  Description:
  180. //      This function tests if the current file has been modified, and
  181. //      if it has it gives the option of saving the file.
  182. //
  183. //      NOTE! This function does *NOT* clear the modified bit for the
  184. //      file. The calling function must do this if necessary.
  185. //
  186. //  Arguments:
  187. //      HWND hwnd: Handle to main window.
  188. //
  189. //      PACMAPPFILEDESC paafd: Pointer to file descriptor.
  190. //
  191. //  Return (BOOL):
  192. //      Returns TRUE if the calling function should continue--the file was
  193. //      either saved or the user does not wish to save it. Returns FALSE
  194. //      if the calling function should cancel its operation--the user
  195. //      wants to keep the data, but it has not been saved.
  196. //
  197. //--------------------------------------------------------------------------;
  198.  
  199. BOOL FNGLOBAL AcmAppFileSaveModified
  200. (
  201.     HWND            hwnd,
  202.     PACMAPPFILEDESC paafd
  203. )
  204. {
  205.     BOOL    f;
  206.     int     n;
  207.  
  208.     //
  209.     //  check if the contents of the file have been modified--if they have
  210.     //  then ask the user if they want to save the current contents...
  211.     //
  212.     f = (0 != (ACMAPPFILEDESC_STATEF_MODIFIED & paafd->fdwState));
  213.     if (f)
  214.     {
  215.         //
  216.         //  display an appropriate message box asking for the user's opinion
  217.         //
  218.         n = AppMsgBox(hwnd, MB_YESNOCANCEL | MB_ICONQUESTION| MB_SETFOREGROUND,
  219.                       TEXT("The file '%s' has been modified. Do you want to save these changes?"),
  220.                       (LPSTR)paafd->szFilePath);
  221.         switch (n)
  222.         {
  223.             case IDYES:
  224.                 f = AppFileSave(hwnd, paafd, FALSE);
  225.                 if (f)
  226.                     break;
  227.  
  228.                 // -- fall through --
  229.  
  230.             case IDCANCEL:
  231.                 //
  232.                 //  don't continue!
  233.                 //
  234.                 return (FALSE);
  235.  
  236.             case IDNO:
  237.                 break;
  238.         }
  239.     }
  240.  
  241.     //
  242.     //  ok to continue...
  243.     //
  244.     return (TRUE);
  245. } // AcmAppFileSaveModified()
  246.  
  247.  
  248. //--------------------------------------------------------------------------;
  249. //
  250. //  BOOL AcmAppFileNew
  251. //
  252. //  Description:
  253. //
  254. //  Arguments:
  255. //      HWND hwnd: Handle to main window.
  256. //
  257. //      PACMAPPFILEDESC paafd: Pointer to file descriptor.
  258. //
  259. //  Return (BOOL):
  260. //
  261. //--------------------------------------------------------------------------;
  262.  
  263. BOOL FNGLOBAL AcmAppFileNew
  264. (
  265.     HWND                hwnd,
  266.     PACMAPPFILEDESC     paafd
  267. )
  268. {
  269.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  270.     TCHAR               szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  271.     MMRESULT            mmr;
  272.     LPWAVEFORMATEX      pwfx;
  273.     DWORD               cbwfx;
  274.     BOOL                f;
  275.     ACMFORMATCHOOSE     afc;
  276.     HMMIO               hmmio;
  277.     MMCKINFO            ckRIFF;
  278.     MMCKINFO            ck;
  279.     DWORD               cSamples;
  280.  
  281.  
  282.  
  283.     if (!gfAcmAvailable)
  284.     {
  285.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  286.                   TEXT("AcmAppFileNew() called when ACM is not installed!"));
  287.         return (FALSE);
  288.     }
  289.  
  290.  
  291.     //
  292.     //  test for a modified file first...
  293.     //
  294.     f = AcmAppFileSaveModified(hwnd, paafd);
  295.     if (!f)
  296.         return (FALSE);
  297.  
  298.  
  299.     //
  300.     //  get a filename
  301.     //
  302.     szFileTitle[0] = '\0';
  303.     szFilePath[0]  = '\0';
  304.  
  305.     f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_SAVE);
  306.     if (!f)
  307.         return (FALSE);
  308.  
  309.  
  310.     //
  311.     //
  312.     //
  313.     //
  314.     //
  315.     //
  316.     mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfx);
  317.     if (MMSYSERR_NOERROR != mmr)
  318.     {
  319.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  320.                   TEXT("AcmAppFileNew() acmMetrics failed mmr=%u!"), mmr);
  321.         return (FALSE);
  322.     }
  323.  
  324.     pwfx = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, cbwfx);
  325.     if (NULL == pwfx)
  326.     {
  327.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  328.                   TEXT("AcmAppFileNew() GlobalAllocPtr(%lu) failed!"), cbwfx);
  329.         return (FALSE);
  330.     }
  331.  
  332.  
  333.     //
  334.     //
  335.     //
  336.     //
  337.     f = FALSE;
  338.  
  339.  
  340.     //
  341.     //  initialize the ACMFORMATCHOOSE members
  342.     //
  343.     memset(&afc, 0, sizeof(afc));
  344.  
  345.     afc.cbStruct        = sizeof(afc);
  346.     afc.fdwStyle        = ACMFORMATCHOOSE_STYLEF_SHOWHELP;
  347.     afc.hwndOwner       = hwnd;
  348.     afc.pwfx            = pwfx;
  349.     afc.cbwfx           = cbwfx;
  350.     afc.pszTitle        = TEXT("ACM App: New Format Choice");
  351.  
  352.     afc.szFormatTag[0]  = '\0';
  353.     afc.szFormat[0]     = '\0';
  354.     afc.pszName         = NULL;
  355.     afc.cchName         = 0;
  356.  
  357.     afc.fdwEnum         = 0;
  358.     afc.pwfxEnum        = NULL;
  359.  
  360.     afc.hInstance       = NULL;
  361.     afc.pszTemplateName = NULL;
  362.     afc.lCustData       = 0L;
  363.     afc.pfnHook         = NULL;
  364.  
  365.  
  366.     //
  367.     //
  368.     //
  369.     mmr = acmFormatChoose(&afc);
  370.     if (MMSYSERR_NOERROR != mmr)
  371.     {
  372.         if (ACMERR_CANCELED != mmr)
  373.         {
  374.             AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  375.                     TEXT("acmFormatChoose() failed with error = %u!"), mmr);
  376.         }
  377.         
  378.         GlobalFreePtr(pwfx);
  379.         return (FALSE);
  380.     }
  381.  
  382.  
  383.     //
  384.     //
  385.     //
  386.     hmmio = mmioOpen(szFilePath,
  387.                      NULL,
  388.                      MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE | MMIO_ALLOCBUF);
  389.     if (NULL == hmmio)
  390.     {
  391.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  392.                   TEXT("AcmAppFileNew() cannot create file '%s'!"), (LPSTR)szFilePath);
  393.       
  394.         GlobalFreePtr(pwfx);
  395.         return (FALSE);
  396.     }
  397.  
  398.  
  399.     //
  400.     //  create the RIFF chunk of form type 'WAVE'
  401.     //
  402.     ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  403.     ckRIFF.cksize  = 0L;
  404.     mmioCreateChunk(hmmio, &ckRIFF, MMIO_CREATERIFF);
  405.  
  406.  
  407.     //
  408.     //  now create the destination fmt, fact, and data chunks _in that order_
  409.     //
  410.     //  hmmio is now descended into the 'RIFF' chunk--create the format chunk
  411.     //  and write the format header into it
  412.     //
  413.     cbwfx = SIZEOF_WAVEFORMATEX(pwfx);
  414.  
  415.     ck.ckid   = mmioFOURCC('f', 'm', 't', ' ');
  416.     ck.cksize = 0L;
  417.     mmioCreateChunk(hmmio, &ck, 0);
  418.  
  419.     mmioWrite(hmmio, (HPSTR)pwfx, cbwfx);
  420.     mmioAscend(hmmio, &ck, 0);
  421.  
  422.     //
  423.     //  create the 'fact' chunk (not necessary for PCM--but is nice to have)
  424.     //  since we are not writing any data to this file (yet), we set the
  425.     //  samples contained in the file to 0..
  426.     //
  427.     ck.ckid   = mmioFOURCC('f', 'a', 'c', 't');
  428.     ck.cksize = 0L;
  429.     mmioCreateChunk(hmmio, &ck, 0);
  430.  
  431.     cSamples  = 0L;
  432.     mmioWrite(hmmio, (HPSTR)&cSamples, sizeof(DWORD));
  433.     mmioAscend(hmmio, &ck, 0);
  434.  
  435.  
  436.     //
  437.     //  create the data chunk with no data..
  438.     //
  439.     ck.ckid   = mmioFOURCC('d', 'a', 't', 'a');
  440.     ck.cksize = 0L;
  441.     mmioCreateChunk(hmmio, &ck, 0);
  442.     mmioAscend(hmmio, &ck, 0);
  443.  
  444.     mmioAscend(hmmio, &ckRIFF, 0);
  445.  
  446.     mmioClose(hmmio, 0);
  447.  
  448.  
  449.     //
  450.     //
  451.     //
  452.     GlobalFreePtr(pwfx);
  453.  
  454.     lstrcpy(paafd->szFilePath, szFilePath);
  455.     lstrcpy(paafd->szFileTitle, szFileTitle);
  456.  
  457.     return (AcmAppFileOpen(hwnd, paafd));
  458.  
  459.  
  460.     //
  461.     //  success
  462.     //
  463.     return (TRUE);
  464. } // AcmAppFileNew()
  465.  
  466.  
  467. //--------------------------------------------------------------------------;
  468. //
  469. //  BOOL AcmAppFileOpen
  470. //
  471. //  Description:
  472. //      This function opens the specified file and get the important info
  473. //      from it.
  474. //
  475. //      NOTE! This function does NOT check for a modified file! It is
  476. //      assumed that the calling function took care of everything before
  477. //      calling this function.
  478. //
  479. //  Arguments:
  480. //      HWND hwnd: Handle to main window.
  481. //
  482. //      PACMAPPFILEDESC paafd: Pointer to file descriptor.
  483. //
  484. //  Return (BOOL):
  485. //      The return value is TRUE if the function is successful. It is FALSE
  486. //      if an error occurred. If an error does occur, then the contents
  487. //      of the file descriptor will remain unchanged.
  488. //
  489. //
  490. //--------------------------------------------------------------------------;
  491.  
  492. BOOL FNGLOBAL AcmAppFileOpen
  493. (
  494.     HWND            hwnd,
  495.     PACMAPPFILEDESC paafd
  496. )
  497. {
  498.     WAVEIOCB    wio;
  499.     WIOERR      werr;
  500.  
  501. #ifdef WIN32
  502.     HANDLE      hf;
  503. #else
  504.     #define SEEK_SET        0       // flags for _lseek
  505.     #define SEEK_CUR        1
  506.     #define SEEK_END        2
  507.  
  508.     HFILE       hf;
  509.     OFSTRUCT    of;
  510.     DWORD       dw;
  511. #endif
  512.     DWORD       cbFileSize;
  513.     BOOL        fReturn;
  514.  
  515.  
  516.  
  517.     //
  518.     //  blow previous stuff...
  519.     //
  520.     if (NULL != paafd->pwfx)
  521.     {
  522.         GlobalFreePtr(paafd->pwfx);
  523.         paafd->pwfx  = NULL;
  524.         paafd->cbwfx = 0;
  525.     }
  526.  
  527.     paafd->fdwState          = 0L;
  528.     paafd->cbFileSize        = 0L;
  529.     paafd->uDosChangeDate    = 0;
  530.     paafd->uDosChangeTime    = 0;
  531.     paafd->fdwFileAttributes = 0L;
  532.     paafd->dwDataBytes       = 0L;
  533.     paafd->dwDataSamples     = 0L;
  534.  
  535.  
  536.     //
  537.     //  open the file for reading..
  538.     //
  539. #ifdef WIN32
  540.     hf = CreateFile(paafd->szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
  541.                     OPEN_EXISTING, 0, 0);
  542.     if (INVALID_HANDLE_VALUE == hf)
  543.         return (FALSE);
  544. #else
  545.     of.cBytes = sizeof(of);
  546.     hf = OpenFile(paafd->szFilePath, &of, OF_READ);
  547.     if (HFILE_ERROR == hf)
  548.         return (FALSE);
  549. #endif
  550.  
  551.     //
  552.     //  assume the worst
  553.     //
  554.     fReturn = FALSE;
  555.  
  556.     //
  557.     //  determine the length in _bytes_ of the file
  558.     //
  559. #ifdef WIN32
  560.     cbFileSize = GetFileSize((HANDLE)hf, NULL);
  561. #else
  562.     cbFileSize = _llseek(hf, 0L, SEEK_END);
  563.     _llseek(hf, 0L, SEEK_SET);
  564. #endif
  565.  
  566.  
  567.     //
  568.     //
  569.     //
  570.     //
  571.     paafd->cbFileSize        = cbFileSize;
  572.  
  573. #ifdef WIN32
  574. {
  575.     BY_HANDLE_FILE_INFORMATION  bhfi;
  576.     WORD                        wDosChangeDate;
  577.     WORD                        wDosChangeTime;
  578.  
  579.     GetFileInformationByHandle(hf, &bhfi);
  580.  
  581.     paafd->fdwFileAttributes = bhfi.dwFileAttributes;
  582.  
  583.     FileTimeToDosDateTime(&bhfi.ftLastWriteTime,
  584.                           &wDosChangeDate, &wDosChangeTime);
  585.  
  586.     paafd->uDosChangeDate = (UINT)wDosChangeDate;
  587.     paafd->uDosChangeTime = (UINT)wDosChangeTime;
  588. }
  589. #else
  590.     paafd->fdwFileAttributes = DosGetFileAttributes(paafd->szFilePath);
  591.  
  592.     dw = DosGetDateTime(hf);
  593.     paafd->uDosChangeDate = LOWORD(dw);
  594.     paafd->uDosChangeTime = HIWORD(dw);
  595. #endif
  596.  
  597.  
  598.     //
  599.     //  now return the fully qualified path and title for the file
  600.     //
  601. #ifndef WIN32
  602.     lstrcpy(paafd->szFilePath, of.szPathName);
  603. #endif
  604.     AppGetFileTitle(paafd->szFilePath, paafd->szFileTitle);
  605.  
  606. #ifdef WIN32
  607.     CloseHandle(hf);
  608. #else
  609.     _lclose(hf);
  610. #endif
  611.  
  612.  
  613.     //
  614.     //
  615.     //
  616.     //
  617.     werr = wioFileOpen(&wio, paafd->szFilePath, 0L);
  618.     if (WIOERR_NOERROR == werr)
  619.     {
  620.         UINT        cbwfx;
  621.  
  622.         cbwfx = SIZEOF_WAVEFORMATEX(wio.pwfx);
  623.  
  624.         paafd->pwfx = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, cbwfx);
  625.         if (NULL != paafd->pwfx)
  626.         {
  627.             _fmemcpy(paafd->pwfx, wio.pwfx, cbwfx);
  628.  
  629.             paafd->cbwfx         = cbwfx;
  630.  
  631.             paafd->dwDataBytes   = wio.dwDataBytes;
  632.             paafd->dwDataSamples = wio.dwDataSamples;
  633.  
  634.             fReturn = TRUE;
  635.         }
  636.  
  637.         wioFileClose(&wio, 0L);
  638.     }
  639.     else
  640.     {
  641.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL,
  642.                   TEXT("The file '%s' cannot be loaded as a wave file (wio error=%u)."),
  643.                   (LPTSTR)paafd->szFilePath, werr);
  644.     }
  645.  
  646.  
  647.     //
  648.     //  !!! before returning, we really should try to display a error
  649.     //      message... memory error, etc..
  650.     //
  651.     return (fReturn);
  652. } // AcmAppFileOpen()
  653.  
  654.  
  655. //--------------------------------------------------------------------------;
  656. //  
  657. //  BOOL AcmAppOpenInstance
  658. //  
  659. //  Description:
  660. //  
  661. //  
  662. //  Arguments:
  663. //      HWND hwnd:
  664. //  
  665. //      LPCTSTR pszFilePath:
  666. //  
  667. //      BOOL fForceOpen:
  668. //  
  669. //  Return (BOOL):
  670. //  
  671. //--------------------------------------------------------------------------;
  672.  
  673. BOOL FNLOCAL AcmAppOpenInstance
  674. (
  675.     HWND                    hwnd,
  676.     LPCTSTR                 pszFilePath,
  677.     BOOL                    fForceOpen
  678. )
  679. {
  680.     TCHAR               szCmdLine[APP_MAX_FILE_PATH_CHARS * 2];
  681.     BOOL                f;
  682.     UINT                uDosErr;
  683.  
  684.  
  685.     //
  686.     //
  687.     //
  688.     if (!fForceOpen)
  689.     {
  690.         if (0 == (APP_OPTIONSF_AUTOOPEN * gfuAppOptions))
  691.         {
  692.             return (TRUE);
  693.         }
  694.     }
  695.  
  696.     //
  697.     //
  698.     //
  699.     if (0 == GetModuleFileName(ghinst, szCmdLine, SIZEOF(szCmdLine)))
  700.     {
  701.         //
  702.         //  this would be fatal
  703.         //
  704.         AppMsgBox(hwnd, MB_ICONEXCLAMATION | MB_OK,
  705.                   TEXT("GetModuleFileName() is unable to return self reference!"));
  706.  
  707.         return (FALSE);
  708.     }
  709.  
  710.     
  711.     lstrcat(szCmdLine, TEXT(" "));
  712.     lstrcat(szCmdLine, pszFilePath);
  713.  
  714. #ifdef WIN32
  715. {
  716.     STARTUPINFO         si;
  717.     PROCESS_INFORMATION pi;
  718.  
  719.     //
  720.     //  perform the equivalent of WinExec in NT, but we use a Unicode string
  721.     //
  722.     memset(&si, 0, sizeof(si));
  723.     si.cb           = sizeof(si);
  724.     si.dwFlags      = STARTF_USESHOWWINDOW;
  725.     si.wShowWindow  = SW_SHOW;
  726.  
  727.     f = CreateProcess(NULL,
  728.                       szCmdLine,
  729.                       NULL,
  730.                       NULL,
  731.                       FALSE, 
  732.                       0,
  733.                       NULL,
  734.                       NULL,
  735.                       &si,
  736.                       &pi);
  737.  
  738.     if (f)
  739.     {
  740.         //
  741.         //  as the docs say.. wait 10 second for process to go idle before
  742.         //  continuing.
  743.         //
  744.         WaitForInputIdle(pi.hProcess, 10000);
  745.  
  746.         CloseHandle(pi.hProcess);
  747.         CloseHandle(pi.hThread);
  748.     }
  749.     else
  750.     {
  751.         uDosErr = GetLastError();
  752.     }
  753. }
  754. #else
  755. {
  756.     uDosErr = WinExec(szCmdLine, SW_SHOW);
  757.     f = (uDosErr >= 32);
  758. }
  759. #endif
  760.  
  761.     if (!f)
  762.     {
  763.         AppMsgBox(hwnd, MB_ICONEXCLAMATION | MB_OK,
  764.                   TEXT("WinExec(%s) failed! DOS error=%u."),
  765.                   (LPTSTR)szCmdLine, uDosErr);
  766.  
  767.     }
  768.  
  769.     return (f);
  770. } // AcmAppOpenInstance()
  771.  
  772.  
  773.  
  774.  
  775.  
  776. //--------------------------------------------------------------------------;
  777. //
  778. //  BOOL AcmAppFileSave
  779. //
  780. //  Description:
  781. //      This function saves the file to the specified file.
  782. //
  783. //      NOTE! This function does NOT bring up a save file chooser dialog
  784. //      if the file path is invalid. The calling function is responsible
  785. //      for making sure the file path is valid before calling this function.
  786. //
  787. //      This function also does NOT modify the 'modified' bit of the file
  788. //      descriptor. This is up to the calling function.
  789. //
  790. //  Arguments:
  791. //      HWND hwnd: Handle to main window.
  792. //
  793. //      PACMAPPFILEDESC paafd: Pointer to file descriptor.
  794. //
  795. //  Return (BOOL):
  796. //      The return value is TRUE if the function is successful. It is FALSE
  797. //      if an error occurred. If an error does occur, then the contents
  798. //      of the file descriptor was not saved.
  799. //
  800. //--------------------------------------------------------------------------;
  801.  
  802. BOOL FNGLOBAL AcmAppFileSave
  803. (
  804.     HWND                    hwnd,
  805.     PACMAPPFILEDESC         paafd,
  806.     PTSTR                   pszFilePath,
  807.     PTSTR                   pszFileTitle,
  808.     UINT                    fuSave
  809. )
  810. {
  811.  
  812.     return (FALSE);
  813. } // AcmAppFileSave()
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820. //==========================================================================;
  821. //==========================================================================;
  822. //==========================================================================;
  823. //==========================================================================;
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833. //
  834. //
  835. //
  836.  
  837. #define IDD_INFOLIST            100
  838. #define IDD_INFOINFO            101
  839. #define IDD_INFOTEXT            102
  840.  
  841. #ifdef RC_INVOKED
  842.  
  843. #define DLG_INFOEDIT            31
  844.  
  845. #else
  846.                         
  847. #define DLG_INFOEDIT            MAKEINTRESOURCE(31)
  848.  
  849. #endif
  850.  
  851. ////////////////////////////////////////////////////////////////////////////
  852.  
  853. typedef struct tCHUNK
  854. {
  855.     FOURCC  fcc;
  856.     DWORD   cksize;
  857.     BYTE    data[];
  858. } CHUNK, * PCHUNK, far * LPCHUNK;
  859.  
  860.  
  861.  
  862. typedef struct tDISP
  863. {
  864.     DWORD   cfid;   // Clipboard id of data
  865.     HANDLE  h;      // handle to data
  866.     struct tDISP *  next;    // next in list
  867. } DISP;
  868.  
  869. typedef struct tINFODATA
  870. {
  871.     WORD    index;  // index into aINFO
  872.     WORD    wFlags; // flags for chunk
  873.     DWORD   dwINFOOffset;   // offset in file to INFO chunk
  874.     
  875. #define INFOCHUNK_MODIFIED  1
  876. #define INFOCHUNK_REVERT    2   // command to revert to original text
  877.  
  878.     LPCTSTR   lpText; // text of modified chunk.  None if NULL.
  879.  
  880.     struct tINFODATA  near *  pnext; // next read sub-chunk
  881. } INFODATA, * PINFODATA, FAR * LPINFODATA;
  882.  
  883. typedef struct tINFOCHUNK
  884. {
  885.     LPTSTR   lpChunk;    // complete chunk in memory (GlobalPtr)
  886.     DWORD   cksize;     // size of chunk data
  887.     PINFODATA   pHead;  // first sub-chunk data
  888. } INFOCHUNK, * PINFOCHUNK, FAR * LPINFOCHUNK;
  889.  
  890. ////////////////////////////////////////////////////////////////////////////
  891. //
  892. //  error returns from RIFF functions
  893. //
  894. #define RIFFERR_BASE         (0)
  895. #define RIFFERR_NOERROR      (0)
  896. #define RIFFERR_ERROR        (RIFFERR_BASE+1)
  897. #define RIFFERR_BADPARAM     (RIFFERR_BASE+2)
  898. #define RIFFERR_FILEERROR    (RIFFERR_BASE+3)
  899. #define RIFFERR_NOMEM        (RIFFERR_BASE+4)
  900. #define RIFFERR_BADFILE      (RIFFERR_BASE+5)
  901.  
  902. ////////////////////////////////////////////////////////////////////////////
  903. //
  904. //  public function prototypes
  905. //
  906.  
  907. #define RIFFAPI  FAR PASCAL
  908.  
  909.  
  910. BOOL RIFFAPI riffCopyList(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck);
  911. BOOL RIFFAPI riffCopyChunk(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck);
  912.  
  913. LRESULT RIFFAPI  riffInitINFO(INFOCHUNK FAR * FAR * lplpInfo);
  914. LRESULT RIFFAPI  riffReadINFO(HMMIO hmmio, const LPMMCKINFO lpck, LPINFOCHUNK lpInfo);
  915. LRESULT RIFFAPI  riffEditINFO(HWND hwnd, LPINFOCHUNK lpInfo, HINSTANCE hInst);
  916. LRESULT RIFFAPI  riffFreeINFO(INFOCHUNK FAR * FAR * lpnpInfo);
  917. LRESULT RIFFAPI riffWriteINFO(HMMIO hmmioDst, LPINFOCHUNK lpInfo);
  918.  
  919.  
  920. LRESULT RIFFAPI  riffReadDISP(HMMIO hmmio, LPMMCKINFO lpck, DISP FAR * FAR * lpnpDisp);
  921. LRESULT RIFFAPI  riffFreeDISP(DISP FAR * FAR * lpnpDisp);
  922. LRESULT RIFFAPI riffWriteDISP(HMMIO hmmio, DISP FAR * FAR * lpnpDisp);
  923.  
  924.  
  925. LRESULT NEAR PASCAL riffParseINFO(const LPINFOCHUNK lpInfo);
  926.  
  927.  
  928.  
  929. /** BOOL RIFFAPI riffCopyChunk(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck)
  930.  *
  931.  *  DESCRIPTION:
  932.  *      
  933.  *
  934.  *  ARGUMENTS:
  935.  *      (LPWAVECONVCB lpwc, LPMMCKINFO lpck)
  936.  *
  937.  *  RETURN (BOOL NEAR PASCAL):
  938.  *
  939.  *
  940.  *  NOTES:
  941.  *
  942.  **  */
  943.  
  944. BOOL RIFFAPI riffCopyChunk(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck)
  945. {
  946.     MMCKINFO    ck;
  947.     HPSTR       hpBuf;
  948.  
  949.     //
  950.     //
  951.     //
  952.     hpBuf = (HPSTR)GlobalAllocPtr(GHND, lpck->cksize);
  953.     if (!hpBuf)
  954.         return (FALSE);
  955.  
  956.     ck.ckid   = lpck->ckid;
  957.     ck.cksize = lpck->cksize;
  958.     if (mmioCreateChunk(hmmioDst, &ck, 0))
  959.         goto rscc_Error;
  960.         
  961.     if (mmioRead(hmmioSrc, hpBuf, lpck->cksize) != (LONG)lpck->cksize)
  962.         goto rscc_Error;
  963.  
  964.     if (mmioWrite(hmmioDst, hpBuf, lpck->cksize) != (LONG)lpck->cksize)
  965.         goto rscc_Error;
  966.  
  967.     if (mmioAscend(hmmioDst, &ck, 0))
  968.         goto rscc_Error;
  969.  
  970.     if (hpBuf)
  971.         GlobalFreePtr(hpBuf);
  972.  
  973.     return (TRUE);
  974.  
  975. rscc_Error:
  976.  
  977.     if (hpBuf)
  978.         GlobalFreePtr(hpBuf);
  979.  
  980.     return (FALSE);
  981. } /* RIFFSupCopyChunk() */
  982.  
  983. /** BOOL RIFFAPI riffCopyList(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck)
  984.  *
  985.  *  DESCRIPTION:
  986.  *      
  987.  *
  988.  *  ARGUMENTS:
  989.  *  (HMMIO hmmioSrc, HMMIO hmmioDst, LPMMCKINFO lpck)
  990.  *
  991.  *  RETURN (BOOL NEAR PASCAL):
  992.  *
  993.  *
  994.  *  NOTES:
  995.  *
  996.  ** */
  997.  
  998. BOOL RIFFAPI riffCopyList(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck)
  999. {
  1000.     MMCKINFO    ck;
  1001.     HPSTR       hpBuf;
  1002.     DWORD       dwCopySize;
  1003.  
  1004.     hpBuf = (HPSTR)GlobalAllocPtr(GHND, lpck->cksize);
  1005.     if (!hpBuf)
  1006.         return (FALSE);
  1007.  
  1008.     dwCopySize=lpck->cksize;
  1009.     
  1010.     // mmio leaves us after LIST ID
  1011.         
  1012.     ck.ckid   = lpck->ckid;
  1013.     ck.cksize = dwCopySize;
  1014.     ck.fccType= lpck->fccType;
  1015.         
  1016.     if (mmioCreateChunk(hmmioDst, &ck, MMIO_CREATELIST))
  1017.         goto rscl_Error;
  1018.  
  1019.     // we already wrote 'LIST' ID, so reduce byte count
  1020.     dwCopySize-=sizeof(FOURCC);
  1021.  
  1022.     if (mmioRead(hmmioSrc, hpBuf, dwCopySize) != (LONG)dwCopySize)
  1023.         goto rscl_Error;
  1024.  
  1025.     if (mmioWrite(hmmioDst, hpBuf, dwCopySize) != (LONG)dwCopySize)
  1026.         goto rscl_Error;
  1027.  
  1028.     if (mmioAscend(hmmioDst, &ck, 0))
  1029.         goto rscl_Error;
  1030.  
  1031.     if (hpBuf)
  1032.         GlobalFreePtr(hpBuf);
  1033.  
  1034.     return (TRUE);
  1035.  
  1036. rscl_Error:
  1037.  
  1038.     if (hpBuf)
  1039.         GlobalFreePtr(hpBuf);
  1040.  
  1041.     return (FALSE);
  1042. } /* RIFFSupCopyList() */
  1043.  
  1044.  
  1045. /////////////////////////////////////////////////////////////////////////////
  1046.  
  1047. typedef struct tINFO
  1048. {
  1049.     PTSTR       pFOURCC;
  1050.     PTSTR       pShort;
  1051.     PTSTR       pLong;
  1052. } INFO;
  1053.  
  1054. static INFO aINFO[]=
  1055. {
  1056. TEXT("IARL"), TEXT("Archival Location"),  TEXT("Indicates where the subject of the file is archived."),
  1057. TEXT("IART"), TEXT("Artist"),             TEXT("Lists the artist of the original subject of the file. For example, \"Michaelangelo.\""),
  1058. TEXT("ICMS"), TEXT("Commissioned"),       TEXT("Lists the name of the person or organization that commissioned the subject of the file. For example, \"Pope Julian II.\""),
  1059. TEXT("ICMT"), TEXT("Comments"),           TEXT("Provides general comments about the file or the subject of the file. If the comment is several sentences long, end each sentence with a period. Do not include newline characters."),
  1060. TEXT("ICOP"), TEXT("Copyright"),          TEXT("Records the copyright information for the file. For example, \"Copyright Encyclopedia International 1991.\" If there are multiple copyrights, separate them by a semicolon followed by a space."),
  1061. TEXT("ICRD"), TEXT("Creation date"),      TEXT("Specifies the date the subject of the file was created. List dates in year-month-day format, padding one-digit months and days with a zero on the left. For example, \"1553-05-03\" for May 3, 1553."),
  1062. TEXT("ICRP"), TEXT("Cropped"),            TEXT("Describes whether an image has been cropped and, if so, how it was cropped. For example, \"lower right corner.\""),
  1063. TEXT("IDIM"), TEXT("Dimensions"),         TEXT("Specifies the size of the original subject of the file. For example, \"8.5 in h, 11 in w.\""),
  1064. TEXT("IDPI"), TEXT("Dots Per Inch"),      TEXT("Stores dots per inch setting of the digitizer used to produce the file, such as \"300.\""),
  1065. TEXT("IENG"), TEXT("Engineer"),           TEXT("Stores the name of the engineer who worked on the file. If there are multiple engineers, separate the names by a semicolon and a blank. For example, \"Smith, John; Adams, Joe.\""),
  1066. TEXT("IGNR"), TEXT("Genre"),              TEXT("Describes the original work, such as, \"landscape,\" \"portrait,\" \"still life,\" etc."),
  1067. TEXT("IKEY"), TEXT("Keywords"),           TEXT("Provides a list of keywords that refer to the file or subject of the file. Separate multiple keywords with a semicolon and a blank. For example, \"Seattle; aerial view; scenery.\""),
  1068. TEXT("ILGT"), TEXT("Lightness"),          TEXT("Describes the changes in lightness settings on the digitizer required to produce the file. Note that the format of this information depends on hardware used."),
  1069. TEXT("IMED"), TEXT("Medium"),             TEXT("Describes the original subject of the file, such as, \"computer image,\" \"drawing,\" \"lithograph,\" and so forth."),
  1070. TEXT("INAM"), TEXT("Name"),               TEXT("Stores the title of the subject of the file, such as, \"Seattle From Above.\""),
  1071. TEXT("IPLT"), TEXT("Palette Setting"),    TEXT("Specifies the number of colors requested when digitizing an image, such as \"256.\""),
  1072. TEXT("IPRD"), TEXT("Product"),            TEXT("Specifies the name of the title the file was originally intended for, such as \"Encyclopedia of Pacific Northwest Geography.\""),
  1073. TEXT("ISBJ"), TEXT("Subject"),            TEXT("Describes the contents of the file, such as \"Aerial view of Seattle.\""),
  1074. TEXT("ISFT"), TEXT("Software"),           TEXT("Identifies the name of the software package used to create the file, such as \"Microsoft WaveEdit.\""),
  1075. TEXT("ISHP"), TEXT("Sharpness"),          TEXT("Identifies the changes in sharpness for the digitizer required to produce the file (the format depends on the hardware used)."),
  1076. TEXT("ISRC"), TEXT("Source"),             TEXT("Identifies the name of the person or organization who supplied the original subject of the file. For example, \"Trey Research.\""),
  1077. TEXT("ISRF"), TEXT("Source Form"),        TEXT("Identifies the original form of the material that was digitized, such as \"slide,\" \"paper,\" \"map,\" and so forth. This is not necessarily the same as IMED."),
  1078. TEXT("ITCH"), TEXT("Technician"),         TEXT("Identifies the technician who digitized the subject file. For example, \"Smith, John.\""),
  1079.  
  1080. NULL, NULL, NULL
  1081.  
  1082. };
  1083.  
  1084.  
  1085. void NEAR PASCAL riffInsertINFO(LPINFOCHUNK lpInfo, const PINFODATA pInfo)
  1086. {
  1087.     PINFODATA pI;
  1088.     
  1089.     if(!lpInfo)
  1090.         return;
  1091.     
  1092.     if(!lpInfo->pHead)
  1093.     {
  1094.         lpInfo->pHead=pInfo;
  1095.         return;
  1096.     }
  1097.     
  1098.     pI=lpInfo->pHead;
  1099.     while(pI->pnext)
  1100.     {
  1101.         pI=pI->pnext;
  1102.     }
  1103.     // insert at end
  1104.     pI->pnext=pInfo;
  1105.     
  1106.     return;
  1107. }
  1108.  
  1109. PINFODATA NEAR PASCAL riffCreateINFO(WORD id, WORD wFlags, DWORD dwInfoOffset, LPCTSTR lpText)
  1110. {
  1111.     PINFODATA pI;
  1112.     pI=(PINFODATA)LocalAlloc(LPTR,sizeof(INFODATA));
  1113.     if(!pI)
  1114.         return NULL;
  1115.     
  1116.     pI->index=id;
  1117.     pI->wFlags=wFlags;
  1118.     pI->dwINFOOffset=dwInfoOffset;
  1119.     pI->lpText=lpText;
  1120.     
  1121.     return pI;
  1122. }
  1123.  
  1124. LRESULT RIFFAPI riffInitINFO(INFOCHUNK FAR * FAR * lplpInfo)
  1125. {
  1126.     LPINFOCHUNK lpInfo;
  1127.     WORD        id;
  1128.     PINFODATA   pI;
  1129.     
  1130.     lpInfo=(LPINFOCHUNK)GlobalAllocPtr(GHND, sizeof(INFOCHUNK));
  1131.     if(!lpInfo)
  1132.         return RIFFERR_NOMEM;
  1133.     *lplpInfo=lpInfo;
  1134.  
  1135.     for (id=0;aINFO[id].pFOURCC;id++)
  1136.     {
  1137.         pI=riffCreateINFO(id, 0, 0L, NULL);   // create empty INFO
  1138.         riffInsertINFO(lpInfo,pI);
  1139.     }
  1140.     return RIFFERR_NOERROR;
  1141. }
  1142.  
  1143. LRESULT RIFFAPI riffReadINFO(HMMIO hmmio, const LPMMCKINFO lpck, LPINFOCHUNK lpInfo)
  1144. {
  1145.     DWORD       dwInfoSize;
  1146.  
  1147.     dwInfoSize=lpck->cksize - sizeof(FOURCC);   // take out 'INFO'
  1148.  
  1149.     lpInfo->cksize=dwInfoSize;
  1150.     lpInfo->lpChunk=(LPTSTR)GlobalAllocPtr(GHND, dwInfoSize);
  1151.     if(!lpInfo->lpChunk)
  1152.         return RIFFERR_NOMEM;
  1153.     
  1154.     if (mmioRead(hmmio, (HPSTR)lpInfo->lpChunk, dwInfoSize) != (LONG)dwInfoSize)
  1155.         return RIFFERR_FILEERROR;
  1156.     else
  1157.         return riffParseINFO(lpInfo);
  1158. }
  1159.  
  1160. PINFODATA NEAR PASCAL riffFindPIINFO(const LPINFOCHUNK lpInfo, FOURCC fcc)
  1161. {
  1162.     PINFODATA pI;
  1163.  
  1164.     pI=lpInfo->pHead;
  1165.     while(pI)
  1166.     {
  1167.         if(mmioStringToFOURCC(aINFO[pI->index].pFOURCC,0)==fcc)
  1168.             return(pI);
  1169.         pI=pI->pnext;
  1170.     }
  1171.     return NULL;
  1172. }
  1173.  
  1174. void NEAR PASCAL riffModifyINFO(const LPINFOCHUNK lpInfo, PINFODATA pI, WORD wFlags, DWORD dw, LPCTSTR lpText)
  1175. {
  1176.     if(!pI)
  1177.         return;
  1178.     
  1179.     pI->wFlags=wFlags;
  1180.     if(!(wFlags&INFOCHUNK_MODIFIED))
  1181.         pI->dwINFOOffset=dw;
  1182.     
  1183.     if(pI->lpText)
  1184.     {
  1185.         if(lpText)
  1186.         {
  1187.             if(!lstrcmp(lpText,pI->lpText))
  1188.             {
  1189.                 // they are the same, don't bother changing...
  1190.                 GlobalFreePtr(lpText);
  1191.             }
  1192.             else
  1193.             {
  1194.                 GlobalFreePtr(pI->lpText);
  1195.                 pI->lpText=lpText;
  1196.             }
  1197.         }
  1198.         else if(wFlags&INFOCHUNK_REVERT)
  1199.         {
  1200.             GlobalFreePtr(pI->lpText);
  1201.             pI->lpText=NULL;
  1202.         }
  1203.     }
  1204.     else if(lpText)
  1205.     {
  1206.         // if no read data, don't bother to check....
  1207.         if(!lpInfo->lpChunk && *lpText)
  1208.         {
  1209.             pI->lpText=lpText;
  1210.         }
  1211.         else if(lstrcmp(lpText, (LPTSTR)lpInfo->lpChunk+pI->dwINFOOffset))
  1212.         {       // new text...
  1213.             if(*lpText)
  1214.                 // NOT the same, set...
  1215.                 pI->lpText=lpText;
  1216.             else
  1217.                 // new is blank, do nothing...
  1218.                 GlobalFreePtr(lpText);
  1219.         }
  1220.         else
  1221.             // the same, don't bother...
  1222.             GlobalFreePtr(lpText);
  1223.     }
  1224. }
  1225.  
  1226. WORD NEAR PASCAL riffFindaINFO(FOURCC fcc)
  1227. {
  1228.     WORD    id;
  1229.  
  1230.     for (id=0;aINFO[id].pFOURCC;id++)
  1231.     {
  1232.         if(mmioStringToFOURCC(aINFO[id].pFOURCC,0)==fcc)
  1233.             return id;
  1234.     }
  1235.     return 0xFFFF;
  1236. }
  1237.  
  1238.  
  1239.  
  1240. LRESULT NEAR PASCAL riffParseINFO(const LPINFOCHUNK lpInfo)
  1241. {
  1242.     LPTSTR   lpBuf;
  1243.     DWORD   dwCurInfoOffset;
  1244.     PINFODATA pI;
  1245.     LPCHUNK lpck;
  1246.  
  1247.     lpBuf=lpInfo->lpChunk;
  1248.     for(dwCurInfoOffset=0;dwCurInfoOffset<lpInfo->cksize;)
  1249.     {
  1250.         lpck=(LPCHUNK)((LPSTR)(lpBuf+dwCurInfoOffset));
  1251.         dwCurInfoOffset+=sizeof(CHUNK);   // dwCurInfoOffset is offset of data
  1252.         pI=riffFindPIINFO(lpInfo,lpck->fcc);
  1253.         if(!pI)
  1254.         {
  1255.             int     n;
  1256.  
  1257.             // file contains unknown INFO chunk
  1258.             n = AppMsgBox(NULL, MB_YESNO | MB_ICONEXCLAMATION | MB_TASKMODAL,
  1259.                           TEXT("This wave file contains an unknown item in the INFO chunk: '%4.4s'.  Open anyway?"),
  1260.                           (LPCSTR)(lpck));
  1261.             if (n == IDNO)
  1262.             {
  1263.                 return RIFFERR_BADFILE;
  1264.             }
  1265.             
  1266.             
  1267.         }
  1268.         else
  1269.         {
  1270.             // modify entry to show text (data) from file...
  1271.             riffModifyINFO(lpInfo, pI, 0, dwCurInfoOffset, NULL);
  1272.         }
  1273.         dwCurInfoOffset+=lpck->cksize+(lpck->cksize&1);  // skip past data
  1274.     }
  1275.  
  1276.     return RIFFERR_NOERROR;
  1277. }
  1278.  
  1279. LRESULT RIFFAPI riffFreeINFO(INFOCHUNK FAR * FAR * lplpInfo)
  1280. {
  1281.     PINFODATA   pI;
  1282.     PINFODATA   pIT;
  1283.     LPINFOCHUNK lpInfo;
  1284.     LRESULT     lr;
  1285.  
  1286.     lr    = RIFFERR_BADPARAM;
  1287.  
  1288.     if(!lplpInfo)
  1289.         goto riff_FI_Error;
  1290.     
  1291.     lpInfo=*lplpInfo;
  1292.     if(!lpInfo)
  1293.         goto riff_FI_Error;
  1294.     
  1295.     if(lpInfo->lpChunk)
  1296.         GlobalFreePtr(lpInfo->lpChunk);
  1297.  
  1298.  
  1299.     pI=lpInfo->pHead;
  1300.     
  1301.     while(pI)
  1302.     {
  1303.         pIT=pI;
  1304.         pI=pI->pnext;
  1305.         LocalFree((HANDLE)pIT);
  1306.     }
  1307.  
  1308.     
  1309.     //
  1310.  
  1311.     GlobalFreePtr(lpInfo);
  1312.     *lplpInfo=NULL;
  1313.     return RIFFERR_NOERROR;
  1314.     
  1315. riff_FI_Error:    
  1316.     return lr;
  1317. }
  1318.  
  1319.  
  1320. TCHAR   szBuf[255];
  1321.  
  1322. static BOOL NEAR PASCAL riffSetupEditBoxINFO(HWND hdlg, const LPINFOCHUNK lpInfo, WORD wFlags)
  1323. {
  1324.     static PTSTR szFormat = TEXT("%-4s%c %-25s");
  1325.     PINFODATA   pI;
  1326.     WORD        iSel;
  1327.     HWND        hLB;
  1328.     
  1329.     hLB=GetDlgItem(hdlg, IDD_INFOLIST);
  1330.     if(wFlags&INFOCHUNK_MODIFIED)
  1331.     {
  1332.         iSel = ComboBox_GetCurSel(hLB);
  1333.         
  1334.     }
  1335.     else
  1336.         iSel = 0;
  1337.  
  1338.     ComboBox_ResetContent(hLB);
  1339.     
  1340.     pI=lpInfo->pHead;
  1341.     
  1342.     while(pI)
  1343.     {
  1344.         wsprintf(szBuf,szFormat,
  1345.             (LPCSTR)aINFO[pI->index].pFOURCC,
  1346.             (pI->dwINFOOffset || ( (pI->lpText) && (pI->lpText[0]) ) ) ?
  1347.                         '*' : ' ',
  1348.             (LPCSTR)aINFO[pI->index].pShort
  1349.             );
  1350.  
  1351.         ComboBox_AddString(hLB, szBuf);
  1352.         pI=pI->pnext;
  1353.     }
  1354.     ComboBox_SetCurSel(hLB, iSel);
  1355.  
  1356.     if(!(wFlags&INFOCHUNK_MODIFIED))
  1357.     {
  1358.         // FIRST time only
  1359.         pI=lpInfo->pHead;
  1360.         if(pI)
  1361.             if(pI->lpText)
  1362.                 // Modified text
  1363.                 SetDlgItemText(hdlg, IDD_INFOTEXT, (LPCTSTR)pI->lpText);
  1364.             else if(pI->dwINFOOffset)
  1365.                 // default text
  1366.                 SetDlgItemText(hdlg, IDD_INFOTEXT, (LPCTSTR)(lpInfo->lpChunk+pI->dwINFOOffset));
  1367.             else
  1368.                 // no text
  1369.                 SetDlgItemText(hdlg, IDD_INFOTEXT, (LPCTSTR)TEXT(""));
  1370.         SetDlgItemText(hdlg, IDD_INFOINFO, (LPCTSTR)aINFO[0].pLong);
  1371.     }
  1372.     return TRUE;
  1373. }
  1374.  
  1375.  
  1376. static BOOL Cls_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1377. {
  1378.     LPINFOCHUNK lpInfo;
  1379.     HFONT       hFont;
  1380.     HWND        hLB;
  1381.  
  1382.     lpInfo = (LPINFOCHUNK)lParam;
  1383.     if(!lpInfo)
  1384.         return FALSE;
  1385.  
  1386.     SetWindowLong(hwnd, DWL_USER, (LONG)lpInfo);
  1387.             
  1388.     hFont = GetStockFont(SYSTEM_FIXED_FONT);
  1389.  
  1390.     hLB=GetDlgItem(hwnd, IDD_INFOLIST);
  1391.     SetWindowFont(hLB, hFont, FALSE);
  1392.  
  1393.     riffSetupEditBoxINFO(hwnd, lpInfo, 0);
  1394.  
  1395.     return TRUE;
  1396. }
  1397.  
  1398. static void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1399. {
  1400.     LPINFOCHUNK lpInfo;
  1401.     PINFODATA   pI;
  1402.     WORD        iSel;
  1403.     int         i;
  1404.     LPTSTR       lpstr;
  1405.  
  1406.     lpInfo=(LPINFOCHUNK)GetWindowLong(hwnd, DWL_USER);
  1407.             
  1408.     switch(id)
  1409.     {
  1410.         case IDOK:
  1411.         case IDCANCEL:
  1412.             EndDialog(hwnd, (id == IDOK));
  1413.             break;
  1414.         case IDD_INFOLIST:
  1415.             switch(codeNotify)
  1416.             {
  1417.                 case CBN_SELCHANGE:
  1418.  
  1419.                     iSel = ComboBox_GetCurSel(GetDlgItem(hwnd, id));
  1420.                     SetDlgItemText(hwnd, IDD_INFOINFO, (LPCTSTR)aINFO[iSel].pLong);
  1421.  
  1422.                     pI=lpInfo->pHead;
  1423.                     while(pI)
  1424.                     {
  1425.                         if(pI->index==iSel)
  1426.                             break;
  1427.                         pI=pI->pnext;
  1428.                     }
  1429.                     if(pI)
  1430.                     {
  1431.                         if(pI->lpText)
  1432.                             // Modified text
  1433.                             SetDlgItemText(hwnd, IDD_INFOTEXT, (LPCTSTR)pI->lpText);
  1434.                         else if(pI->dwINFOOffset)
  1435.                             // default text
  1436.                             SetDlgItemText(hwnd, IDD_INFOTEXT, (LPCTSTR)(lpInfo->lpChunk+pI->dwINFOOffset));
  1437.                         else
  1438.                             // no text
  1439.                             SetDlgItemText(hwnd, IDD_INFOTEXT, (LPCTSTR)TEXT(""));
  1440.                     }
  1441.                         else
  1442.                             SetDlgItemText(hwnd, IDD_INFOINFO, (LPCTSTR)TEXT("Can't FIND iSel"));
  1443.                     break;
  1444.             }
  1445.  
  1446.         case IDD_INFOTEXT:
  1447.             switch(codeNotify)
  1448.             {
  1449.                 case EN_KILLFOCUS:
  1450.                     // get text out and give to current id
  1451.                     iSel=(WORD)SendDlgItemMessage(hwnd,IDD_INFOLIST,CB_GETCURSEL,0,0L);
  1452.                     pI=lpInfo->pHead;
  1453.                     while(pI)
  1454.                     {
  1455.                         if(pI->index==iSel)
  1456.                             break;
  1457.                         pI=pI->pnext;
  1458.                     }
  1459.                     if(pI)
  1460.                     {
  1461.                         i=GetDlgItemText(hwnd, IDD_INFOTEXT, szBuf,sizeof(szBuf));
  1462.                         lpstr=(LPTSTR)GlobalAllocPtr(GHND,(DWORD)i+1);
  1463.                         if(!lpstr)
  1464.                             break;
  1465.  
  1466.                         lstrcpy(lpstr,szBuf);
  1467.  
  1468.                         riffModifyINFO(lpInfo, pI, INFOCHUNK_MODIFIED, 0, lpstr);
  1469.  
  1470.                         riffSetupEditBoxINFO(hwnd, lpInfo, INFOCHUNK_MODIFIED);
  1471.                     }
  1472.                     else
  1473.                         SetDlgItemText(hwnd, IDD_INFOINFO, (LPCTSTR)TEXT("Can't FIND iSel"));
  1474.                     break;
  1475.  
  1476.             }
  1477.             break;
  1478.         case IDD_INFOINFO:
  1479.             break;
  1480.     }
  1481.  
  1482. }                           
  1483.  
  1484. BOOL FNGLOBAL DlgProcINFOEdit(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1485. {
  1486.     switch (uMsg)
  1487.     {
  1488.         case WM_INITDIALOG:
  1489.             return (BOOL)(UINT)(DWORD)(LRESULT)HANDLE_WM_INITDIALOG(hdlg, wParam, lParam, Cls_OnInitDialog);
  1490.  
  1491.         case WM_COMMAND:
  1492.             HANDLE_WM_COMMAND(hdlg, wParam, lParam, Cls_OnCommand);
  1493.             break;
  1494.     }
  1495.  
  1496.     return FALSE;
  1497. }
  1498.  
  1499.  
  1500. LRESULT RIFFAPI riffEditINFO(HWND hwnd, LPINFOCHUNK lpInfo, HINSTANCE hInst)
  1501. {
  1502.     LRESULT     lr;
  1503.     DLGPROC     lpfn;
  1504. #ifdef DEBUG    
  1505.     int         i;
  1506. #endif
  1507.     
  1508.     lr    = RIFFERR_BADPARAM;
  1509.  
  1510.     if(!lpInfo)
  1511.         goto riff_EI_Error;
  1512.  
  1513.     if (lpfn = (DLGPROC)MakeProcInstance((FARPROC)DlgProcINFOEdit, hInst))
  1514.     {
  1515. #ifdef DEBUG
  1516.         i=
  1517. #endif
  1518.         DialogBoxParam(hInst, DLG_INFOEDIT, hwnd, lpfn, (LPARAM)(LPVOID)lpInfo);
  1519.         FreeProcInstance((FARPROC)lpfn);
  1520.         lr=RIFFERR_NOERROR;
  1521. #ifdef DEBUG
  1522.         if(i==-1)
  1523.         {
  1524.             MessageBox(hwnd, TEXT("INFO Edit Error: DLG_INFOEDIT not found.  Check .RC file."), TEXT("RIFF SUP module"), MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
  1525.             lr=RIFFERR_ERROR;
  1526.         }
  1527. #endif
  1528.         
  1529.     }
  1530. #ifdef DEBUG
  1531.     else
  1532.     {
  1533.         MessageBox(hwnd, TEXT("INFO Edit Error: Can't MakeProcInstace()"), TEXT("RIFF SUP module"), MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
  1534.         lr=RIFFERR_ERROR;
  1535.     }
  1536. #endif
  1537.     
  1538. riff_EI_Error:    
  1539.     return lr;
  1540. }
  1541.  
  1542. LRESULT RIFFAPI riffWriteINFO(HMMIO hmmioDst, LPINFOCHUNK lpInfo)
  1543. {
  1544.     LRESULT     lr;
  1545.     MMCKINFO    ck;
  1546.     MMCKINFO    ckINFO;
  1547.     PINFODATA   pI;
  1548.     LPTSTR      lpstr;
  1549.     BOOL        fList=FALSE;
  1550.  
  1551.     lr    = RIFFERR_BADPARAM;
  1552.  
  1553.     if(!hmmioDst || !lpInfo)
  1554.         goto riff_SI_Error;
  1555.  
  1556.     lr=RIFFERR_FILEERROR;
  1557.     
  1558.     ckINFO.ckid   = mmioFOURCC('L', 'I', 'S', 'T');
  1559.     ckINFO.cksize = 0;  // mmio fill fill it in later
  1560.     ckINFO.fccType= mmioFOURCC('I', 'N', 'F', 'O');
  1561.         
  1562.     pI=lpInfo->pHead;
  1563.     
  1564.     while(pI)
  1565.     {
  1566.         if(pI->lpText)
  1567.             // Modified text
  1568.             lpstr=(LPTSTR)pI->lpText;
  1569.         else if(pI->dwINFOOffset)
  1570.             // default text
  1571.             lpstr=(lpInfo->lpChunk+pI->dwINFOOffset);
  1572.         else
  1573.             // no text
  1574.             lpstr=NULL;
  1575.         if(lpstr)
  1576.         {
  1577.             if(!fList)
  1578.             {
  1579.                 // only create if needed...
  1580.                 if (mmioCreateChunk(hmmioDst, &ckINFO, MMIO_CREATELIST))
  1581.                     goto riff_SI_Error;
  1582.                 fList=TRUE;
  1583.             }
  1584.     
  1585.             ck.ckid=mmioStringToFOURCC(aINFO[pI->index].pFOURCC,0);
  1586.             ck.cksize=lstrlen(lpstr)+1;
  1587.             ck.fccType=0;
  1588.             if (mmioCreateChunk(hmmioDst, &ck, 0))
  1589.                 goto riff_SI_Error;
  1590.  
  1591.             if (mmioWrite(hmmioDst, (LPBYTE)lpstr, ck.cksize) != (LONG)(ck.cksize))
  1592.                 goto riff_SI_Error;
  1593.  
  1594.             if (mmioAscend(hmmioDst, &ck, 0))
  1595.                 goto riff_SI_Error;
  1596.  
  1597.         }
  1598.         pI=pI->pnext;
  1599.     }
  1600.     
  1601.     if(fList)
  1602.     {
  1603.         if (mmioAscend(hmmioDst, &ckINFO, 0))
  1604.             goto riff_SI_Error;
  1605.     }
  1606.  
  1607.     return RIFFERR_NOERROR;
  1608.     
  1609. riff_SI_Error:    
  1610.     return lr;
  1611.     
  1612. }
  1613.  
  1614.  
  1615. ///////////////////////////////////////////////////////////////////////////////
  1616.  
  1617. LRESULT RIFFAPI riffReadDISP(HMMIO hmmio, LPMMCKINFO lpck, DISP FAR * FAR * lpnpDisp)
  1618. {
  1619.     LRESULT     lr;
  1620.     lr    = RIFFERR_ERROR;
  1621.    
  1622.     return lr;
  1623. }
  1624.  
  1625. LRESULT RIFFAPI riffFreeDISP(DISP FAR * FAR * lpnpDisp)
  1626. {
  1627.     LRESULT     lr;
  1628.     lr    = RIFFERR_ERROR;
  1629.     
  1630.     return lr;
  1631. }
  1632.  
  1633. LRESULT RIFFAPI riffWriteDISP(HMMIO hmmio, DISP FAR * FAR * lpnpDisp)
  1634. {
  1635.     LRESULT     lr;
  1636.     lr    = RIFFERR_ERROR;
  1637.     
  1638.     return lr;
  1639. }
  1640.  
  1641.  
  1642.  
  1643.  
  1644.  
  1645.  
  1646.  
  1647.  
  1648.  
  1649. //==========================================================================;
  1650. //==========================================================================;
  1651. //==========================================================================;
  1652. //==========================================================================;
  1653.  
  1654.  
  1655.  
  1656.  
  1657. BOOL        gfCancelConvert;
  1658.  
  1659.  
  1660. #define WM_CONVERT_BEGIN        (WM_USER + 100)
  1661. #define WM_CONVERT_END          (WM_USER + 101)
  1662.  
  1663. #define BeginConvert(hwnd, paacd)   PostMessage(hwnd, WM_CONVERT_BEGIN, 0, (LPARAM)(UINT)paacd)
  1664. #define EndConvert(hwnd, f, paacd)  PostMessage(hwnd, WM_CONVERT_END, (WPARAM)f, (LPARAM)(UINT)paacd)
  1665.  
  1666.  
  1667. //--------------------------------------------------------------------------;
  1668. //  
  1669. //  void AppDlgYield
  1670. //  
  1671. //  Description:
  1672. //  
  1673. //  
  1674. //  Arguments:
  1675. //      HWND hdlg:
  1676. //  
  1677. //  Return (void):
  1678. //  
  1679. //--------------------------------------------------------------------------;
  1680.  
  1681. void FNLOCAL AppDlgYield
  1682. (
  1683.     HWND            hdlg
  1684. )
  1685. {
  1686.     MSG     msg;
  1687.  
  1688.     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1689.     {
  1690.         if ((hdlg == NULL) || !IsDialogMessage(hdlg, &msg))
  1691.         {
  1692.             TranslateMessage(&msg);
  1693.             DispatchMessage(&msg);
  1694.         }
  1695.     }
  1696. } // AppDlgYield()
  1697.  
  1698.  
  1699. //--------------------------------------------------------------------------;
  1700. //  
  1701. //  BOOL AcmAppConvertEnd
  1702. //  
  1703. //  Description:
  1704. //  
  1705. //  
  1706. //  Arguments:
  1707. //      HWND hdlg:
  1708. //  
  1709. //      PAACONVERTDESC paacd:
  1710. //  
  1711. //  Return (BOOL):
  1712. //  
  1713. //  
  1714. //--------------------------------------------------------------------------;
  1715.  
  1716. BOOL FNLOCAL AcmAppConvertEnd
  1717. (
  1718.     HWND                hdlg,
  1719.     PAACONVERTDESC      paacd
  1720. )
  1721. {
  1722.     MMRESULT            mmr;
  1723.     LPACMSTREAMHEADER   pash;
  1724.  
  1725.  
  1726.     //
  1727.     //
  1728.     //
  1729.     //
  1730.     if (NULL != paacd->hmmioSrc)
  1731.     {
  1732.         mmioClose(paacd->hmmioSrc, 0);
  1733.         paacd->hmmioSrc = NULL;
  1734.     }
  1735.  
  1736.     if (NULL != paacd->hmmioDst)
  1737.     {
  1738.         mmioAscend(paacd->hmmioDst, &paacd->ckDst, 0);
  1739.         mmioAscend(paacd->hmmioDst, &paacd->ckDstRIFF, 0);
  1740.  
  1741.         mmioClose(paacd->hmmioDst, 0);
  1742.         paacd->hmmioDst = NULL;
  1743.     }
  1744.  
  1745.  
  1746.     //
  1747.     //
  1748.     //
  1749.     //
  1750.     if (NULL != paacd->has)
  1751.     {
  1752.         pash = &paacd->ash;
  1753.  
  1754.         if (ACMSTREAMHEADER_STATUSF_PREPARED & pash->fdwStatus)
  1755.         {
  1756.             pash->cbSrcLength = paacd->cbSrcReadSize;
  1757.             pash->cbDstLength = paacd->cbDstBufSize;
  1758.  
  1759.             mmr = acmStreamUnprepareHeader(paacd->has, &paacd->ash, 0L);
  1760.             if (MMSYSERR_NOERROR != mmr)
  1761.             {
  1762.                 AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  1763.                           TEXT("acmStreamUnprepareHeader() failed with error = %u!"), mmr);
  1764.             }
  1765.         }
  1766.  
  1767.         //
  1768.         //
  1769.         //
  1770.         acmStreamClose(paacd->has, 0L);
  1771.         paacd->has = NULL;
  1772.  
  1773.         if (NULL != paacd->had)
  1774.         {
  1775.             acmDriverClose(paacd->had, 0L);
  1776.             paacd->had = NULL;
  1777.         }
  1778.     }
  1779.  
  1780.  
  1781.     //
  1782.     //
  1783.     //
  1784.     //
  1785.     if (NULL != paacd->pbSrc)
  1786.     {
  1787.         GlobalFreePtr(paacd->pbSrc);
  1788.         paacd->pbSrc = NULL;
  1789.     }
  1790.     
  1791.     if (NULL != paacd->pbDst)
  1792.     {
  1793.         GlobalFreePtr(paacd->pbDst);
  1794.         paacd->pbDst = NULL;
  1795.     }
  1796.  
  1797.  
  1798.     return (TRUE);
  1799. } // AcmAppConvertEnd()
  1800.  
  1801.  
  1802. //--------------------------------------------------------------------------;
  1803. //  
  1804. //  BOOL AcmAppConvertBegin
  1805. //  
  1806. //  Description:
  1807. //  
  1808. //  
  1809. //  Arguments:
  1810. //      HWND hdlg:
  1811. //  
  1812. //      PAACONVERTDESC paacd:
  1813. //  
  1814. //  Return (BOOL):
  1815. //  
  1816. //  
  1817. //--------------------------------------------------------------------------;
  1818.  
  1819. BOOL FNLOCAL AcmAppConvertBegin
  1820. (
  1821.     HWND                    hdlg,
  1822.     PAACONVERTDESC          paacd
  1823. )
  1824. {
  1825.     TCHAR               ach[40];
  1826.     MMRESULT            mmr;
  1827.     MMCKINFO            ckSrcRIFF;
  1828.     MMCKINFO            ck;
  1829.     DWORD               dw;
  1830.     LPACMSTREAMHEADER   pash;
  1831.     LPWAVEFILTER        pwfltr;
  1832.  
  1833.  
  1834.     //
  1835.     //
  1836.     //
  1837.     if (NULL != paacd->hadid)
  1838.     {
  1839.         mmr = acmDriverOpen(&paacd->had, paacd->hadid, 0L);
  1840.         if (MMSYSERR_NOERROR != mmr)
  1841.         {
  1842.             AcmAppGetErrorString(mmr, ach);
  1843.             AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  1844.                         TEXT("The selected driver (hadid=%.04Xh) cannot be opened. %s (%u)"),
  1845.                         paacd->hadid, (LPSTR)ach, mmr);
  1846.             return (FALSE);
  1847.         }
  1848.     }
  1849.  
  1850.  
  1851.     //
  1852.     //
  1853.     //
  1854.     //
  1855.     pwfltr = paacd->fApplyFilter ? paacd->pwfltr : (LPWAVEFILTER)NULL;
  1856.  
  1857.     mmr = acmStreamOpen(&paacd->has,
  1858.                         paacd->had,
  1859.                         paacd->pwfxSrc,
  1860.                         paacd->pwfxDst,
  1861.                         pwfltr,
  1862.                         0L,
  1863.                         0L,
  1864.                         paacd->fdwOpen);
  1865.  
  1866.     if (MMSYSERR_NOERROR != mmr)
  1867.     {
  1868.         AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  1869.                   TEXT("acmStreamOpen() failed with error = %u!"), mmr);
  1870.  
  1871.         return (FALSE);
  1872.     }
  1873.  
  1874.  
  1875.     //
  1876.     //
  1877.     //
  1878.     mmr = acmStreamSize(paacd->has,
  1879.                         paacd->cbSrcReadSize,
  1880.                         &paacd->cbDstBufSize,
  1881.                         ACM_STREAMSIZEF_SOURCE);
  1882.  
  1883.     if (MMSYSERR_NOERROR != mmr)
  1884.     {
  1885.         AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  1886.                   TEXT("acmStreamSize() failed with error = %u!"), mmr);
  1887.  
  1888.         return (FALSE);
  1889.     }
  1890.  
  1891.  
  1892.  
  1893.     //
  1894.     //  first try to open the file, etc.. open the given file for reading
  1895.     //  using buffered I/O
  1896.     //
  1897.     paacd->hmmioSrc = mmioOpen(paacd->szFilePathSrc,
  1898.                                NULL,
  1899.                                MMIO_READ | MMIO_DENYWRITE | MMIO_ALLOCBUF);
  1900.     if (NULL == paacd->hmmioSrc)
  1901.         goto aacb_Error;
  1902.  
  1903.     //
  1904.     //
  1905.     //
  1906.     paacd->hmmioDst = mmioOpen(paacd->szFilePathDst,
  1907.                                NULL,
  1908.                                MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE | MMIO_ALLOCBUF);
  1909.     if (NULL == paacd->hmmioDst)
  1910.         goto aacb_Error;
  1911.  
  1912.  
  1913.  
  1914.     //
  1915.     //
  1916.     //
  1917.     //
  1918.     pash = &paacd->ash;
  1919.     pash->fdwStatus = 0L;
  1920.  
  1921.  
  1922.     //
  1923.     //  allocate the src and dst buffers for reading/converting data
  1924.     //
  1925.     paacd->pbSrc = (HPSTR)GlobalAllocPtr(GHND, paacd->cbSrcReadSize);
  1926.     if (NULL == paacd->pbSrc)
  1927.         goto aacb_Error;
  1928.     
  1929.     paacd->pbDst = (HPSTR)GlobalAllocPtr(GHND, paacd->cbDstBufSize);
  1930.     if (NULL == paacd->pbDst)
  1931.         goto aacb_Error;
  1932.  
  1933.  
  1934.     //
  1935.     //
  1936.     //
  1937.     //
  1938.     pash->cbStruct          = sizeof(*pash);
  1939.     pash->fdwStatus         = 0L;
  1940.     pash->dwUser            = 0L;
  1941.     pash->pbSrc             = paacd->pbSrc;
  1942.     pash->cbSrcLength       = paacd->cbSrcReadSize;
  1943.     pash->cbSrcLengthUsed   = 0L;
  1944.     pash->dwSrcUser         = paacd->cbSrcReadSize;
  1945.     pash->pbDst             = paacd->pbDst;
  1946.     pash->cbDstLength       = paacd->cbDstBufSize;
  1947.     pash->cbDstLengthUsed   = 0L;
  1948.     pash->dwDstUser         = paacd->cbDstBufSize;
  1949.  
  1950.     mmr = acmStreamPrepareHeader(paacd->has, pash, 0L);
  1951.     if (MMSYSERR_NOERROR != mmr)
  1952.     {
  1953.         AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  1954.                     TEXT("acmStreamPrepareHeader() failed with error = %u!"), mmr);
  1955.  
  1956.         goto aacb_Error;
  1957.     }                          
  1958.  
  1959.  
  1960.  
  1961.     //
  1962.     //  create the RIFF chunk of form type 'WAVE'
  1963.     //
  1964.     //
  1965.     paacd->ckDstRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  1966.     paacd->ckDstRIFF.cksize  = 0L;
  1967.     if (mmioCreateChunk(paacd->hmmioDst, &paacd->ckDstRIFF, MMIO_CREATERIFF))
  1968.         goto aacb_Error;
  1969.  
  1970.     //
  1971.     //  locate a 'WAVE' form type in a 'RIFF' thing...
  1972.     //
  1973.     ckSrcRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  1974.     if (mmioDescend(paacd->hmmioSrc, (LPMMCKINFO)&ckSrcRIFF, NULL, MMIO_FINDRIFF))
  1975.         goto aacb_Error;
  1976.  
  1977.     //
  1978.     //  we found a WAVE chunk--now go through and get all subchunks that
  1979.     //  we know how to deal with...
  1980.     //
  1981.     while (mmioDescend(paacd->hmmioSrc, &ck, &ckSrcRIFF, 0) == 0)
  1982.     {
  1983.         //
  1984.         //  quickly check for corrupt RIFF file--don't ascend past end!
  1985.         //
  1986.         if ((ck.dwDataOffset + ck.cksize) > (ckSrcRIFF.dwDataOffset + ckSrcRIFF.cksize))
  1987.             goto aacb_Error;
  1988.  
  1989.         switch (ck.ckid)
  1990.         {
  1991.             //
  1992.             //  explicitly skip these...
  1993.             //
  1994.             //
  1995.             //
  1996.             case mmioFOURCC('f', 'm', 't', ' '):
  1997.                 break;
  1998.  
  1999.             case mmioFOURCC('d', 'a', 't', 'a'):
  2000.                 break;
  2001.  
  2002.             case mmioFOURCC('f', 'a', 'c', 't'):
  2003.                 break;
  2004.  
  2005.             case mmioFOURCC('J', 'U', 'N', 'K'):
  2006.                 break;
  2007.  
  2008.             case mmioFOURCC('P', 'A', 'D', ' '):
  2009.                 break;
  2010.  
  2011.             case mmioFOURCC('c', 'u', 'e', ' '):
  2012.                 break;
  2013.  
  2014.  
  2015.             //
  2016.             //  copy chunks that are OK to copy
  2017.             //
  2018.             //
  2019.             //
  2020.             case mmioFOURCC('p', 'l', 's', 't'):
  2021.                 // although without the 'cue' chunk, it doesn't make much sense
  2022.                 riffCopyChunk(paacd->hmmioSrc, paacd->hmmioDst, &ck);
  2023.                 break;
  2024.  
  2025.             case mmioFOURCC('D', 'I', 'S', 'P'):
  2026.                 riffCopyChunk(paacd->hmmioSrc, paacd->hmmioDst, &ck);
  2027.                 break;
  2028.  
  2029.                 
  2030.             //
  2031.             //  don't copy unknown chunks
  2032.             //
  2033.             //
  2034.             //
  2035.             default:
  2036.                 break;
  2037.         }
  2038.  
  2039.         //
  2040.         //  step up to prepare for next chunk..
  2041.         //
  2042.         mmioAscend(paacd->hmmioSrc, &ck, 0);
  2043.     }
  2044.  
  2045. #if 0
  2046.     //
  2047.     //  now write out possibly editted chunks...
  2048.     //
  2049.     if (riffWriteINFO(paacd->hmmioDst, (glpwio->pInfo)))
  2050.     {
  2051.         goto aacb_Error;
  2052.     }
  2053. #endif
  2054.  
  2055.     //
  2056.     // go back to beginning of data portion of WAVE chunk
  2057.     //
  2058.     if (-1 == mmioSeek(paacd->hmmioSrc, ckSrcRIFF.dwDataOffset + sizeof(FOURCC), SEEK_SET))
  2059.         goto aacb_Error;
  2060.  
  2061.     ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
  2062.     mmioDescend(paacd->hmmioSrc, &ck, &ckSrcRIFF, MMIO_FINDCHUNK);
  2063.  
  2064.  
  2065.     //
  2066.     //  now create the destination fmt, fact, and data chunks _in that order_
  2067.     //
  2068.     //
  2069.     //
  2070.     //  hmmio is now descended into the 'RIFF' chunk--create the format chunk
  2071.     //  and write the format header into it
  2072.     //
  2073.     dw = SIZEOF_WAVEFORMATEX(paacd->pwfxDst);
  2074.  
  2075.     paacd->ckDst.ckid   = mmioFOURCC('f', 'm', 't', ' ');
  2076.     paacd->ckDst.cksize = dw;
  2077.     if (mmioCreateChunk(paacd->hmmioDst, &paacd->ckDst, 0))
  2078.         goto aacb_Error;
  2079.  
  2080.     if (mmioWrite(paacd->hmmioDst, (HPSTR)paacd->pwfxDst, dw) != (LONG)dw)
  2081.         goto aacb_Error;
  2082.  
  2083.     if (mmioAscend(paacd->hmmioDst, &paacd->ckDst, 0) != 0)
  2084.         goto aacb_Error;
  2085.  
  2086.     //
  2087.     //  create the 'fact' chunk (not necessary for PCM--but is nice to have)
  2088.     //  since we are not writing any data to this file (yet), we set the
  2089.     //  samples contained in the file to 0..
  2090.     //
  2091.     paacd->ckDst.ckid   = mmioFOURCC('f', 'a', 'c', 't');
  2092.     paacd->ckDst.cksize = 0L;
  2093.     if (mmioCreateChunk(paacd->hmmioDst, &paacd->ckDst, 0))
  2094.         goto aacb_Error;
  2095.  
  2096.     if (mmioWrite(paacd->hmmioDst, (HPSTR)&paacd->dwSrcSamples, sizeof(DWORD)) != sizeof(DWORD))
  2097.         goto aacb_Error;
  2098.  
  2099.     if (mmioAscend(paacd->hmmioDst, &paacd->ckDst, 0) != 0)
  2100.         goto aacb_Error;
  2101.  
  2102.  
  2103.     //
  2104.     //  create the data chunk AND STAY DESCENDED... for reasons that will
  2105.     //  become apparent later..
  2106.     //
  2107.     paacd->ckDst.ckid   = mmioFOURCC('d', 'a', 't', 'a');
  2108.     paacd->ckDst.cksize = 0L;
  2109.     if (mmioCreateChunk(paacd->hmmioDst, &paacd->ckDst, 0))
  2110.         goto aacb_Error;
  2111.  
  2112.     //
  2113.     //  at this point, BOTH the src and dst files are sitting at the very
  2114.     //  beginning of their data chunks--so we can READ from the source,
  2115.     //  CONVERT the data, then WRITE it to the destination file...
  2116.     //
  2117.     return (TRUE);
  2118.  
  2119.  
  2120.     //
  2121.     //
  2122.     //
  2123.     //
  2124. aacb_Error:
  2125.  
  2126.     AcmAppConvertEnd(hdlg, paacd);
  2127.  
  2128.     return (FALSE);
  2129. } // AcmAppConvertBegin()
  2130.  
  2131.  
  2132. //--------------------------------------------------------------------------;
  2133. //  
  2134. //  BOOL AcmAppConvertConvert
  2135. //  
  2136. //  Description:
  2137. //  
  2138. //  
  2139. //  Arguments:
  2140. //      HWND hdlg:
  2141. //  
  2142. //      PAACONVERTDESC paacd:
  2143. //  
  2144. //  Return (BOOL):
  2145. //  
  2146. //  
  2147. //--------------------------------------------------------------------------;
  2148.  
  2149. BOOL FNLOCAL AcmAppConvertConvert
  2150. (
  2151.     HWND                hdlg,
  2152.     PAACONVERTDESC     paacd
  2153. )
  2154. {
  2155.     MMRESULT            mmr;
  2156.     TCHAR               ach[40];
  2157.     DWORD               dw;
  2158.     WORD                w;
  2159.     DWORD               dwCurrent;
  2160.     WORD                wCurPercent;
  2161.     LPACMSTREAMHEADER   pash;
  2162.     DWORD               cbRead;
  2163.     DWORD               dwTime;
  2164.  
  2165.  
  2166.     wCurPercent = (WORD)-1;
  2167.  
  2168.     paacd->cTotalConverts    = 0L;
  2169.     paacd->dwTimeTotal       = 0L;
  2170.     paacd->dwTimeLongest     = 0L;
  2171.     if (0 == paacd->cbSrcData)
  2172.     {
  2173.         paacd->dwTimeShortest    = 0L;
  2174.         paacd->dwShortestConvert = 0L;
  2175.         paacd->dwLongestConvert  = 0L;
  2176.     }
  2177.     else
  2178.     {
  2179.         paacd->dwTimeShortest    = (DWORD)-1L;
  2180.         paacd->dwShortestConvert = (DWORD)-1L;
  2181.         paacd->dwLongestConvert  = (DWORD)-1L;
  2182.     }
  2183.  
  2184.     pash = &paacd->ash;
  2185.  
  2186.     for (dwCurrent = 0; dwCurrent < paacd->cbSrcData; )
  2187.     {
  2188.         w = (WORD)((dwCurrent * 100) / paacd->cbSrcData);
  2189.         if (w != wCurPercent)
  2190.         {
  2191.             wCurPercent = w;
  2192.             wsprintf(ach, TEXT("%u%%"), wCurPercent);
  2193.  
  2194.             if (hdlg)
  2195.                 SetDlgItemText(hdlg, IDD_AACONVERT_TXT_STATUS, ach);
  2196.         }
  2197.  
  2198.         AppDlgYield(hdlg);
  2199.  
  2200.         if (gfCancelConvert)
  2201.             goto aacc_Error;
  2202.  
  2203.         //
  2204.         //
  2205.         //
  2206.         cbRead = min(paacd->cbSrcReadSize, paacd->cbSrcData - dwCurrent);
  2207.         dw = mmioRead(paacd->hmmioSrc, paacd->pbSrc, cbRead);
  2208.         if (0L == dw)
  2209.             break;
  2210.  
  2211.  
  2212.         AppDlgYield(hdlg);
  2213.         if (gfCancelConvert)
  2214.             goto aacc_Error;
  2215.  
  2216.              
  2217.  
  2218.         //
  2219.         //
  2220.         //
  2221.         pash->cbSrcLength     = dw;
  2222.         pash->cbDstLengthUsed = 0L;
  2223.  
  2224.  
  2225.  
  2226.         dwTime = timeGetTime();
  2227.  
  2228.         mmr = acmStreamConvert(paacd->has,
  2229.                                &paacd->ash,
  2230.                                ACM_STREAMCONVERTF_BLOCKALIGN);
  2231.  
  2232.         if (MMSYSERR_NOERROR != mmr)
  2233.         {
  2234.             AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  2235.                       TEXT("acmStreamConvert() failed with error = %u!"), mmr);
  2236.             goto aacc_Error;
  2237.         }
  2238.  
  2239.         while (0 == (ACMSTREAMHEADER_STATUSF_DONE & ((AACONVERTDESC volatile *)paacd)->ash.fdwStatus))
  2240.             ;
  2241.  
  2242.         dwTime = timeGetTime() - dwTime;
  2243.  
  2244.  
  2245.         paacd->dwTimeTotal += dwTime;
  2246.  
  2247.         if (dwTime < paacd->dwTimeShortest)
  2248.         {
  2249.             paacd->dwTimeShortest    = dwTime;
  2250.             paacd->dwShortestConvert = paacd->cTotalConverts;
  2251.         }
  2252.  
  2253.         if (dwTime > paacd->dwTimeLongest)
  2254.         {
  2255.             paacd->dwTimeLongest     = dwTime;
  2256.             paacd->dwLongestConvert  = paacd->cTotalConverts;
  2257.         }
  2258.  
  2259.         paacd->cTotalConverts++;
  2260.  
  2261.  
  2262.         AppDlgYield(hdlg);
  2263.         if (gfCancelConvert)
  2264.             goto aacc_Error;
  2265.  
  2266.  
  2267.         //
  2268.         //
  2269.         //
  2270.         dw = (cbRead - pash->cbSrcLengthUsed);
  2271.         if (0L != dw)
  2272.         {
  2273.             mmioSeek(paacd->hmmioSrc, -(LONG)dw, SEEK_CUR);
  2274.         }
  2275.  
  2276.         dwCurrent += pash->cbSrcLengthUsed;
  2277.  
  2278.  
  2279.         //
  2280.         //
  2281.         //
  2282.         dw = pash->cbDstLengthUsed;
  2283.         if (0L == dw)
  2284.             break;
  2285.           
  2286.         if (mmioWrite(paacd->hmmioDst, paacd->pbDst, dw) != (LONG)dw)
  2287.             goto aacc_Error;
  2288.     }
  2289.  
  2290.  
  2291.     //
  2292.     //
  2293.     //
  2294.     //
  2295.     //
  2296.     //
  2297.     wCurPercent = (WORD)-1;
  2298.  
  2299.     for (;paacd->cbSrcData;)
  2300.     {
  2301.         w = (WORD)((dwCurrent * 100) / paacd->cbSrcData);
  2302.         if (w != wCurPercent)
  2303.         {
  2304.             wCurPercent = w;
  2305.             wsprintf(ach, TEXT("Cleanup Pass -- %u%%"), wCurPercent);
  2306.  
  2307.             if (hdlg)
  2308.                 SetDlgItemText(hdlg, IDD_AACONVERT_TXT_STATUS, ach);
  2309.         }
  2310.  
  2311.         AppDlgYield(hdlg);
  2312.         if (gfCancelConvert)
  2313.             goto aacc_Error;
  2314.  
  2315.  
  2316.         //
  2317.         //
  2318.         //
  2319.         dw = 0L;
  2320.         cbRead = min(paacd->cbSrcReadSize, paacd->cbSrcData - dwCurrent);
  2321.         if (0L != cbRead)
  2322.         {
  2323.             dw = mmioRead(paacd->hmmioSrc, paacd->pbSrc, cbRead);
  2324.             if (0L == dw)
  2325.                 break;
  2326.         }
  2327.  
  2328.  
  2329.         AppDlgYield(hdlg);
  2330.         if (gfCancelConvert)
  2331.             goto aacc_Error;
  2332.  
  2333.              
  2334.  
  2335.         //
  2336.         //
  2337.         //
  2338.         pash->cbSrcLength     = dw;
  2339.         pash->cbDstLengthUsed = 0L;
  2340.  
  2341.  
  2342.  
  2343.         dwTime = timeGetTime();
  2344.  
  2345.         mmr = acmStreamConvert(paacd->has,
  2346.                                &paacd->ash,
  2347.                                ACM_STREAMCONVERTF_BLOCKALIGN |
  2348.                                ACM_STREAMCONVERTF_END);
  2349.  
  2350.         if (MMSYSERR_NOERROR != mmr)
  2351.         {
  2352.             AppMsgBox(hdlg, MB_OK | MB_ICONEXCLAMATION,
  2353.                       TEXT("acmStreamConvert() failed with error = %u!"), mmr);
  2354.             goto aacc_Error;
  2355.         }
  2356.  
  2357.         while (0 == (ACMSTREAMHEADER_STATUSF_DONE & ((AACONVERTDESC volatile *)paacd)->ash.fdwStatus))
  2358.             ;
  2359.  
  2360.         dwTime = timeGetTime() - dwTime;
  2361.  
  2362.  
  2363.         paacd->dwTimeTotal += dwTime;
  2364.  
  2365.         if (dwTime < paacd->dwTimeShortest)
  2366.         {
  2367.             paacd->dwTimeShortest    = dwTime;
  2368.             paacd->dwShortestConvert = paacd->cTotalConverts;
  2369.         }
  2370.  
  2371.         if (dwTime > paacd->dwTimeLongest)
  2372.         {
  2373.             paacd->dwTimeLongest     = dwTime;
  2374.             paacd->dwLongestConvert  = paacd->cTotalConverts;
  2375.         }
  2376.  
  2377.         paacd->cTotalConverts++;
  2378.  
  2379.  
  2380.         AppDlgYield(hdlg);
  2381.         if (gfCancelConvert)
  2382.             goto aacc_Error;
  2383.  
  2384.         //
  2385.         //
  2386.         //
  2387.         dw = pash->cbDstLengthUsed;
  2388.         if (0L == dw)
  2389.         {
  2390.             pash->cbDstLengthUsed = 0L;
  2391.  
  2392.             //
  2393.             //  BUGBUG BOBSTER
  2394.             //  What if the last conversion ate up some of the source bytes?
  2395.             //  It's possible - the codec could cache some of the data
  2396.             //  without actually converting it, right?  The pbSrc pointer
  2397.             //  might have to be incremented, and cbSrcLength might have to
  2398.             //  to be decreased by cbSrcLengthUsed.  This probably wouldn't
  2399.             //  happen with most of our codecs though...?
  2400.             //
  2401.             mmr = acmStreamConvert(paacd->has,
  2402.                                    &paacd->ash,
  2403.                                    ACM_STREAMCONVERTF_END);
  2404.  
  2405.             if (MMSYSERR_NOERROR == mmr)
  2406.             {
  2407.                 while (0 == (ACMSTREAMHEADER_STATUSF_DONE & ((AACONVERTDESC volatile *)paacd)->ash.fdwStatus))
  2408.                     ;
  2409.             }
  2410.  
  2411.             dw = pash->cbDstLengthUsed;
  2412.             if (0L == dw)
  2413.                 break;
  2414.         }
  2415.           
  2416.         if (mmioWrite(paacd->hmmioDst, paacd->pbDst, dw) != (LONG)dw)
  2417.             goto aacc_Error;
  2418.  
  2419.         //
  2420.         //
  2421.         //
  2422.         dw = (cbRead - pash->cbSrcLengthUsed);
  2423.         if (0L != dw)
  2424.         {
  2425.             mmioSeek(paacd->hmmioSrc, -(LONG)dw, SEEK_CUR);
  2426.         }
  2427.  
  2428.         dwCurrent += pash->cbSrcLengthUsed;
  2429.  
  2430.         if (0L == pash->cbDstLengthUsed)
  2431.             break;
  2432.     }
  2433.  
  2434.     if (hdlg)
  2435.         EndConvert(hdlg, !gfCancelConvert, paacd);
  2436.  
  2437.     return (!gfCancelConvert);
  2438.  
  2439.  
  2440. aacc_Error:
  2441.  
  2442.     if (hdlg)
  2443.         EndConvert(hdlg, FALSE, paacd);
  2444.     return (FALSE);
  2445. } // AcmAppConvertConvert()
  2446.  
  2447.  
  2448. //--------------------------------------------------------------------------;
  2449. //  
  2450. //  BOOL AcmAppConvertDlgProc
  2451. //  
  2452. //  Description:
  2453. //  
  2454. //  
  2455. //  Arguments:
  2456. //      HWND hdlg:
  2457. //  
  2458. //      UINT uMsg:
  2459. //  
  2460. //      WPARAM wParam:
  2461. //  
  2462. //      LPARAM lParam:
  2463. //  
  2464. //  Return (BOOL):
  2465. //  
  2466. //  
  2467. //--------------------------------------------------------------------------;
  2468.  
  2469. BOOL FNEXPORT AcmAppConvertDlgProc
  2470. (
  2471.     HWND                    hwnd,
  2472.     UINT                    uMsg,
  2473.     WPARAM                  wParam,
  2474.     LPARAM                  lParam
  2475. )
  2476. {
  2477.     PAACONVERTDESC      paacd;
  2478.     UINT                uId;
  2479.  
  2480.     paacd = (PAACONVERTDESC)(UINT)GetWindowLong(hwnd, DWL_USER);
  2481.  
  2482.     switch (uMsg)
  2483.     {
  2484.         case WM_INITDIALOG:
  2485.             paacd = (PAACONVERTDESC)(UINT)lParam;
  2486.  
  2487.             SetWindowLong(hwnd, DWL_USER, lParam);
  2488.  
  2489.             SetWindowFont(GetDlgItem(hwnd, IDD_AACONVERT_TXT_INFILEPATH), ghfontApp, FALSE);
  2490.             SetWindowFont(GetDlgItem(hwnd, IDD_AACONVERT_TXT_OUTFILEPATH), ghfontApp, FALSE);
  2491.             SetWindowFont(GetDlgItem(hwnd, IDD_AACONVERT_TXT_STATUS), ghfontApp, FALSE);
  2492.  
  2493.             SetDlgItemText(hwnd, IDD_AACONVERT_TXT_INFILEPATH, paacd->szFilePathSrc);
  2494.             SetDlgItemText(hwnd, IDD_AACONVERT_TXT_OUTFILEPATH, paacd->szFilePathDst);
  2495.  
  2496.             BeginConvert(hwnd, paacd);
  2497.             return (TRUE);
  2498.  
  2499.  
  2500.         case WM_CONVERT_BEGIN:
  2501.             gfCancelConvert = FALSE;
  2502.             if (AcmAppConvertBegin(hwnd, paacd))
  2503.             {
  2504.                 AcmAppConvertConvert(hwnd, paacd);
  2505.             }
  2506.             else
  2507.             {
  2508.                 EndConvert(hwnd, FALSE, paacd);
  2509.             }
  2510.             break;
  2511.  
  2512.  
  2513.         case WM_CONVERT_END:
  2514.             AcmAppConvertEnd(hwnd, paacd);
  2515.             EndDialog(hwnd, !gfCancelConvert);
  2516.             break;
  2517.  
  2518.  
  2519.         case WM_COMMAND:
  2520.             uId = GET_WM_COMMAND_ID(wParam, lParam);
  2521.             if (IDCANCEL == uId)
  2522.             {
  2523.                 gfCancelConvert = TRUE;
  2524.             }
  2525.             break;
  2526.     }
  2527.  
  2528.     return (FALSE);
  2529. } // AcmAppConvertDlgProc()
  2530.  
  2531.  
  2532. //--------------------------------------------------------------------------;
  2533. //  
  2534. //  BOOL AcmAppMultiThreadConvert
  2535. //  
  2536. //  Description:
  2537. //  
  2538. //  
  2539. //  Arguments:
  2540. //      HWND hdlg:
  2541. //  
  2542. //      UINT uMsg:
  2543. //  
  2544. //      WPARAM wParam:
  2545. //  
  2546. //      LPARAM lParam:
  2547. //  
  2548. //  Return (BOOL):
  2549. //  
  2550. //  
  2551. //--------------------------------------------------------------------------;
  2552.  
  2553. LONG AcmAppMultiThreadConvert
  2554. (
  2555.     PAACONVERTDESC      paacd
  2556. )
  2557. {
  2558.     if (AcmAppConvertBegin(NULL, paacd))
  2559.     {
  2560.         AcmAppConvertConvert(NULL, paacd);
  2561.     }
  2562.  
  2563.     AcmAppConvertEnd(NULL, paacd);
  2564.  
  2565.     AcmAppOpenInstance(NULL, paacd->szFilePathDst, FALSE);
  2566.  
  2567.     //
  2568.     //  clean up...
  2569.     //
  2570.     if (NULL != paacd->pwfxDst)
  2571.     {
  2572.         GlobalFreePtr(paacd->pwfxDst);
  2573.         paacd->pwfxDst = NULL;
  2574.     }
  2575.  
  2576.     if (NULL != paacd->pwfltr)
  2577.     {
  2578.         GlobalFreePtr(paacd->pwfltr);
  2579.         paacd->pwfltr = NULL;
  2580.     }
  2581.  
  2582.     paacd->pwfxSrc = NULL;
  2583.  
  2584.     LocalFree((HLOCAL)paacd);
  2585.  
  2586.     return (TRUE);
  2587.  
  2588. } // AcmAppMultiThreadConvert()
  2589.  
  2590.  
  2591.  
  2592. //==========================================================================;
  2593. //
  2594. //
  2595. //
  2596. //
  2597. //==========================================================================;
  2598.  
  2599. //--------------------------------------------------------------------------;
  2600. //  
  2601. //  BOOL AcmAppFileConvert
  2602. //  
  2603. //  Description:
  2604. //  
  2605. //  
  2606. //  Arguments:
  2607. //      HWND hwnd:
  2608. //  
  2609. //      PACMAPPFILEDESC paafd:
  2610. //  
  2611. //  Return (BOOL):
  2612. //  
  2613. //--------------------------------------------------------------------------;
  2614.  
  2615. BOOL FNGLOBAL AcmAppFileConvert
  2616. (
  2617.     HWND                    hwnd,
  2618.     PACMAPPFILEDESC         paafd
  2619. )
  2620. {
  2621.     BOOL                f;
  2622.     DWORD               nAvgBytesPerSec;
  2623.     DWORD               nBlockAlign;
  2624.     DWORD               dwTimeAverage;
  2625.     PAACONVERTDESC      paacd;
  2626.  
  2627.     paacd = (PAACONVERTDESC)LocalAlloc(LPTR, sizeof(*paacd));
  2628.     if (NULL == paacd)
  2629.     {
  2630.         return (FALSE);
  2631.     }
  2632.  
  2633.  
  2634.     //
  2635.     //
  2636.     //
  2637.     paacd->hmmioSrc      = NULL;
  2638.     paacd->hmmioDst      = NULL;
  2639.  
  2640.     //
  2641.     //  default to 1 second per convert buffer..
  2642.     //
  2643.     paacd->uBufferTimePerConvert = 1000;
  2644.  
  2645.     paacd->dwSrcSamples  = paafd->dwDataSamples;
  2646.  
  2647.  
  2648.     //
  2649.     //  compute source bytes to read (round down to nearest block for
  2650.     //  one second of data)
  2651.     //
  2652.     nAvgBytesPerSec     = paafd->pwfx->nAvgBytesPerSec;
  2653.     nBlockAlign         = paafd->pwfx->nBlockAlign;
  2654.     paacd->cbSrcReadSize = nAvgBytesPerSec - (nAvgBytesPerSec % nBlockAlign);
  2655.  
  2656.     paacd->cbDstBufSize  = 0L;
  2657.     paacd->fdwOpen       = 0L;
  2658.  
  2659.     lstrcpy(paacd->szFilePathSrc, paafd->szFilePath);
  2660.     paacd->pwfxSrc       = paafd->pwfx;
  2661.     paacd->pbSrc         = NULL;
  2662.  
  2663.     paacd->cbSrcData     = paafd->dwDataBytes;
  2664.  
  2665.     lstrcpy(paacd->szFilePathDst, gszLastSaveFile);
  2666.     paacd->pwfxDst       = NULL;
  2667.     paacd->pbDst         = NULL;
  2668.  
  2669.     paacd->fApplyFilter  = FALSE;
  2670.     paacd->pwfltr        = NULL;
  2671.  
  2672.  
  2673.     paacd->cTotalConverts     = 0L;
  2674.     paacd->dwTimeTotal        = 0L;
  2675.     paacd->dwTimeShortest     = (DWORD)-1L;
  2676.     paacd->dwShortestConvert  = (DWORD)-1L;
  2677.     paacd->dwTimeLongest      = 0L;
  2678.     paacd->dwLongestConvert   = (DWORD)-1L;
  2679.  
  2680.     //
  2681.     //
  2682.     //
  2683.     f = DialogBoxParam(ghinst,
  2684.                        DLG_AACHOOSER,
  2685.                        hwnd,
  2686.                        AcmAppDlgProcChooser,
  2687.                        (LPARAM)(UINT)paacd);
  2688.     if (f)
  2689.     {
  2690.         lstrcpy(gszLastSaveFile, paacd->szFilePathDst);
  2691.  
  2692.         //
  2693.         //
  2694.         //
  2695.         f = DialogBoxParam(ghinst,
  2696.                             DLG_AACONVERT,
  2697.                             hwnd,
  2698.                             AcmAppConvertDlgProc,
  2699.                             (LPARAM)(UINT)paacd);
  2700.         if (!f)
  2701.         {
  2702.             AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  2703.                         TEXT("Conversion aborted--destination file is corrupt!"));
  2704.         }
  2705.  
  2706.  
  2707.         if (paacd->cTotalConverts > 1)
  2708.         {
  2709.             dwTimeAverage  = paacd->dwTimeTotal;
  2710.             dwTimeAverage -= paacd->dwTimeShortest;
  2711.  
  2712.             dwTimeAverage /= (paacd->cTotalConverts - 1);
  2713.         }
  2714.         else
  2715.         {
  2716.             dwTimeAverage = paacd->dwTimeTotal;
  2717.         }
  2718.  
  2719.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  2720.                     TEXT("Conversion Statistics:\n\nTotal Time:\t%lu ms\nTotal Converts:\t%lu\nShortest Time:\t%lu ms (on %lu)\nLongest Time:\t%lu ms (on %lu)\n\nAverage Time:\t%lu ms"),
  2721.                     paacd->dwTimeTotal,
  2722.                     paacd->cTotalConverts,
  2723.                     paacd->dwTimeShortest,
  2724.                     paacd->dwShortestConvert,
  2725.                     paacd->dwTimeLongest,
  2726.                     paacd->dwLongestConvert,
  2727.                     dwTimeAverage);
  2728.  
  2729.         if (f)
  2730.         {
  2731.             AcmAppOpenInstance(hwnd, paacd->szFilePathDst, FALSE);
  2732.         }
  2733.     }
  2734.  
  2735.  
  2736.     //
  2737.     //
  2738.     //
  2739.     if (NULL != paacd->pwfxDst)
  2740.     {
  2741.         GlobalFreePtr(paacd->pwfxDst);
  2742.         paacd->pwfxDst = NULL;
  2743.     }
  2744.  
  2745.     if (NULL != paacd->pwfltr)
  2746.     {
  2747.         GlobalFreePtr(paacd->pwfltr);
  2748.         paacd->pwfltr = NULL;
  2749.     }
  2750.  
  2751.     paacd->pwfxSrc = NULL;
  2752.  
  2753.  
  2754.     LocalFree((HLOCAL)paacd);
  2755.  
  2756.     return (f);
  2757. } // AcmAppFileConvert()
  2758.  
  2759.  
  2760. //--------------------------------------------------------------------------;
  2761. //  
  2762. //  BOOL AcmAppMultiThreadedCallback
  2763. //  
  2764. //  Description:
  2765. //  
  2766. //  
  2767. //  Arguments:
  2768. //      HACMDRIVERID hadid:
  2769. //  
  2770. //      DWORD dwInstance:
  2771. //  
  2772. //      DWORD fdwSupport:
  2773. //  
  2774. //  Return (BOOL):
  2775. //  
  2776. //  
  2777. //--------------------------------------------------------------------------;
  2778.  
  2779. BOOL FNEXPORT AcmAppMultiThreadedCallback
  2780. (
  2781.     HACMDRIVERID        hadid,
  2782.     LPACMFORMATDETAILS  pafd,
  2783.     DWORD               dwInstance,
  2784.     DWORD               fdwSupport
  2785. )
  2786. {
  2787.     DWORD               nAvgBytesPerSec;
  2788.     DWORD               nBlockAlign;
  2789.     PAACONVERTDESC      paacd;
  2790.     PACMAPPFILEDESC     paafd;
  2791. #ifdef WIN32
  2792.     int                 i = -1;
  2793.     ACMFORMATTAGDETAILS aftd;
  2794.     MMRESULT            mmr;
  2795.     HANDLE              hThrd;
  2796.     LONG                lThreadId;
  2797. #endif
  2798.  
  2799.     //
  2800.     // I have sent myself (PACMAPPFILEDESC)paafd for the source
  2801.     // file.  I need to copy the relevent information from this structure
  2802.     // into a (PAACONVERTDESC)paacd and send it off to the thread created
  2803.     // below.
  2804.     //
  2805.     paafd = (PACMAPPFILEDESC)dwInstance;
  2806.  
  2807.     paacd = (PAACONVERTDESC)LocalAlloc(LPTR, sizeof(*paacd));
  2808.     if (NULL == paacd)
  2809.     {
  2810.         return (FALSE);
  2811.     }
  2812.  
  2813.     //
  2814.     //
  2815.     //
  2816.     paacd->hmmioSrc      = NULL;
  2817.     paacd->hmmioDst      = NULL;
  2818.  
  2819.     //
  2820.     //  default to 1 second per convert buffer..
  2821.     //
  2822.     paacd->uBufferTimePerConvert = 1000;
  2823.  
  2824.     paacd->dwSrcSamples  = paafd->dwDataSamples;
  2825.  
  2826.  
  2827.     //
  2828.     //  compute source bytes to read (round down to nearest block for
  2829.     //  one second of data)
  2830.     //
  2831.     nAvgBytesPerSec     = paafd->pwfx->nAvgBytesPerSec;
  2832.     nBlockAlign         = paafd->pwfx->nBlockAlign;
  2833.     paacd->cbSrcReadSize = nAvgBytesPerSec - (nAvgBytesPerSec % nBlockAlign);
  2834.  
  2835.     paacd->cbDstBufSize  = 0L;
  2836.     paacd->fdwOpen       = ACM_STREAMOPENF_NONREALTIME;
  2837.  
  2838.     lstrcpy(paacd->szFilePathSrc, paafd->szFilePath);
  2839.     paacd->pwfxSrc       = paafd->pwfx;
  2840.     paacd->pbSrc         = NULL;
  2841.  
  2842.     paacd->cbSrcData     = paafd->dwDataBytes;
  2843.  
  2844.  
  2845.      
  2846.     paacd->pwfxDst = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, SIZEOF_WAVEFORMATEX(pafd->pwfx));
  2847.     if (NULL == paacd->pwfxDst)
  2848.     {
  2849.         return (FALSE);
  2850.     }
  2851.     _fmemcpy(paacd->pwfxDst,pafd->pwfx,SIZEOF_WAVEFORMATEX(pafd->pwfx));
  2852.     paacd->pbDst         = NULL;
  2853.  
  2854.     paacd->fApplyFilter  = FALSE;
  2855.     paacd->pwfltr        = NULL;
  2856.  
  2857.  
  2858.     paacd->cTotalConverts     = 0L;
  2859.     paacd->dwTimeTotal        = 0L;
  2860.     paacd->dwTimeShortest     = (DWORD)-1L;
  2861.     paacd->dwShortestConvert  = (DWORD)-1L;
  2862.     paacd->dwTimeLongest      = 0L;
  2863.     paacd->dwLongestConvert   = (DWORD)-1L;
  2864.  
  2865.  
  2866.     //
  2867.     //  Under Win32 I can spawn a thread for each conversion.
  2868.     //  Under Win16 I have to wait for each of the conversions to complete.
  2869.     //
  2870. #ifdef WIN32
  2871.     //
  2872.     // Remove file extension and add extra info
  2873.     //
  2874.     lstrcpy(paacd->szFilePathDst, paafd->szFilePath);
  2875.  
  2876.     while ((paacd->szFilePathDst[++i] != '.') &&
  2877.            (paacd->szFilePathDst[i]   != '('));
  2878.     paacd->szFilePathDst[i] = '\0';
  2879.  
  2880.     //
  2881.     //  initialize all unused members of the ACMFORMATTAGDETAILS
  2882.     //  structure to zero
  2883.     //
  2884.     memset(&aftd, 0, sizeof(aftd));
  2885.  
  2886.     //
  2887.     //  fill in the required members of the ACMFORMATTAGDETAILS
  2888.     //  structure for the ACM_FORMATTAGDETAILSF_FORMATTAG query
  2889.     //
  2890.     aftd.cbStruct    = sizeof(aftd);
  2891.     aftd.dwFormatTag = pafd->pwfx->wFormatTag;
  2892.  
  2893.     mmr = acmFormatTagDetails(NULL,
  2894.                               &aftd,
  2895.                               ACM_FORMATTAGDETAILSF_FORMATTAG);
  2896.     if (MMSYSERR_NOERROR != mmr)
  2897.     {
  2898.         AppMsgBox(NULL, MB_OK | MB_ICONEXCLAMATION,
  2899.                     TEXT("Conversion aborted--could not construct filename"));
  2900.     }
  2901.  
  2902.     //
  2903.     //  Construct a long filename based on the format type
  2904.     //
  2905.     wsprintf(paacd->szFilePathDst, "%s(%s %s).wav",
  2906.                 (LPCTSTR)paacd->szFilePathDst,
  2907.                 (LPCTSTR)aftd.szFormatTag,
  2908.                 (LPCTSTR)pafd->szFormat);
  2909.  
  2910.     hThrd = CreateThread(NULL, 0,
  2911.                          (LPTHREAD_START_ROUTINE)AcmAppMultiThreadConvert,
  2912.                          (LPVOID)paacd,
  2913.                          0,
  2914.                          (LPDWORD)&lThreadId );
  2915.  
  2916.     if (!hThrd)
  2917.     {
  2918.         AppMsgBox(NULL, MB_OK | MB_ICONEXCLAMATION,
  2919.                     TEXT("Conversion aborted--failure doing conversion"));
  2920.     }
  2921.  
  2922.     //
  2923.     //  Since I don't use this handle anywhere, I will close it
  2924.     //
  2925.     CloseHandle(hThrd);
  2926. #else
  2927.     //
  2928.     //  Don't want to make too much trouble for the Win16 version.
  2929.     //
  2930.     wsprintf(paacd->szFilePathDst, "%d%c%d%d.wav",
  2931.                 pafd->pwfx->wFormatTag,
  2932.                 (2 == pafd->pwfx->nChannels) ? 's' : 'm',
  2933.                 (UINT)(pafd->pwfx->nAvgBytesPerSec * 8 /
  2934.                  pafd->pwfx->nSamplesPerSec /
  2935.                  pafd->pwfx->nChannels),
  2936.                  pafd->pwfx->nSamplesPerSec/1000);
  2937.  
  2938.     AcmAppMultiThreadConvert(paacd);
  2939. #endif
  2940.  
  2941.     //
  2942.     //  return TRUE to continue with enumeration
  2943.     //
  2944.     return (TRUE);
  2945. } // AcmAppMultiThreadedCallback()
  2946.  
  2947.  
  2948. //--------------------------------------------------------------------------;
  2949. //  
  2950. //  BOOL AcmAppMultiThreadedConvertAll
  2951. //  
  2952. //  Description:
  2953. //  
  2954. //  
  2955. //  Arguments:
  2956. //      HWND hwnd:
  2957. //  
  2958. //      PACMAPPFILEDESC paafd:
  2959. //  
  2960. //  Return (BOOL):
  2961. //  
  2962. //--------------------------------------------------------------------------;
  2963.  
  2964. BOOL FNGLOBAL AcmAppMultiThreadedConvertAll
  2965. (
  2966.     HWND                    hwnd,
  2967.     PACMAPPFILEDESC         paafd
  2968. )
  2969. {
  2970.     MMRESULT            mmr;
  2971.     ACMFORMATDETAILS    afd;
  2972.     DWORD               cbwfx;
  2973.  
  2974.  
  2975.     //
  2976.     //  Call acmFormatEnum to enumerated all formats that the source format
  2977.     //  can convert to.
  2978.     //
  2979.     //  Use the wave format for the enumeration
  2980.     //
  2981.  
  2982.     mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfx);
  2983.     if (MMSYSERR_NOERROR != mmr)
  2984.     {
  2985.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  2986.                   TEXT("AcmAppMultiThreadedConvertAll() acmMetrics failed mmr=%u!"), mmr);
  2987.         return (FALSE);
  2988.     }
  2989.  
  2990.     memset(&afd, 0, sizeof(afd));
  2991.     afd.cbStruct    = sizeof(afd);
  2992.     afd.dwFormatTag = WAVE_FORMAT_UNKNOWN;
  2993.  
  2994.     afd.pwfx = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, (UINT)cbwfx);
  2995.     if (NULL == afd.pwfx)
  2996.     {
  2997.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  2998.                   TEXT("AcmAppMultiThreadedConvertAll() LocalAlloc failed!"));
  2999.         return (FALSE);
  3000.     }
  3001.  
  3002.     _fmemcpy(afd.pwfx, paafd->pwfx, SIZEOF_WAVEFORMATEX(paafd->pwfx));
  3003.     afd.cbwfx = cbwfx;
  3004.  
  3005.  
  3006.     mmr = acmFormatEnum(NULL, &afd, AcmAppMultiThreadedCallback, (DWORD)(LPVOID)paafd,
  3007.             ACM_FORMATENUMF_CONVERT);
  3008.     if (MMSYSERR_NOERROR != mmr)
  3009.     {
  3010.         AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  3011.                   TEXT("AcmAppMultiThreadedConvertAll() acmFormatEnum failed mmr=%u!"), mmr);
  3012.         return (FALSE);
  3013.     }
  3014.  
  3015.     GlobalFreePtr(afd.pwfx);
  3016.  
  3017.     return TRUE;
  3018.  
  3019. } // AcmAppMultiThreadedConvertAll()
  3020.  
  3021.  
  3022.