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

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