AAFILE.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:77k
源码类别:

Windows编程

开发平台:

Visual C++

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