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

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  acmapp.c
  13. //
  14. //  Description:
  15. //      This is a sample application that demonstrates how to use the 
  16. //      Audio Compression Manager API's in Windows. This application is
  17. //      also useful as an ACM driver test.
  18. //
  19. //==========================================================================;
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #include <mmsystem.h>
  24. #include <commdlg.h>
  25. #include <shellapi.h>
  26. #include <stdarg.h>
  27. #include <memory.h>
  28. #include <mmreg.h>
  29. #include <msacm.h>
  30.  
  31. #include "appport.h"
  32. #include "acmapp.h"
  33.  
  34. #include "debug.h"
  35.  
  36.  
  37. //
  38. //  globals, no less
  39. //
  40. HINSTANCE       ghinst;
  41. BOOL            gfAcmAvailable;
  42. UINT            gfuAppOptions       = APP_OPTIONSF_AUTOOPEN;
  43. HFONT           ghfontApp;
  44. HACMDRIVERID    ghadidNotify;
  45.  
  46. UINT            guWaveInId          = (UINT)WAVE_MAPPER;
  47. UINT            guWaveOutId         = (UINT)WAVE_MAPPER;
  48.  
  49. TCHAR           gszNull[]           = TEXT("");
  50. TCHAR           gszAppProfile[]     = TEXT("acmapp.ini");
  51. TCHAR           gszYes[]            = TEXT("Yes");
  52. TCHAR           gszNo[]             = TEXT("No");
  53.  
  54. TCHAR           gszAppName[APP_MAX_APP_NAME_CHARS];
  55. TCHAR           gszFileUntitled[APP_MAX_FILE_TITLE_CHARS];
  56.  
  57. TCHAR           gszInitialDirOpen[APP_MAX_FILE_PATH_CHARS];
  58. TCHAR           gszInitialDirSave[APP_MAX_FILE_PATH_CHARS];
  59.  
  60. TCHAR           gszLastSaveFile[APP_MAX_FILE_PATH_CHARS];
  61.  
  62. ACMAPPFILEDESC  gaafd;
  63.  
  64.  
  65. //==========================================================================;
  66. //
  67. //  Application helper functions
  68. //
  69. //
  70. //==========================================================================;
  71.  
  72. //--------------------------------------------------------------------------;
  73. //
  74. //  int AppMsgBox
  75. //
  76. //  Description:
  77. //      This function displays a message for the application in a standard
  78. //      message box.
  79. //
  80. //      Note that this function takes any valid argument list that can
  81. //      be passed to wsprintf. Because of this, the application must
  82. //      remember to cast near string pointers to FAR when built for Win 16.
  83. //      You will get a nice GP fault if you do not cast them correctly.
  84. //
  85. //  Arguments:
  86. //      HWND hwnd: Handle to parent window for message box holding the
  87. //      message.
  88. //
  89. //      UINT fuStyle: Style flags for MessageBox().
  90. //
  91. //      PTSTR pszFormat: Format string used for wvsprintf().
  92. //
  93. //  Return (int):
  94. //      The return value is the result of MessageBox() function.
  95. //
  96. //--------------------------------------------------------------------------;
  97.  
  98. int FNCGLOBAL AppMsgBox
  99. (
  100.     HWND                    hwnd,
  101.     UINT                    fuStyle,
  102.     PTSTR                   pszFormat,
  103.     ...
  104. )
  105. {
  106.     va_list     va;
  107.     TCHAR       ach[1024];
  108.     int         n;
  109.  
  110.     //
  111.     //  format and display the message..
  112.     //
  113.     va_start(va, pszFormat);
  114. #ifdef WIN32
  115.     wvsprintf(ach, pszFormat, va);
  116. #else
  117.     wvsprintf(ach, pszFormat, (LPSTR)va);
  118. #endif
  119.     va_end(va);
  120.  
  121.     n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  122.  
  123.     return (n);
  124. } // AppMsgBox()
  125.  
  126.  
  127. //--------------------------------------------------------------------------;
  128. //
  129. //  int AppMsgBoxId
  130. //
  131. //  Description:
  132. //      This function displays a message for the application. The message
  133. //      text is retrieved from the string resource table using LoadString.
  134. //
  135. //      Note that this function takes any valid argument list that can
  136. //      be passed to wsprintf. Because of this, the application must
  137. //      remember to cast near string pointers to FAR when built for Win 16.
  138. //      You will get a nice GP fault if you do not cast them correctly.
  139. //
  140. //  Arguments:
  141. //      HWND hwnd: Handle to parent window for message box holding the
  142. //      message.
  143. //
  144. //      UINT fuStyle: Style flags for MessageBox().
  145. //
  146. //      UINT uIdsFormat: String resource id to be loaded with LoadString()
  147. //      and used a the format string for wvsprintf().
  148. //
  149. //  Return (int):
  150. //      The return value is the result of MessageBox() if the string
  151. //      resource specified by uIdsFormat is valid. The return value is zero
  152. //      if the string resource failed to load.
  153. //
  154. //--------------------------------------------------------------------------;
  155.  
  156. int FNCGLOBAL AppMsgBoxId
  157. (
  158.     HWND                    hwnd,
  159.     UINT                    fuStyle,
  160.     UINT                    uIdsFormat,
  161.     ...
  162. )
  163. {
  164.     va_list     va;
  165.     TCHAR       szFormat[APP_MAX_STRING_RC_CHARS];
  166.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  167.     int         n;
  168.  
  169.     n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  170.     if (0 != n)
  171.     {
  172.         //
  173.         //  format and display the message..
  174.         //
  175.         va_start(va, uIdsFormat);
  176. #ifdef WIN32
  177.         wvsprintf(ach, szFormat, va);
  178. #else
  179.         wvsprintf(ach, szFormat, (LPSTR)va);
  180. #endif
  181.         va_end(va);
  182.  
  183.         n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  184.     }
  185.  
  186.     return (n);
  187. } // AppMsgBoxId()
  188.  
  189.  
  190. //--------------------------------------------------------------------------;
  191. //
  192. //  void AppHourGlass
  193. //
  194. //  Description:
  195. //      This function changes the cursor to that of the hour glass or
  196. //      back to the previous cursor.
  197. //
  198. //      This function can be called recursively.
  199. //
  200. //  Arguments:
  201. //      BOOL fHourGlass: TRUE if we need the hour glass.  FALSE if we need
  202. //      the arrow back.
  203. //
  204. //  Return (void):
  205. //      On return, the cursor will be what was requested.
  206. //
  207. //--------------------------------------------------------------------------;
  208.  
  209. void FNGLOBAL AppHourGlass
  210. (
  211.     BOOL                    fHourGlass
  212. )
  213. {
  214.     static HCURSOR  hcur;
  215.     static UINT     uWaiting = 0;
  216.  
  217.     if (fHourGlass)
  218.     {
  219.         if (!uWaiting)
  220.         {
  221.             hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  222.             ShowCursor(TRUE);
  223.         }
  224.  
  225.         uWaiting++;
  226.     }
  227.     else
  228.     {
  229.         --uWaiting;
  230.  
  231.         if (!uWaiting)
  232.         {
  233.             ShowCursor(FALSE);
  234.             SetCursor(hcur);
  235.         }
  236.     }
  237. } // AppHourGlass()
  238.  
  239.  
  240. //--------------------------------------------------------------------------;
  241. //
  242. //  BOOL AppYield
  243. //
  244. //  Description:
  245. //      This function yields by dispatching all messages stacked up in the
  246. //      application queue.
  247. //
  248. //  Arguments:
  249. //      HWND hwnd: Handle to main window of application if not yielding
  250. //      for a dialog. Handle to dialog box if yielding for a dialog box.
  251. //
  252. //      BOOL fIsDialog: TRUE if being called to yield for a dialog box.
  253. //
  254. //  Return (BOOL):
  255. //      The return value is always TRUE.
  256. //
  257. //--------------------------------------------------------------------------;
  258.  
  259. BOOL FNGLOBAL AppYield
  260. (
  261.     HWND                    hwnd,
  262.     BOOL                    fIsDialog
  263. )
  264. {
  265.     MSG     msg;
  266.  
  267.     if (fIsDialog)
  268.     {
  269.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  270.         {
  271.             if ((NULL == hwnd) || !IsDialogMessage(hwnd, &msg))
  272.             {
  273.                 TranslateMessage(&msg);
  274.                 DispatchMessage(&msg);
  275.             }
  276.         }
  277.     }
  278.     else
  279.     {
  280.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  281.         {
  282.             TranslateMessage(&msg);
  283.             DispatchMessage(&msg);
  284.         }
  285.     }
  286.  
  287.     return (TRUE);
  288. } // AppYield()
  289.  
  290.  
  291. //--------------------------------------------------------------------------;
  292. //
  293. //  int AppSetWindowText
  294. //
  295. //  Description:
  296. //      This function formats a string and sets the specified window text
  297. //      to the result.
  298. //
  299. //  Arguments:
  300. //      HWND hwnd: Handle to window to receive the new text.
  301. //
  302. //      PTSTR pszFormat: Pointer to any valid format for wsprintf.
  303. //
  304. //  Return (int):
  305. //      The return value is the number of bytes that the resulting window
  306. //      text was.
  307. //
  308. //--------------------------------------------------------------------------;
  309.  
  310. int FNCGLOBAL AppSetWindowText
  311. (
  312.     HWND                    hwnd,
  313.     PTSTR                   pszFormat,
  314.     ...
  315. )
  316. {
  317.     va_list     va;
  318.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  319.     int         n;
  320.  
  321.     //
  322.     //  format and display the string in the window...
  323.     //
  324.     va_start(va, pszFormat);
  325. #ifdef WIN32
  326.     n = wvsprintf(ach, pszFormat, va);
  327. #else
  328.     n = wvsprintf(ach, pszFormat, (LPSTR)va);
  329. #endif
  330.     va_end(va);
  331.  
  332.     SetWindowText(hwnd, ach);
  333.  
  334.     return (n);
  335. } // AppSetWindowText()
  336.  
  337.  
  338. //--------------------------------------------------------------------------;
  339. //
  340. //  int AppSetWindowTextId
  341. //
  342. //  Description:
  343. //      This function formats a string and sets the specified window text
  344. //      to the result. The format string is extracted from the string
  345. //      table using LoadString() on the uIdsFormat argument.
  346. //
  347. //  Arguments:
  348. //      HWND hwnd: Handle to window to receive the new text.
  349. //
  350. //      UINT uIdsFormat: String resource id to be loaded with LoadString()
  351. //      and used a the format string for wvsprintf().
  352. //
  353. //  Return (int):
  354. //      The return value is the number of bytes that the resulting window
  355. //      text was. This value is zero if the LoadString() function fails
  356. //      for the uIdsFormat argument.
  357. //
  358. //--------------------------------------------------------------------------;
  359.  
  360. int FNCGLOBAL AppSetWindowTextId
  361. (
  362.     HWND                    hwnd,
  363.     UINT                    uIdsFormat,
  364.     ...
  365. )
  366. {
  367.     va_list     va;
  368.     TCHAR       szFormat[APP_MAX_STRING_RC_CHARS];
  369.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  370.     int         n;
  371.  
  372.     n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  373.     if (0 != n)
  374.     {
  375.         //
  376.         //  format and display the string in the window...
  377.         //
  378.         va_start(va, uIdsFormat);
  379. #ifdef WIN32
  380.         n = wvsprintf(ach, szFormat, va);
  381. #else
  382.         n = wvsprintf(ach, szFormat, (LPSTR)va);
  383. #endif
  384.         va_end(va);
  385.  
  386.         SetWindowText(hwnd, ach);
  387.     }
  388.  
  389.     return (n);
  390. } // AppSetWindowTextId()
  391.  
  392.  
  393. //--------------------------------------------------------------------------;
  394. //  
  395. //  BOOL AppFormatBigNumber
  396. //  
  397. //  Description:
  398. //  
  399. //  
  400. //  Arguments:
  401. //      LPTSTR pszNumber:
  402. //  
  403. //      DWORD dw:
  404. //  
  405. //  Return (BOOL):
  406. //  
  407. //--------------------------------------------------------------------------;
  408.  
  409. BOOL FNGLOBAL AppFormatBigNumber
  410. (
  411.     LPTSTR                  pszNumber,
  412.     DWORD                   dw
  413. )
  414. {
  415.     //
  416.     //  this is ugly...
  417.     //
  418.     //
  419.     if (dw >= 1000000000L)
  420.     {
  421.         wsprintf(pszNumber, TEXT("%u,%03u,%03u,%03u"),
  422.                             (WORD)(dw / 1000000000L),
  423.                             (WORD)((dw % 1000000000L) / 1000000L),
  424.                             (WORD)((dw % 1000000L) / 1000),
  425.                             (WORD)(dw % 1000));
  426.     }
  427.     else if (dw >= 1000000L)
  428.     {
  429.         wsprintf(pszNumber, TEXT("%u,%03u,%03u"),
  430.                             (WORD)(dw / 1000000L),
  431.                             (WORD)((dw % 1000000L) / 1000),
  432.                             (WORD)(dw % 1000));
  433.     }
  434.     else if (dw >= 1000)
  435.     {
  436.         wsprintf(pszNumber, TEXT("%u,%03u"),
  437.                             (WORD)(dw / 1000),
  438.                             (WORD)(dw % 1000));
  439.     }
  440.     else
  441.     {
  442.         wsprintf(pszNumber, TEXT("%lu"), dw);
  443.     }
  444.  
  445.  
  446.     return (TRUE);
  447. } // AppFormatBigNumber()
  448.  
  449.  
  450. //--------------------------------------------------------------------------;
  451. //  
  452. //  BOOL AppFormatDosDateTime
  453. //  
  454. //  Description:
  455. //  
  456. //  
  457. //  Arguments:
  458. //      LPTSTR pszDateTime:
  459. //  
  460. //      UINT uDosDate:
  461. //  
  462. //      UINT uDosTime:
  463. //  
  464. //  Return (BOOL):
  465. //  
  466. //--------------------------------------------------------------------------;
  467.  
  468. BOOL FNGLOBAL AppFormatDosDateTime
  469. (
  470.     LPTSTR                  pszDateTime,
  471.     UINT                    uDosDate,
  472.     UINT                    uDosTime
  473. )
  474. {
  475.     static TCHAR        szFormatDateTime[]  = TEXT("%.02u/%.02u/%.02u  %.02u:%.02u:%.02u");
  476.  
  477.     UINT                uDateMonth;
  478.     UINT                uDateDay;
  479.     UINT                uDateYear;
  480.     UINT                uTimeHour;
  481.     UINT                uTimeMinute;
  482.     UINT                uTimeSecond;
  483.  
  484.     //
  485.     //
  486.     //
  487.     uTimeHour   = uDosTime >> 11;
  488.     uTimeMinute = (uDosTime & 0x07E0) >> 5;
  489.     uTimeSecond = (uDosTime & 0x001F) << 1;
  490.  
  491.     uDateMonth  = (uDosDate & 0x01E0) >> 5;
  492.     uDateDay    = (uDosDate & 0x001F);
  493.     uDateYear   = (uDosDate >> 9) + 80;
  494.  
  495.     //
  496.     //
  497.     //
  498.     //
  499.     wsprintf(pszDateTime, szFormatDateTime,
  500.              uDateMonth,
  501.              uDateDay,
  502.              uDateYear,
  503.              uTimeHour,
  504.              uTimeMinute,
  505.              uTimeSecond);
  506.  
  507.     return (TRUE);
  508. } // AppFormatDosDateTime()
  509.  
  510.  
  511. //--------------------------------------------------------------------------;
  512. //
  513. //  void AcmAppDebugLog
  514. //
  515. //  Description:
  516. //      This function logs information to the debugger if the Debug Log
  517. //      option is set. You can then run DBWin (or something similar)
  518. //      to redirect the output whereever you want. Very useful for debugging
  519. //      ACM drivers.
  520. //
  521. //  Arguments:
  522. //      PTSTR pszFormat: Pointer to any valid format for wsprintf.
  523. //
  524. //  Return (void):
  525. //      None.
  526. //
  527. //--------------------------------------------------------------------------;
  528.  
  529. void FNCGLOBAL AcmAppDebugLog
  530. (
  531.     PTSTR                   pszFormat,
  532.     ...
  533. )
  534. {
  535.     static  TCHAR   szDebugLogSeparator[] = TEXT("=============================================================================\r\n");
  536.  
  537.     va_list     va;
  538.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  539.  
  540.  
  541.     //
  542.     //  !!! UNICODE !!!
  543.     //
  544.     //
  545.     if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions))
  546.     {
  547.         if (NULL == pszFormat)
  548.         {
  549.             OutputDebugString(szDebugLogSeparator);
  550.             return;
  551.         }
  552.  
  553.         //
  554.         //  format and display the string in a message box...
  555.         //
  556.         va_start(va, pszFormat);
  557. #ifdef WIN32
  558.         wvsprintf(ach, pszFormat, va);
  559. #else
  560.         wvsprintf(ach, pszFormat, (LPSTR)va);
  561. #endif
  562.         va_end(va);
  563.  
  564.         OutputDebugString(ach);
  565.     }
  566. } // AcmAppDebugLog()
  567.  
  568.  
  569. //--------------------------------------------------------------------------;
  570. //  
  571. //  int MEditPrintF
  572. //  
  573. //  Description:
  574. //      This function is used to print formatted text into a Multiline
  575. //      Edit Control as if it were a standard console display. This is
  576. //      a very easy way to display small amounts of text information
  577. //      that can be scrolled and copied to the clip-board.
  578. //  
  579. //  Arguments:
  580. //      HWND hedit: Handle to a Multiline Edit control.
  581. //  
  582. //      PTSTR pszFormat: Pointer to any valid format for wsprintf. If
  583. //      this argument is NULL, then the Multiline Edit Control is cleared
  584. //      of all text.
  585. //
  586. //
  587. //  Return (int):
  588. //      Returns the number of characters written into the edit control.
  589. //
  590. //  Notes:
  591. //      The pszFormat string can contain combinations of escapes that 
  592. //      modify the default behaviour of this function. Escapes are single
  593. //      character codes placed at the _beginning_ of the format string.
  594. //
  595. //      Current escapes defined are:
  596. //
  597. //      ~   :   Suppresses the default CR/LF added to the end of the 
  598. //              printed line. Since the most common use of this function
  599. //              is to output a whole line of text with a CR/LF, that is
  600. //              the default.
  601. //
  602. //      `   :   Suppresses logging to the debug terminal (regardless of
  603. //              the global debug log options flag).
  604. //
  605. //  
  606. //--------------------------------------------------------------------------;
  607.  
  608. int FNCGLOBAL MEditPrintF
  609. (
  610.     HWND                    hedit,
  611.     PTSTR                   pszFormat,
  612.     ...
  613. )
  614. {
  615.     static  TCHAR   szCRLF[]              = TEXT("\r\n");
  616.  
  617.     va_list     va;
  618.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  619.     int         n;
  620.     BOOL        fCRLF;
  621.     BOOL        fDebugLog;
  622.  
  623.     //
  624.     //  default the escapes
  625.     //
  626.     fCRLF     = TRUE;
  627.     fDebugLog = TRUE;
  628.  
  629.  
  630.     //
  631.     //  if the pszFormat argument is NULL, then just clear all text in
  632.     //  the edit control..
  633.     //
  634.     if (NULL == pszFormat)
  635.     {
  636.         SetWindowText(hedit, gszNull);
  637.  
  638.         AcmAppDebugLog(NULL);
  639.  
  640.         return (0);
  641.     }
  642.  
  643.     //
  644.     //  format and display the string in the window... first search for
  645.     //  escapes to modify default behaviour.
  646.     //
  647.     for (;;)
  648.     {
  649.         switch (*pszFormat)
  650.         {
  651.             case '~':
  652.                 fCRLF = FALSE;
  653.                 pszFormat++;
  654.                 continue;
  655.  
  656.             case '`':
  657.                 fDebugLog = FALSE;
  658.                 pszFormat++;
  659.                 continue;
  660.         }
  661.  
  662.         break;
  663.     }
  664.  
  665.     va_start(va, pszFormat);
  666. #ifdef WIN32
  667.     n = wvsprintf(ach, pszFormat, va);
  668. #else
  669.     n = wvsprintf(ach, pszFormat, (LPSTR)va);
  670. #endif
  671.     va_end(va);
  672.  
  673.     Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
  674.     Edit_ReplaceSel(hedit, ach);
  675.  
  676.     if (fDebugLog)
  677.     {
  678.         AcmAppDebugLog(ach);
  679.     }
  680.  
  681.     if (fCRLF)
  682.     {
  683.         Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
  684.         Edit_ReplaceSel(hedit, szCRLF);
  685.  
  686.         if (fDebugLog)
  687.         {
  688.             AcmAppDebugLog(szCRLF);
  689.         }
  690.     }
  691.  
  692.     return (n);
  693. } // MEditPrintF()
  694.  
  695.  
  696. //--------------------------------------------------------------------------;
  697. //
  698. //  BOOL AppGetFileTitle
  699. //
  700. //  Description:
  701. //      This function extracts the file title from a file path and returns
  702. //      it in the caller's specified buffer.
  703. //
  704. //  Arguments:
  705. //      PTSTR pszFilePath: Pointer to null terminated file path.
  706. //
  707. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  708. //
  709. //  Return (BOOL):
  710. //      Always returns TRUE. But should return FALSE if this function
  711. //      checked for bogus values, etc.
  712. //
  713. //
  714. //--------------------------------------------------------------------------;
  715.  
  716. BOOL FNGLOBAL AppGetFileTitle
  717. (
  718.     PTSTR                   pszFilePath,
  719.     PTSTR                   pszFileTitle
  720. )
  721. {
  722.     #define IS_SLASH(c)     ('/' == (c) || '\\' == (c))
  723.  
  724.     PTSTR       pch;
  725.  
  726.     //
  727.     //  scan to the end of the file path string..
  728.     //
  729.     for (pch = pszFilePath; '\0' != *pch; pch++)
  730.         ;
  731.  
  732.     //
  733.     //  now scan back toward the beginning of the string until a slash (\),
  734.     //  colon, or start of the string is encountered.
  735.     //
  736.     while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch))
  737.     {
  738.         pch--;
  739.     }
  740.  
  741.     //
  742.     //  finally, copy the 'title' into the destination buffer.. skip ahead
  743.     //  one char since the above loop steps back one too many chars...
  744.     //
  745.     lstrcpy(pszFileTitle, ++pch);
  746.  
  747.     return (TRUE);
  748. } // AppGetFileTitle()
  749.  
  750.  
  751. //--------------------------------------------------------------------------;
  752. //
  753. //  BOOL AppGetFileName
  754. //
  755. //  Description:
  756. //      This function is a wrapper for the Get[Open/Save]FileName commdlg
  757. //      chooser dialogs. Based on the fuFlags argument, this function will
  758. //      display the appropriate chooser dialog and return the result.
  759. //
  760. //  Arguments:
  761. //      HWND hwnd: Handle to parent window for chooser dialog.
  762. //
  763. //      PTSTR pszFilePath: Pointer to buffer to receive the file path.
  764. //
  765. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  766. //      This argument may be NULL, in which case no title will be returned.
  767. //
  768. //      UINT fuFlags:
  769. //
  770. //  Return (BOOL):
  771. //      The return value is TRUE if a file was chosen. It is FALSE if the
  772. //      user canceled the operation.
  773. //
  774. //
  775. //--------------------------------------------------------------------------;
  776.  
  777. BOOL FNGLOBAL AppGetFileName
  778. (
  779.     HWND                    hwnd,
  780.     PTSTR                   pszFilePath,
  781.     PTSTR                   pszFileTitle,
  782.     UINT                    fuFlags
  783. )
  784. {
  785.     #define APP_OFN_FLAGS_SAVE  (OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT)
  786.     #define APP_OFN_FLAGS_OPEN  (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST)
  787.  
  788.     TCHAR               szExtDefault[APP_MAX_EXT_DEFAULT_CHARS];
  789.     TCHAR               szExtFilter[APP_MAX_EXT_FILTER_CHARS];
  790.     OPENFILENAME        ofn;
  791.     BOOL                f;
  792.     PTCHAR              pch;
  793.  
  794.  
  795.     //
  796.     //  get the extension filter and default extension for this application
  797.     //
  798.     LoadString(ghinst, IDS_OFN_EXT_DEF, szExtDefault, SIZEOF(szExtDefault));
  799.     LoadString(ghinst, IDS_OFN_EXT_FILTER, szExtFilter, SIZEOF(szExtFilter));
  800.  
  801.  
  802.     //
  803.     //  NOTE! building the filter string for the OPENFILENAME structure
  804.     //  is a bit more difficult when dealing with Unicode and C8's new
  805.     //  optimizer. it joyfully removes literal '\0' characters from
  806.     //  strings that are concatted together. if you try making each
  807.     //  string separate (array of pointers to strings), the compiler
  808.     //  will dword align them... etc, etc.
  809.     //
  810.     //  if you can think of a better way to build the silly filter string
  811.     //  for common dialogs and still work in Win 16 and Win 32 [Unicode]
  812.     //  i'd sure like to hear about it...
  813.     //
  814.     for (pch = &szExtFilter[0]; '\0' != *pch; pch++)
  815.     {
  816.         if ('!' == *pch)
  817.             *pch = '\0';
  818.     }
  819.  
  820.     //
  821.     //  initialize the OPENFILENAME members
  822.     //
  823.     memset(&ofn, 0, sizeof(OPENFILENAME));
  824.  
  825.     pszFilePath[0]          = '\0';
  826.     if (pszFileTitle)
  827.         pszFileTitle[0]     = '\0';
  828.  
  829.     ofn.lStructSize         = sizeof(OPENFILENAME);
  830.     ofn.hwndOwner           = hwnd;
  831.     ofn.lpstrFilter         = szExtFilter;
  832.     ofn.lpstrCustomFilter   = NULL;
  833.     ofn.nMaxCustFilter      = 0L;
  834.     ofn.nFilterIndex        = 1L;
  835.     ofn.lpstrFile           = pszFilePath;
  836.     ofn.nMaxFile            = APP_MAX_FILE_PATH_CHARS;
  837.     ofn.lpstrFileTitle      = pszFileTitle;
  838.     ofn.nMaxFileTitle       = pszFileTitle ? APP_MAX_FILE_TITLE_CHARS : 0;
  839.     if (fuFlags & APP_GETFILENAMEF_SAVE)
  840.     {
  841.         ofn.lpstrInitialDir = gszInitialDirSave;
  842.     }
  843.     else
  844.     {
  845.         ofn.lpstrInitialDir = gszInitialDirOpen;
  846.     }
  847.     ofn.nFileOffset         = 0;
  848.     ofn.nFileExtension      = 0;
  849.     ofn.lpstrDefExt         = szExtDefault;
  850.  
  851.     //
  852.     //  if the fuFlags.APP_GETFILENAMEF_SAVE bit is set, then call
  853.     //  GetSaveFileName() otherwise call GetOpenFileName(). why commdlg was
  854.     //  designed with two separate functions for save and open only clark
  855.     //  knows.
  856.     //
  857.     if (fuFlags & APP_GETFILENAMEF_SAVE)
  858.     {
  859.         ofn.Flags = APP_OFN_FLAGS_SAVE;
  860.         f = GetSaveFileName(&ofn);
  861.         if (f)
  862.         {
  863.             if (NULL != pszFilePath)
  864.             {
  865.                 lstrcpy(gszInitialDirSave, pszFilePath);
  866.  
  867.                 pch = &gszInitialDirSave[lstrlen(gszInitialDirSave) - 1];
  868.                 for ( ; gszInitialDirSave != pch; pch--)
  869.                 {
  870.                     if ('\\' == *pch)
  871.                     {
  872.                         *pch = '\0';
  873.                         break;
  874.                     }
  875.                 }
  876.             }
  877.         }
  878.     }
  879.     else
  880.     {
  881.         ofn.Flags = APP_OFN_FLAGS_OPEN;
  882.         f = GetOpenFileName(&ofn);
  883.         if (f)
  884.         {
  885.             if (NULL != pszFilePath)
  886.             {
  887.                 lstrcpy(gszInitialDirOpen, pszFilePath);
  888.  
  889.                 pch = &gszInitialDirOpen[lstrlen(gszInitialDirOpen) - 1];
  890.                 for ( ; gszInitialDirOpen != pch; pch--)
  891.                 {
  892.                     if ('\\' == *pch)
  893.                     {
  894.                         *pch = '\0';
  895.                         break;
  896.                     }
  897.                 }
  898.             }
  899.         }
  900.     }
  901.  
  902.     return (f);
  903. } // AppGetFileName()
  904.  
  905.  
  906. //--------------------------------------------------------------------------;
  907. //
  908. //  BOOL AppTitle
  909. //
  910. //  Description:
  911. //      This function formats and sets the title text of the application's
  912. //      window.
  913. //
  914. //  Arguments:
  915. //      HWND hwnd: Handle to application window to set title text for.
  916. //
  917. //      PTSTR pszFileTitle: Pointer to file title to display.
  918. //
  919. //  Return (BOOL):
  920. //      The return value is always TRUE.
  921. //
  922. //
  923. //--------------------------------------------------------------------------;
  924.  
  925. BOOL FNGLOBAL AppTitle
  926. (
  927.     HWND                    hwnd,
  928.     PTSTR                   pszFileTitle
  929. )
  930. {
  931.     static  TCHAR   szFormatTitle[]     = TEXT("%s - %s");
  932.  
  933.     TCHAR       ach[APP_MAX_FILE_PATH_CHARS];
  934.  
  935.     //
  936.     //  format the title text as 'AppName - FileTitle'
  937.     //
  938.     wsprintf(ach, szFormatTitle, (LPSTR)gszAppName, (LPSTR)pszFileTitle);
  939.     SetWindowText(hwnd, ach);
  940.  
  941.     return (TRUE);
  942. } // AppTitle()
  943.  
  944.  
  945. //--------------------------------------------------------------------------;
  946. //
  947. //  BOOL AppFileNew
  948. //
  949. //  Description:
  950. //      This function is called to handle the IDM_FILE_NEW message. It is
  951. //      responsible for clearing the working area for a new unnamed file.
  952. //
  953. //  Arguments:
  954. //      HWND hwnd: Handle to application window.
  955. //
  956. //      PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  957. //
  958. //  Return (BOOL):
  959. //      The return value is TRUE if the working area was cleared and is
  960. //      ready for new stuff. The return value is FALSE if the user canceled
  961. //      the operation.
  962. //
  963. //--------------------------------------------------------------------------;
  964.  
  965. BOOL FNGLOBAL AppFileNew
  966. (
  967.     HWND                    hwnd,
  968.     PACMAPPFILEDESC         paafd,
  969.     BOOL                    fCreate
  970. )
  971. {
  972.     BOOL                f;
  973.  
  974.     if (fCreate)
  975.     {
  976.         f = AcmAppFileNew(hwnd, paafd);
  977.         if (!f)
  978.             return (FALSE);
  979.     }
  980.     else
  981.     {
  982.         //
  983.         //  if there is currently a file path, then we have to do some real
  984.         //  work...
  985.         //
  986.         if ('\0' != paafd->szFilePath[0])
  987.         {
  988.             f = AcmAppFileNew(hwnd, paafd);
  989.             if (!f)
  990.                 return (FALSE);
  991.         }
  992.  
  993.         //
  994.         //  blow away the old file path and title; set the window title
  995.         //  and return success
  996.         //
  997.         lstrcpy(paafd->szFilePath, gszFileUntitled);
  998.         lstrcpy(paafd->szFileTitle, gszFileUntitled);
  999.     }
  1000.  
  1001.     AppTitle(hwnd, paafd->szFileTitle);
  1002.  
  1003.     AcmAppDisplayFileProperties(hwnd, paafd);
  1004.  
  1005.     return (TRUE);
  1006. } // AppFileNew()
  1007.  
  1008.  
  1009. //--------------------------------------------------------------------------;
  1010. //
  1011. //  BOOL AppFileOpen
  1012. //
  1013. //  Description:
  1014. //      This function handles the IDM_FILE_OPEN message. It is responsible
  1015. //      for getting a new file name from the user and opening that file
  1016. //      if possible.
  1017. //
  1018. //  Arguments:
  1019. //      HWND hwnd: Handle to application window.
  1020. //
  1021. //      PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  1022. //
  1023. //  Return (BOOL):
  1024. //      The return value is TRUE if a new file was selected and opened.
  1025. //      It is FALSE if the user canceled the operation.
  1026. //
  1027. //--------------------------------------------------------------------------;
  1028.  
  1029. BOOL FNLOCAL AppFileOpen
  1030. (
  1031.     HWND                    hwnd,
  1032.     PACMAPPFILEDESC         paafd
  1033. )
  1034. {
  1035.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  1036.     TCHAR               szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  1037.     BOOL                f;
  1038.  
  1039.     //
  1040.     //  first test for a modified file that has not been saved. if the
  1041.     //  return value is FALSE we should cancel the File.Open operation.
  1042.     //
  1043.     f = AcmAppFileSaveModified(hwnd, paafd);
  1044.     if (!f)
  1045.         return (FALSE);
  1046.  
  1047.  
  1048.     //
  1049.     //  get the file name of the new file into temporary buffers (so
  1050.     //  if we fail to open it we can back out cleanly).
  1051.     //
  1052.     f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_OPEN);
  1053.     if (!f)
  1054.         return (FALSE);
  1055.  
  1056.  
  1057.     //!!!
  1058.     //  read the new file...
  1059.     //
  1060.     lstrcpy(paafd->szFilePath, szFilePath);
  1061.     lstrcpy(paafd->szFileTitle, szFileTitle);
  1062.  
  1063.     f = AcmAppFileOpen(hwnd, paafd);
  1064.     if (f)
  1065.     {
  1066.         //
  1067.         //  set the window title text...
  1068.         //
  1069.         AppTitle(hwnd, szFileTitle);
  1070.         AcmAppDisplayFileProperties(hwnd, paafd);
  1071.     }
  1072.  
  1073.     return (f);
  1074. } // AppFileOpen()
  1075.  
  1076.  
  1077. //--------------------------------------------------------------------------;
  1078. //
  1079. //  BOOL AppFileSave
  1080. //
  1081. //  Description:
  1082. //      This function handles the IDM_FILE_SAVE[AS] messages. It is
  1083. //      responsible for saving the current file. If a file name needs
  1084. //      to be specified then the save file dialog is displayed.
  1085. //
  1086. //  Arguments:
  1087. //      HWND hwnd: Handle to application window.
  1088. //
  1089. //      PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  1090. //
  1091. //      BOOL fSaveAs: TRUE if the save file chooser should be displayed
  1092. //      before saving the file. FALSE if should operate like File.Save.
  1093. //
  1094. //  Return (BOOL):
  1095. //      The return value is TRUE if the file was saved. It is FALSE if the
  1096. //      user canceled the operation or the file does not need saved.
  1097. //
  1098. //--------------------------------------------------------------------------;
  1099.  
  1100. BOOL FNGLOBAL AppFileSave
  1101. (
  1102.     HWND                    hwnd,
  1103.     PACMAPPFILEDESC         paafd,
  1104.     BOOL                    fSaveAs
  1105. )
  1106. {
  1107.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  1108.     TCHAR               szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  1109.     BOOL                f;
  1110.  
  1111.     //
  1112.     //
  1113.     //
  1114.     lstrcpy(szFilePath, paafd->szFilePath);
  1115.     lstrcpy(szFileTitle, paafd->szFileTitle);
  1116.  
  1117.  
  1118.     //
  1119.     //  check if we should bring up the save file chooser dialog...
  1120.     //
  1121.     if (fSaveAs || (0 == lstrcmp(paafd->szFileTitle, gszFileUntitled)))
  1122.     {
  1123.         //
  1124.         //  get the file name for saving the data to into temporary
  1125.         //  buffers (so if we fail to save it we can back out cleanly).
  1126.         //
  1127.         f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_SAVE);
  1128.         if (!f)
  1129.             return (FALSE);
  1130.     }
  1131.  
  1132.     //
  1133.     //  save the file...
  1134.     //
  1135.     f = AcmAppFileSave(hwnd, paafd, szFilePath, szFileTitle, 0);
  1136.     if (f)
  1137.     {
  1138.         //
  1139.         //  changes have been saved, so clear the modified bit...
  1140.         //
  1141.         paafd->fdwState &= ~ACMAPPFILEDESC_STATEF_MODIFIED;
  1142.  
  1143.         AppTitle(hwnd, paafd->szFileTitle);
  1144.  
  1145.         AcmAppDisplayFileProperties(hwnd, paafd);
  1146.     }
  1147.  
  1148.     return (f);
  1149. } // AppFileSave()
  1150.  
  1151.  
  1152. //==========================================================================;
  1153. //
  1154. //  Main application window handling code...
  1155. //
  1156. //
  1157. //==========================================================================;
  1158.  
  1159. //--------------------------------------------------------------------------;
  1160. //
  1161. //  LRESULT AppInitMenuPopup
  1162. //
  1163. //  Description:
  1164. //      This function handles the WM_INITMENUPOPUP message. This message
  1165. //      is sent to the window owning the menu that is going to become
  1166. //      active. This gives an application the ability to modify the menu
  1167. //      before it is displayed (disable/add items, etc).
  1168. //
  1169. //  Arguments:
  1170. //      HWND hwnd: Handle to window that generated the WM_INITMENUPOPUP
  1171. //      message.
  1172. //
  1173. //      HMENU hmenu: Handle to the menu that is to become active.
  1174. //
  1175. //      int nItem: Specifies the zero-based relative position of the menu
  1176. //      item that invoked the popup menu.
  1177. //
  1178. //      BOOL fSysMenu: Specifies whether the popup menu is a System menu
  1179. //      (TRUE) or it is not a System menu (FALSE).
  1180. //
  1181. //  Return (LRESULT):
  1182. //      Returns zero if the message is processed.
  1183. //
  1184. //--------------------------------------------------------------------------;
  1185.  
  1186. LRESULT FNLOCAL AppInitMenuPopup
  1187. (
  1188.     HWND                    hwnd,
  1189.     HMENU                   hmenu,
  1190.     int                     nItem,
  1191.     BOOL                    fSysMenu
  1192. )
  1193. {
  1194.     BOOL                f;
  1195.     int                 nSelStart;
  1196.     int                 nSelEnd;
  1197.     HWND                hedit;
  1198.  
  1199.     DPF(4, "AppInitMenuPopup(hwnd=%Xh, hmenu=%Xh, nItem=%d, fSysMenu=%d)",
  1200.             hwnd, hmenu, nItem, fSysMenu);
  1201.  
  1202.     //
  1203.     //  if the system menu is what got hit, succeed immediately... this
  1204.     //  application has no stuff in the system menu.
  1205.     //
  1206.     if (fSysMenu)
  1207.         return (0L);
  1208.  
  1209.     //
  1210.     //  initialize the menu that is being 'popped up'
  1211.     //
  1212.     switch (nItem)
  1213.     {
  1214.         case APP_MENU_ITEM_FILE:
  1215.             EnableMenuItem(hmenu, IDM_FILE_NEW,
  1216.                            (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
  1217.  
  1218.             f = (NULL != gaafd.pwfx);
  1219.             EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_PLAY,
  1220.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1221.             EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_STOP,
  1222.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1223.  
  1224.             f = (NULL != gaafd.pwfx) && gfAcmAvailable;
  1225.             EnableMenuItem(hmenu, IDM_FILE_CONVERT,
  1226.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1227.             EnableMenuItem(hmenu, IDM_FILE_CONVERT_ALL,
  1228.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1229.  
  1230.  
  1231.             //
  1232.             //  if the file has been modified, then enable the File.Save
  1233.             //  menu
  1234.             //
  1235.             f = (0 != (gaafd.fdwState & ACMAPPFILEDESC_STATEF_MODIFIED));
  1236.             EnableMenuItem(hmenu, IDM_FILE_SAVE,
  1237.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1238.  
  1239.             // f = (NULL != gaafd.pwfx);
  1240.             EnableMenuItem(hmenu, IDM_FILE_SAVEAS,
  1241.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1242.             break;
  1243.  
  1244.         case APP_MENU_ITEM_EDIT:
  1245.             //
  1246.             //  check to see if something is selected in the display
  1247.             //  window and enable/disable Edit menu options appropriately
  1248.             //
  1249.             hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1250.             Edit_GetSelEx(hedit, &nSelStart, &nSelEnd);
  1251.  
  1252.             f = (nSelStart != nSelEnd);
  1253.             EnableMenuItem(hmenu, WM_COPY,  (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1254.             break;
  1255.  
  1256.         case APP_MENU_ITEM_VIEW:
  1257.             EnableMenuItem(hmenu, IDM_VIEW_ACM_DRIVERS,
  1258.                            (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
  1259.             break;
  1260.  
  1261.  
  1262.         case APP_MENU_ITEM_OPTIONS:
  1263.             f = (0 != waveInGetNumDevs());
  1264.             EnableMenuItem(hmenu, IDM_OPTIONS_WAVEINDEVICE,  (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1265.  
  1266.             f = (0 != waveOutGetNumDevs());
  1267.             EnableMenuItem(hmenu, IDM_OPTIONS_WAVEOUTDEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1268.  
  1269.             //
  1270.             //  make sure the options that need a checkmark are checked..
  1271.             //
  1272.             f = (0 != (APP_OPTIONSF_AUTOOPEN & gfuAppOptions));
  1273.             CheckMenuItem(hmenu, IDM_OPTIONS_AUTOOPEN,
  1274.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  1275.  
  1276.             f = (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions));
  1277.             CheckMenuItem(hmenu, IDM_OPTIONS_DEBUGLOG,
  1278.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  1279.             break;
  1280.     }
  1281.  
  1282.     //
  1283.     //  we processed the message--return 0...
  1284.     //
  1285.     return (0L);
  1286. } // AppInitMenuPopup()
  1287.  
  1288.  
  1289. //--------------------------------------------------------------------------;
  1290. //
  1291. //  LRESULT AppCommand
  1292. //
  1293. //  Description:
  1294. //      This function handles the WM_COMMAND message.
  1295. //
  1296. //  Arguments:
  1297. //      HWND hwnd: Handle to window receiving the WM_COMMAND message.
  1298. //
  1299. //      int nId: Control or menu item identifier.
  1300. //
  1301. //      HWND hwndCtl: Handle of control if the message is from a control.
  1302. //      This argument is NULL if the message was not generated by a control.
  1303. //
  1304. //      UINT uCode: Notification code. This argument is 1 if the message
  1305. //      was generated by an accelerator. If the message is from a menu,
  1306. //      this argument is 0.
  1307. //
  1308. //  Return (LRESULT):
  1309. //      Returns zero if the message is processed.
  1310. //
  1311. //--------------------------------------------------------------------------;
  1312.  
  1313. LRESULT FNLOCAL AppCommand
  1314. (
  1315.     HWND                    hwnd,
  1316.     int                     nId,
  1317.     HWND                    hwndCtl,
  1318.     UINT                    uCode
  1319. )
  1320. {
  1321.     BOOL                f;
  1322.     DWORD               dw;
  1323.     UINT                uDevId;
  1324.  
  1325.     switch (nId)
  1326.     {
  1327.         case IDM_FILE_NEW:
  1328.             AppFileNew(hwnd, &gaafd, TRUE);
  1329.             break;
  1330.  
  1331.         case IDM_FILE_OPEN:
  1332.             AppFileOpen(hwnd, &gaafd);
  1333.             break;
  1334.  
  1335.         case IDM_FILE_SAVE:
  1336.             AppFileSave(hwnd, &gaafd, FALSE);
  1337.             break;
  1338.  
  1339.         case IDM_FILE_SAVEAS:
  1340.             AppFileSave(hwnd, &gaafd, TRUE);
  1341.             break;
  1342.  
  1343.  
  1344.         case IDM_FILE_SNDPLAYSOUND_PLAY:
  1345.             if (NULL == gaafd.pwfx)
  1346.             {
  1347.                 MessageBeep((UINT)-1);
  1348.                 break;
  1349.             }
  1350.  
  1351.             AppHourGlass(TRUE);
  1352.             dw = timeGetTime();
  1353.             f  = sndPlaySound(gaafd.szFilePath, SND_ASYNC | SND_NODEFAULT);
  1354.             dw = timeGetTime() - dw;
  1355.             AppHourGlass(FALSE);
  1356.  
  1357.             if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions))
  1358.             {
  1359.                 AcmAppDebugLog(NULL);
  1360.                 AcmAppDebugLog(TEXT("sndPlaySound(%s) took %lu milliseconds to %s.\r\n"),
  1361.                                 (LPTSTR)gaafd.szFilePath,
  1362.                                 dw,
  1363.                                 f ? (LPTSTR)TEXT("succeed") : (LPTSTR)TEXT("fail"));
  1364.             }
  1365.             
  1366.             if (!f)
  1367.             {
  1368.                 AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  1369.                           TEXT("The file '%s' cannot be played by sndPlaySound."),
  1370.                           (LPSTR)gaafd.szFilePath);
  1371.             }
  1372.             break;
  1373.  
  1374.         case IDM_FILE_SNDPLAYSOUND_STOP:
  1375.             sndPlaySound(NULL, 0L);
  1376.             break;
  1377.  
  1378.         case IDM_FILE_CONVERT:
  1379.             AcmAppFileConvert(hwnd, &gaafd);
  1380.             break;
  1381.  
  1382.         case IDM_FILE_CONVERT_ALL:
  1383.             AcmAppMultiThreadedConvertAll(hwnd, &gaafd);
  1384.             break;
  1385.  
  1386.  
  1387.         case IDM_FILE_ABOUT:
  1388.             DialogBox(ghinst, DLG_ABOUT, hwnd, AboutDlgProc);
  1389.             break;
  1390.  
  1391.         case IDM_FILE_EXIT:
  1392.             FORWARD_WM_CLOSE(hwnd, SendMessage);
  1393.             break;
  1394.  
  1395.  
  1396.         case WM_COPY:
  1397.             //
  1398.             //  pass on edit messages received to the display window
  1399.             //
  1400.             SendMessage(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), nId, 0, 0L);
  1401.             break;
  1402.  
  1403.         case IDM_EDIT_SELECTALL:
  1404.             Edit_SetSel(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), 0, -1);
  1405.             break;
  1406.  
  1407.  
  1408.         case IDM_UPDATE:
  1409.             AcmAppFileOpen(hwnd, &gaafd);
  1410.  
  1411.             AcmAppDisplayFileProperties(hwnd, &gaafd);
  1412.             break;
  1413.  
  1414.         case IDM_VIEW_SYSTEMINFO:
  1415.             DialogBox(ghinst, DLG_AADETAILS, hwnd, AcmAppSystemInfoDlgProc);
  1416.             break;
  1417.  
  1418.         case IDM_VIEW_ACM_DRIVERS:
  1419.             DialogBox(ghinst, DLG_AADRIVERS, hwnd, AcmAppDriversDlgProc);
  1420.             break;
  1421.  
  1422.  
  1423.         case IDM_OPTIONS_WAVEINDEVICE:
  1424.             uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd,
  1425.                                     AcmAppWaveDeviceDlgProc,
  1426.                                     MAKELONG((WORD)guWaveInId, TRUE));
  1427.  
  1428.             if (uDevId != guWaveInId)
  1429.             {
  1430.                 guWaveInId = uDevId;
  1431.                 AcmAppDisplayFileProperties(hwnd, &gaafd);
  1432.             }
  1433.             break;
  1434.  
  1435.         case IDM_OPTIONS_WAVEOUTDEVICE:
  1436.             uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd,
  1437.                                     AcmAppWaveDeviceDlgProc,
  1438.                                     MAKELONG((WORD)guWaveOutId, FALSE));
  1439.  
  1440.             if (uDevId != guWaveOutId)
  1441.             {
  1442.                 guWaveOutId = uDevId;
  1443.                 AcmAppDisplayFileProperties(hwnd, &gaafd);
  1444.             }
  1445.             break;
  1446.  
  1447.  
  1448.         case IDM_OPTIONS_AUTOOPEN:
  1449.             gfuAppOptions ^= APP_OPTIONSF_AUTOOPEN;
  1450.             break;
  1451.  
  1452.         case IDM_OPTIONS_DEBUGLOG:
  1453.             gfuAppOptions ^= APP_OPTIONSF_DEBUGLOG;
  1454.             break;
  1455.  
  1456.         case IDM_OPTIONS_FONT:
  1457.             AcmAppChooseFont(hwnd);
  1458.             break;
  1459.  
  1460.  
  1461.         case IDM_PLAYRECORD:
  1462.             if (NULL == gaafd.pwfx)
  1463.             {
  1464.                 f = AppFileNew(hwnd, &gaafd, TRUE);
  1465.                 if (!f)
  1466.                     break;
  1467.  
  1468.                 if (NULL == gaafd.pwfx)
  1469.                     break;
  1470.             }
  1471.  
  1472.             f = DialogBoxParam(ghinst, DLG_AAPLAYRECORD, hwnd,
  1473.                                AcmAppPlayRecord, (LPARAM)(LPVOID)&gaafd);
  1474.             if (f)
  1475.             {
  1476.                 AcmAppFileOpen(hwnd, &gaafd);
  1477.  
  1478.                 AcmAppDisplayFileProperties(hwnd, &gaafd);
  1479.             }
  1480.             break;
  1481.     }
  1482.  
  1483.     return (0L);
  1484. } // AppCommand()
  1485.  
  1486.  
  1487. //--------------------------------------------------------------------------;
  1488. //
  1489. //  BOOL AcmAppDlgProcDragDropContinue
  1490. //
  1491. //  Description:
  1492. //
  1493. //  Arguments:
  1494. //      HWND hwnd: Handle to window.
  1495. //
  1496. //      UINT uMsg: Message being sent to the window.
  1497. //
  1498. //      WPARAM wParam: Specific argument to message.
  1499. //
  1500. //      LPARAM lParam: Specific argument to message.
  1501. //
  1502. //  Return (BOOL):
  1503. //      The return value is specific to the message that was received. For
  1504. //      the most part, it is FALSE if this dialog procedure does not handle
  1505. //      a message.
  1506. //
  1507. //--------------------------------------------------------------------------;
  1508.  
  1509. BOOL FNEXPORT AcmAppDlgProcDragDropContinue
  1510. (
  1511.     HWND                    hwnd,
  1512.     UINT                    uMsg,
  1513.     WPARAM                  wParam,
  1514.     LPARAM                  lParam
  1515. )
  1516. {
  1517.     UINT                uId;
  1518.  
  1519.     switch (uMsg)
  1520.     {
  1521.         case WM_INITDIALOG:
  1522.             AppSetWindowText(hwnd, TEXT("File %u of %u"), LOWORD(lParam), HIWORD(lParam));
  1523.             return (TRUE);
  1524.  
  1525.         case WM_COMMAND:
  1526.             uId = GET_WM_COMMAND_ID(wParam, lParam);
  1527.             if ((IDOK == uId) || (IDCANCEL == uId))
  1528.             {
  1529.                 EndDialog(hwnd, uId);
  1530.             }
  1531.             break;
  1532.     }
  1533.  
  1534.     return (FALSE);
  1535. } // AcmAppDlgProcDragDropContinue()
  1536.  
  1537.  
  1538. //--------------------------------------------------------------------------;
  1539. //
  1540. //  LRESULT AppDropFiles
  1541. //
  1542. //  Description:
  1543. //      This function handles the WM_DROPFILES message. This message is
  1544. //      sent when files are 'dropped' on the window from file manager
  1545. //      (or other drag/drop servers made by ISV's that figured out the
  1546. //      undocumented internal workings of the SHELL).
  1547. //
  1548. //      A window must be registered to receive these messages either by
  1549. //      called DragAcceptFiles() or using CreateWindowEx() with the
  1550. //      WS_EX_ACCEPTFILES style bit.
  1551. //
  1552. //  Arguments:
  1553. //      HWND hwnd: Handle to window receiving the message.
  1554. //
  1555. //      HDROP hdrop: Handle to drop structure.
  1556. //
  1557. //  Return (LRESULT):
  1558. //      Returns 0 if the message is processed.
  1559. //
  1560. //--------------------------------------------------------------------------;
  1561.  
  1562. LRESULT FNLOCAL AppDropFiles
  1563. (
  1564.     HWND                    hwnd,
  1565.     HDROP                   hdrop
  1566. )
  1567. {
  1568.     TCHAR               szFilePath[APP_MAX_FILE_PATH_CHARS];
  1569.     UINT                cFiles;
  1570.     UINT                u;
  1571.     BOOL                f;
  1572.     int                 n;
  1573.  
  1574.     //
  1575.     //  first test for a file that has not been saved. if the return
  1576.     //  value is FALSE we should cancel the drop operation.
  1577.     //
  1578.     f = AcmAppFileSaveModified(hwnd, &gaafd);
  1579.     if (!f)
  1580.     {
  1581.         goto App_Drop_Files_Exit;
  1582.     }
  1583.  
  1584.     //
  1585.     //  get number of files dropped on our window
  1586.     //
  1587.     cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
  1588.  
  1589.     DPF(4, "AppDropFiles(hwnd=%Xh, hdrop=%Xh)--cFiles=%u", hwnd, hdrop, cFiles);
  1590.  
  1591.     //
  1592.     //  step through each file and stop on the one the user wants or
  1593.     //  the last file (whichever comes first).
  1594.     //
  1595.     for (u = 0; u < cFiles; u++)
  1596.     {
  1597.         //
  1598.         //  get the next file name and try to open it--if not a valid
  1599.         //  file, then skip to the next one (if there is one).
  1600.         //
  1601.         DragQueryFile(hdrop, u, szFilePath, SIZEOF(szFilePath));
  1602.  
  1603.  
  1604.         //
  1605.         //  !!! destructive !!!
  1606.         //
  1607.         //  attempt to open the file
  1608.         //
  1609.         lstrcpy(gaafd.szFilePath, szFilePath);
  1610.         lstrcpy(gaafd.szFileTitle, gszNull);
  1611.  
  1612.         f = AcmAppFileOpen(hwnd, &gaafd);
  1613.         if (!f)
  1614.         {
  1615.             continue;
  1616.         }
  1617.  
  1618.         AppTitle(hwnd, gaafd.szFileTitle);
  1619.         AcmAppDisplayFileProperties(hwnd, &gaafd);
  1620.  
  1621.         //
  1622.         //  if this is NOT the last file in the list of files that are
  1623.         //  being dropped on us, then bring up a box asking if we should
  1624.         //  continue or stop where we are..
  1625.         //
  1626.         if ((cFiles - 1) != u)
  1627.         {
  1628.             n = DialogBoxParam(ghinst,
  1629.                                DLG_AADRAGDROP,
  1630.                                hwnd,
  1631.                                AcmAppDlgProcDragDropContinue,
  1632.                                MAKELPARAM((WORD)(u + 1), (WORD)cFiles));
  1633.             if (IDCANCEL == n)
  1634.                 break;
  1635.         }
  1636.     }
  1637.  
  1638.     //
  1639.     //  tell the shell to release the memory it allocated for beaming
  1640.     //  the file name(s) over to us... return 0 to show we processed
  1641.     //  the message.
  1642.     //
  1643. App_Drop_Files_Exit:
  1644.  
  1645.     DragFinish(hdrop);
  1646.     return (0L);
  1647. } // AppDropFiles()
  1648.  
  1649.  
  1650. //--------------------------------------------------------------------------;
  1651. //
  1652. //  LRESULT AppSize
  1653. //
  1654. //  Description:
  1655. //      This function handles the WM_SIZE message for the application's
  1656. //      window. This message is sent to the application window after the
  1657. //      size has changed (but before it is painted).
  1658. //
  1659. //  Arguments:
  1660. //      HWND hwnd: Handle to window that generated the WM_SIZE message.
  1661. //
  1662. //      UINT fuSizeType: Specifies the type of resizing requested. This
  1663. //      argument is one of the following: SIZE_MAXIMIZED, SIZE_MINIMIZED,
  1664. //      SIZE_RESTORED, SIZE_MAXHIDE, or SIZE_MAXSHOW.
  1665. //
  1666. //      int nWidth: Width of the new client area for the window.
  1667. //
  1668. //      int nHeight: Height of the new client area for the window.
  1669. //
  1670. //  Return (LRESULT):
  1671. //      Returns zero if the application processes the message.
  1672. //
  1673. //--------------------------------------------------------------------------;
  1674.  
  1675. LRESULT FNLOCAL AppSize
  1676. (
  1677.     HWND                    hwnd,
  1678.     UINT                    fuSizeType,
  1679.     int                     nWidth,
  1680.     int                     nHeight
  1681. )
  1682. {
  1683.     HWND                hedit;
  1684.     RECT                rc;
  1685.  
  1686.     DPF(4, "AppSize(hwnd=%Xh, fuSizeType=%u, nWidth=%d, nHeight=%d)",
  1687.             hwnd, fuSizeType, nWidth, nHeight);
  1688.  
  1689.     //
  1690.     //  unless this application is the one being resized then don't waste
  1691.     //  time computing stuff that doesn't matter. this applies to being
  1692.     //  minimized also because this application does not have a custom
  1693.     //  minimized state.
  1694.     //
  1695.     if ((SIZE_RESTORED != fuSizeType) && (SIZE_MAXIMIZED != fuSizeType))
  1696.         return (0L);
  1697.  
  1698.  
  1699.     //
  1700.     //
  1701.     //
  1702.     GetClientRect(hwnd, &rc);
  1703.     InflateRect(&rc, 1, 1);
  1704.  
  1705.     hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1706.     SetWindowPos(hedit,
  1707.                  NULL,
  1708.                  rc.left,
  1709.                  rc.top,
  1710.                  rc.right - rc.left,
  1711.                  rc.bottom - rc.top,
  1712.                  SWP_NOZORDER);
  1713.  
  1714.  
  1715.     //
  1716.     //  we processed the message..
  1717.     //
  1718.     return (0L);
  1719. } // AppSize()
  1720.  
  1721.  
  1722. //--------------------------------------------------------------------------;
  1723. //  
  1724. //  LRESULT AcmAppNotify
  1725. //  
  1726. //  Description:
  1727. //  
  1728. //  
  1729. //  Arguments:
  1730. //  
  1731. //  Return (LRESULT):
  1732. //  
  1733. //  
  1734. //--------------------------------------------------------------------------;
  1735.  
  1736. LRESULT FNLOCAL AcmAppNotify
  1737. (
  1738.     HWND                hwnd,
  1739.     WPARAM              wParam,
  1740.     LPARAM              lParam
  1741. )
  1742. {
  1743.     HWND                hwndNext;
  1744.  
  1745.     DPF(1, "AcmAppNotify: hwnd=%.04Xh, wParam=%.04Xh, lParam2=%.08lXh",
  1746.         hwnd, wParam, lParam);
  1747.  
  1748.     //
  1749.     //
  1750.     //
  1751.     hwndNext = GetWindow(hwnd, GW_HWNDFIRST);
  1752.     while (NULL != hwndNext)
  1753.     {
  1754.         if (GetParent(hwndNext) == hwnd)
  1755.         {
  1756.             SendMessage(hwndNext, WM_ACMAPP_ACM_NOTIFY, wParam, lParam);
  1757.         }
  1758.  
  1759.         hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
  1760.     }
  1761.  
  1762.  
  1763.     //
  1764.     //  now force an update to our display in case driver [dis/en]able
  1765.     //  changed what is playable/recordable.
  1766.     //
  1767.     AcmAppDisplayFileProperties(hwnd, &gaafd);
  1768.  
  1769.  
  1770.     //
  1771.     //
  1772.     //
  1773.     return (1L);
  1774. } // AcmAppNotify()
  1775.  
  1776.  
  1777. //--------------------------------------------------------------------------;
  1778. //
  1779. //  LRESULT AppWndProc
  1780. //
  1781. //  Description:
  1782. //      This is the main application window procedure.
  1783. //
  1784. //  Arguments:
  1785. //      HWND hwnd: Handle to window.
  1786. //
  1787. //      UINT uMsg: Message being sent to the window.
  1788. //
  1789. //      WPARAM wParam: Specific argument to message.
  1790. //
  1791. //      LPARAM lParam: Specific argument to message.
  1792. //
  1793. //  Return (LRESULT):
  1794. //      The return value depends on the message that is being processed.
  1795. //
  1796. //--------------------------------------------------------------------------;
  1797.  
  1798. LRESULT FNEXPORT AppWndProc
  1799. (
  1800.     HWND                    hwnd,
  1801.     UINT                    uMsg,
  1802.     WPARAM                  wParam,
  1803.     LPARAM                  lParam
  1804. )
  1805. {
  1806.     LRESULT             lr;
  1807.  
  1808.     switch (uMsg)
  1809.     {
  1810.         case WM_CREATE:
  1811.             lr = HANDLE_WM_CREATE(hwnd, wParam, lParam, AppCreate);
  1812.             return (lr);
  1813.  
  1814.         case WM_WININICHANGE:
  1815.             HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, AppWinIniChange);
  1816.             return (0L);
  1817.  
  1818.         case WM_INITMENUPOPUP:
  1819.             HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, AppInitMenuPopup);
  1820.             return (0L);
  1821.  
  1822.         case WM_COMMAND:
  1823.             lr = HANDLE_WM_COMMAND(hwnd, wParam, lParam, AppCommand);
  1824.             return (lr);
  1825.  
  1826.         case WM_DROPFILES:
  1827.             //
  1828.             //  some windowsx.h files have a screwed up message cracker for
  1829.             //  WM_DROPFILES. because this is a sample app, i don't want
  1830.             //  people having trouble with bogus windowsx.h files, so crack
  1831.             //  the message manually... you should use the message cracker
  1832.             //  if you know your windowsx.h file is good.
  1833.             //
  1834.             //  lr = HANDLE_WM_DROPFILES(hwnd, wParam, lParam, AppDropFiles);
  1835.             //
  1836.             lr = AppDropFiles(hwnd, (HDROP)wParam);
  1837.             return (lr);
  1838.  
  1839.         case WM_SIZE:
  1840.             //
  1841.             //  handle what we want for sizing, and then always call the
  1842.             //  default handler...
  1843.             //
  1844.             HANDLE_WM_SIZE(hwnd, wParam, lParam, AppSize);
  1845.             break;
  1846.  
  1847.         case WM_QUERYENDSESSION:
  1848.             lr = HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, AppQueryEndSession);
  1849.             return (lr);
  1850.  
  1851.         case WM_ENDSESSION:
  1852.             HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, AppEndSession);
  1853.             return (0L);
  1854.  
  1855.         case WM_CLOSE:
  1856.             HANDLE_WM_CLOSE(hwnd, wParam, lParam, AppClose);
  1857.             return (0L);
  1858.  
  1859.         case WM_DESTROY:
  1860.             PostQuitMessage(0);
  1861.             return (0L);
  1862.  
  1863.         case WM_ACMAPP_ACM_NOTIFY:
  1864.             AcmAppNotify(hwnd, wParam, lParam);
  1865.             return (0L);
  1866.     }
  1867.  
  1868.     return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1869. } // AppWndProc()
  1870.  
  1871.  
  1872. //==========================================================================;
  1873. //
  1874. //  Main entry and message dispatching code
  1875. //
  1876. //
  1877. //==========================================================================;
  1878.  
  1879. //--------------------------------------------------------------------------;
  1880. //
  1881. //  int WinMain
  1882. //
  1883. //  Description:
  1884. //      This function is called by the system as the initial entry point
  1885. //      for a Windows application.
  1886. //
  1887. //  Arguments:
  1888. //      HINSTANCE hinst: Identifies the current instance of the
  1889. //      application.
  1890. //
  1891. //      HINSTANCE hinstPrev: Identifies the previous instance of the
  1892. //      application (NULL if first instance). For Win 32, this argument
  1893. //      is _always_ NULL.
  1894. //
  1895. //      LPSTR pszCmdLine: Points to null-terminated unparsed command line.
  1896. //      This string is strictly ANSI regardless of whether the application
  1897. //      is built for Unicode. To get the Unicode equivalent call the
  1898. //      GetCommandLine() function (Win 32 only).
  1899. //
  1900. //      int nCmdShow: How the main window for the application is to be
  1901. //      shown by default.
  1902. //
  1903. //  Return (int):
  1904. //      Returns result from WM_QUIT message (in wParam of MSG structure) if
  1905. //      the application is able to enter its message loop. Returns 0 if
  1906. //      the application is not able to enter its message loop.
  1907. //
  1908. //--------------------------------------------------------------------------;
  1909.  
  1910. int PASCAL WinMain
  1911. (
  1912.     HINSTANCE               hinst,
  1913.     HINSTANCE               hinstPrev,
  1914.     LPSTR                   pszCmdLine,
  1915.     int                     nCmdShow
  1916. )
  1917. {
  1918.     int                 nResult;
  1919.     HWND                hwnd;
  1920.     MSG                 msg;
  1921.     HACCEL              haccl;
  1922.  
  1923.     DbgInitialize(TRUE);
  1924.  
  1925.     //
  1926.     //  our documentation states that WinMain is supposed to return 0 if
  1927.     //  we do not enter our message loop--so assume the worst...
  1928.     //
  1929.     nResult = 0;
  1930.  
  1931.     //
  1932.     //  make our instance handle global for convenience..
  1933.     //
  1934.     ghinst = hinst;
  1935.  
  1936.     //
  1937.     //  init some stuff, create window, etc.. note the explicit cast of
  1938.     //  pszCmdLine--this is to mute a warning (and an ugly ifdef) when
  1939.     //  compiling for Unicode. see AppInit() for more details.
  1940.     //
  1941.     hwnd = AppInit(hinst, hinstPrev, (LPTSTR)pszCmdLine, nCmdShow);
  1942.     if (hwnd)
  1943.     {
  1944.         haccl = LoadAccelerators(hinst, ACCEL_APP);
  1945.  
  1946.         //
  1947.         //  dispatch messages
  1948.         //
  1949.         while (GetMessage(&msg, NULL, 0, 0))
  1950.         {
  1951.             //
  1952.             //  do all the special stuff required for this application
  1953.             //  when dispatching messages..
  1954.             //
  1955.             if (!TranslateAccelerator(hwnd, haccl, &msg))
  1956.             {
  1957.                 TranslateMessage(&msg);
  1958.                 DispatchMessage(&msg);
  1959.             }
  1960.         }
  1961.  
  1962.         //
  1963.         //  return result of WM_QUIT message.
  1964.         //
  1965.         nResult = (int)msg.wParam;
  1966.     }
  1967.  
  1968.     //
  1969.     //  shut things down, clean up, etc.
  1970.     //
  1971.     nResult = AppExit(hinst, nResult);
  1972.  
  1973.     return (nResult);
  1974. } // WinMain()
  1975.