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 / mixapp / mainit.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  39KB  |  1,330 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) 1993 - 1997  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  mainit.c
  13. //
  14. //  Description:
  15. //
  16. //
  17. //  History:
  18. //       9/21/93
  19. //
  20. //==========================================================================;
  21.  
  22. #include <windows.h>
  23. #include <windowsx.h>
  24. #include <mmsystem.h>
  25. #include <commdlg.h>
  26.  
  27. #include "mixapp.h"
  28.  
  29. #include "debug.h"
  30.  
  31.  
  32.  
  33. //
  34. //
  35. //
  36. TCHAR       gszAppProfile[]     = TEXT("mixapp.ini");
  37.  
  38. TCHAR       gszSecConfig[]      = TEXT("Configuration");
  39.  
  40. TCHAR       gszKeyOptions[]     = TEXT("Options");
  41. TCHAR       gszFormatOptions[]  = TEXT("%u");
  42.  
  43. TCHAR       gszKeyWindow[]      = TEXT("Window");
  44. TCHAR       gszKeyFont[]        = TEXT("Font");
  45.  
  46.  
  47. //==========================================================================;
  48. //
  49. //
  50. //
  51. //
  52. //==========================================================================;
  53.  
  54. //--------------------------------------------------------------------------;
  55. //
  56. //  BOOL AppProfileWriteBytes
  57. //
  58. //  Description:
  59. //      This function writes a raw structure of bytes to the application's
  60. //      ini section that can later be retrieved using AppProfileReadBytes.
  61. //      This gives an application the ability to write any structure to
  62. //      the ini file and restore it later--very useful.
  63. //
  64. //      NOTE! Starting with Windows for Workgroups 3.1 there are two new
  65. //      profile functions that provide the same functionality of this
  66. //      function. Specifically, these functions are GetPrivateProfileStruct
  67. //      and WritePrivateProfileStruct. These new functions are provided
  68. //      by the Common Controls DLL. The prototypes are as follows:
  69. //
  70. //      BOOL GetPrivateProfileStruct
  71. //      (
  72. //          LPSTR       szSection,
  73. //          LPSTR       szKey,
  74. //          LPBYTE      lpStruct,
  75. //          UINT        uSizeStruct,
  76. //          LPSTR       szFile
  77. //      );
  78. //
  79. //      BOOL WritePrivateProfileStruct
  80. //      (
  81. //          LPSTR       szSection,
  82. //          LPSTR       szKey,
  83. //          LPBYTE      lpStruct,
  84. //          UINT        uSizeStruct,
  85. //          LPSTR       szFile
  86. //      );
  87. //
  88. //      If you are building an application that is for Window for Workgroups
  89. //      or newer versions of Windows, you will probably want to use the
  90. //      above functions.
  91. //
  92. //  Arguments:
  93. //      PTSTR pszSection: Pointer to section for the stored data.
  94. //
  95. //      PTSTR pszKey: Pointer to key name for the stored data.
  96. //
  97. //      LPBYTE pbStruct: Pointer to the data to be saved.
  98. //
  99. //      UINT cbStruct: Count in bytes of the data to store.
  100. //
  101. //  Return (BOOL):
  102. //      The return value is TRUE if the function is successful. It is FALSE
  103. //      if it fails.
  104. //
  105. //  History:
  106. //       3/10/93
  107. //
  108. //--------------------------------------------------------------------------;
  109.  
  110. BOOL FNGLOBAL AppProfileWriteBytes
  111. (
  112.     PTSTR                   pszSection,
  113.     PTSTR                   pszKey,
  114.     LPBYTE                  pbStruct,
  115.     UINT                    cbStruct
  116. )
  117. {
  118.     static TCHAR achNibbleToChar[] =
  119.     {
  120.         '0', '1', '2', '3', '4', '5', '6', '7',
  121.         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  122.     };
  123.     #define     NIBBLE2CHAR(x)      (achNibbleToChar[x])
  124.  
  125.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  126.     LPTSTR      psz;
  127.     LPTSTR      pch;
  128.     UINT        cchTemp;
  129.     BOOL        fAllocated;
  130.     BOOL        fReturn;
  131.     BYTE        b;
  132.     BYTE        bChecksum;
  133.  
  134.     //
  135.     //  if pbStruct is NULL, then erase the key from the ini file, otherwise
  136.     //  format the raw bytes into a hex string and write that out...
  137.     //
  138.     fAllocated = FALSE;
  139.     psz        = NULL;
  140.     if (NULL != pbStruct)
  141.     {
  142.         //
  143.         //  check if the quick buffer can be used for formatting the output
  144.         //  text--if it cannot, then alloc space for it. note that space
  145.         //  must be available for an ending checksum byte (2 bytes for high
  146.         //  and low nibble) as well as a null terminator.
  147.         //
  148.         psz     = (LPTSTR)ach;
  149.         cchTemp = cbStruct * 2 + 3;
  150.         if (cchTemp > SIZEOF(ach))
  151.         {
  152.             psz = (LPTSTR)GlobalAllocPtr(GHND, cchTemp * sizeof(TCHAR));
  153.             if (NULL == psz)
  154.                 return (FALSE);
  155.  
  156.             fAllocated = TRUE;
  157.         }
  158.  
  159.         //
  160.         //  step through all bytes in the structure and convert it to
  161.         //  a string of hex numbers...
  162.         //
  163.         bChecksum = 0;
  164.         for (pch = psz; 0 != cbStruct; cbStruct--, pbStruct++)
  165.         {
  166.             //
  167.             //  grab the next byte and add into checksum...
  168.             //
  169.             bChecksum = (BYTE) (bChecksum + (b = *pbStruct));
  170.  
  171.             *pch++ = NIBBLE2CHAR((b >> (BYTE)4) & (BYTE)0x0F);
  172.             *pch++ = NIBBLE2CHAR(b & (BYTE)0x0F);
  173.         }
  174.  
  175.         //
  176.         //  add the checksum byte to the end and null terminate the hex
  177.         //  dumped string...
  178.         //
  179.         *pch++ = NIBBLE2CHAR((bChecksum >> (BYTE)4) & (BYTE)0x0F);
  180.         *pch++ = NIBBLE2CHAR(bChecksum & (BYTE)0x0F);
  181.         *pch   = '\0';
  182.     }
  183.  
  184.     //
  185.     //  write the string of hex bytes out to the ini file...
  186.     //
  187.     fReturn = WritePrivateProfileString(pszSection, pszKey, psz, gszAppProfile);
  188.  
  189.     //
  190.     //  free the temporary buffer if one was allocated (lots of bytes!)
  191.     //
  192.     if (fAllocated)
  193.         GlobalFreePtr(psz);
  194.  
  195.     return (fReturn);
  196. } // AppProfileWriteBytes
  197.  
  198.  
  199. //--------------------------------------------------------------------------;
  200. //
  201. //  BOOL AppProfileReadBytes
  202. //
  203. //  Description:
  204. //      This function reads a previously stored structure of bytes from
  205. //      the application's ini file. This data must have been written with
  206. //      the AppProfileWriteBytes function--it is checksumed to keep bad
  207. //      data from blowing up the application.
  208. //
  209. //      NOTE! Starting with Windows for Workgroups 3.1 there are two new
  210. //      profile functions that provide the same functionality of this
  211. //      function. Specifically, these functions are GetPrivateProfileStruct
  212. //      and WritePrivateProfileStruct. These new functions are provided
  213. //      by the Common Controls DLL. The prototypes are as follows:
  214. //
  215. //      BOOL GetPrivateProfileStruct
  216. //      (
  217. //          LPSTR       szSection,
  218. //          LPSTR       szKey,
  219. //          LPBYTE      lpStruct,
  220. //          UINT        uSizeStruct,
  221. //          LPSTR       szFile
  222. //      );
  223. //
  224. //      BOOL WritePrivateProfileStruct
  225. //      (
  226. //          LPSTR       szSection,
  227. //          LPSTR       szKey,
  228. //          LPBYTE      lpStruct,
  229. //          UINT        uSizeStruct,
  230. //          LPSTR       szFile
  231. //      );
  232. //
  233. //      If you are building an application that is for Window for Workgroups
  234. //      or newer versions of Windows, you will probably want to use the
  235. //      above functions.
  236. //
  237. //  Arguments:
  238. //      PTSTR pszSection: Pointer to section that contains the data.
  239. //
  240. //      PTSTR pszKey: Pointer to key that contains the data.
  241. //
  242. //      LPBYTE pbStruct: Pointer to buffer to receive the data.
  243. //
  244. //      UINT cbStruct: Number of bytes expected.
  245. //
  246. //  Return (BOOL):
  247. //      The return value is TRUE if the function is successful. It is FALSE
  248. //      if the function fails (bad checksum, missing key, etc).
  249. //
  250. //  History:
  251. //       3/10/93
  252. //
  253. //--------------------------------------------------------------------------;
  254.  
  255. BOOL FNGLOBAL AppProfileReadBytes
  256. (
  257.     PTSTR                   pszSection,
  258.     PTSTR                   pszKey,
  259.     LPBYTE                  pbStruct,
  260.     UINT                    cbStruct
  261. )
  262. {
  263.     //
  264.     //  note that the following works for both upper and lower case, and
  265.     //  will return valid values for garbage chars
  266.     //
  267.     #define CHAR2NIBBLE(ch) (BYTE)( ((ch) >= '0' && (ch) <= '9') ?  \
  268.                                 (BYTE)((ch) - '0') :                \
  269.                                 ((BYTE)(10 + (ch) - 'A') & (BYTE)0x0F) )
  270.  
  271.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  272.     LPTSTR      psz;
  273.     LPTSTR      pch;
  274.     UINT        cchTemp;
  275.     UINT        u;
  276.     BOOL        fAllocated;
  277.     BOOL        fReturn;
  278.     BYTE        b;
  279.     BYTE        bChecksum;
  280.     TCHAR       ch;
  281.  
  282.     //
  283.     //  add one the the number of bytes needed to accomodate the checksum
  284.     //  byte placed at the end by AppProfileWriteBytes...
  285.     //
  286.     cbStruct++;
  287.  
  288.     //
  289.     //  check if the quick buffer can be used for retrieving the input
  290.     //  text--if it cannot, then alloc space for it. note that there must
  291.     //  be space available for the null terminator (the +1 below).
  292.     //
  293.     fAllocated = FALSE;
  294.     psz        = (LPTSTR)ach;
  295.     cchTemp    = cbStruct * 2 + 1;
  296.     if (cchTemp > SIZEOF(ach))
  297.     {
  298.         psz = (LPTSTR)GlobalAllocPtr(GHND, cchTemp * sizeof(TCHAR));
  299.         if (NULL == psz)
  300.             return (FALSE);
  301.  
  302.         fAllocated = TRUE;
  303.     }
  304.  
  305.     //
  306.     //  read the hex string... if it is not the correct length, then assume
  307.     //  error and return.
  308.     //
  309.     fReturn = FALSE;
  310.     u = (UINT)GetPrivateProfileString(pszSection, pszKey, gszNull,
  311.                                       psz, cchTemp, gszAppProfile);
  312.     if ((cbStruct * 2) == u)
  313.     {
  314.         bChecksum = 0;
  315.         for (pch = psz; 0 != cbStruct; cbStruct--, pbStruct++)
  316.         {
  317.             ch = *pch++;
  318.             b  = (BYTE) (CHAR2NIBBLE(ch) << (BYTE)4);
  319.             ch = *pch++;
  320.             b |= CHAR2NIBBLE(ch);
  321.  
  322.             //
  323.             //  if this is not the final byte (the checksum byte), then
  324.             //  store it and accumulate checksum..
  325.             //
  326.             if (cbStruct != 1)
  327.                 bChecksum = (BYTE) (bChecksum + (*pbStruct = b));
  328.         }
  329.  
  330.         //
  331.         //  check the last byte read against the checksum that we calculated
  332.         //  if they are not equal then return error...
  333.         //
  334.         fReturn = (bChecksum == b);
  335.     }
  336.  
  337.  
  338.     //
  339.     //  free the temporary buffer if one was allocated (lots of bytes!)
  340.     //
  341.     if (fAllocated)
  342.         GlobalFreePtr(psz);
  343.  
  344.     return (fReturn);
  345. } // AppProfileReadBytes
  346.  
  347.  
  348. //--------------------------------------------------------------------------;
  349. //
  350. //  DWORD AppGetWindowsVersion
  351. //
  352. //  Description:
  353. //      This function returns the version of Windows that the application
  354. //      is running on plus some platform information.
  355. //
  356. //  Arguments:
  357. //      PTSTR pach: Options pointer to buffer to receive text string of
  358. //      the Windows version and platform.
  359. //
  360. //  Return (LRESULT):
  361. //      The return value will be the version and platform information of
  362. //      the current operating system in the following format:
  363. //
  364. //      0xPPPPMMRR where:
  365. //
  366. //      MM      :   major version of Windows
  367. //      RR      :   minor version (revision) of Windows
  368. //      PPPP    :   the platform the application is running on which
  369. //                  the HIWORD() is RESERVED except for the high bit:
  370. //                      high bit is 0 = Windows NT
  371. //                      high bit is 1 = Win32s/Windows 3.1
  372. //
  373. //
  374. //--------------------------------------------------------------------------;
  375.  
  376. LRESULT FNLOCAL AppGetWindowsVersion
  377. (
  378.     PTSTR                   pszEnvironment,
  379.     PTSTR                   pszPlatform
  380. )
  381. {
  382.  
  383.     BYTE    bVerWinMajor;
  384.     BYTE    bVerWinMinor;
  385.     UINT    uVerEnv;
  386.     DWORD   dw;
  387.     LRESULT lr;
  388.  
  389.     dw = GetVersion();
  390.  
  391.     //
  392.     //  massage the version information into something intelligent
  393.     //
  394.     //
  395.     bVerWinMajor = LOBYTE(LOWORD(dw));
  396.     bVerWinMinor = HIBYTE(LOWORD(dw));
  397.     uVerEnv      = HIWORD(dw);
  398.     lr = MAKELPARAM(((UINT)bVerWinMajor << 8) | bVerWinMinor, uVerEnv);
  399.  
  400.     //
  401.     //  if caller wants the environment string version...
  402.     //
  403.     if (NULL != pszEnvironment)
  404.     {
  405.         static TCHAR    szFormatVersion[]   = TEXT("Win32 Version %u.%.2u");
  406.  
  407.         wsprintf(pszEnvironment, szFormatVersion,
  408.                  bVerWinMajor, bVerWinMinor);
  409.     }
  410.  
  411.     //
  412.     //  if caller wants the platform string version...
  413.     //
  414.     if (NULL != pszPlatform)
  415.     {
  416.         static TCHAR    szFormatPlatform[]  = TEXT("%s%u, %u Processor(s)");
  417.         static TCHAR    szProcessorIntel[]  = TEXT("Intel ");
  418.         static TCHAR    szProcessorMIPS[]   = TEXT("MIPS R");
  419.         static TCHAR    szProcessorAlpha[]  = TEXT("DEC Alpha ");
  420.         static TCHAR    szProcessorDunno[]  = TEXT("Dunno zYz");
  421.  
  422.         SYSTEM_INFO sysinfo;
  423.         PTSTR       pszProcessor;
  424.  
  425.         //
  426.         //  this is absolutely silly. one would think that the dwOemId member
  427.         //  would provide something useful like the processor class... but
  428.         //  no, it doesn't--it is always 0.
  429.         //
  430.         GetSystemInfo(&sysinfo);
  431.         switch (sysinfo.dwProcessorType)
  432.         {
  433.             case PROCESSOR_INTEL_386:
  434.             case PROCESSOR_INTEL_486:
  435.                 pszProcessor = szProcessorIntel;
  436.                 break;
  437.  
  438.             case PROCESSOR_MIPS_R4000:
  439.                 pszProcessor = szProcessorMIPS;
  440.                 break;
  441.  
  442.             case PROCESSOR_ALPHA_21064:
  443.                 pszProcessor = szProcessorAlpha;
  444.                 break;
  445.  
  446.             default:
  447.                 pszProcessor = szProcessorDunno;
  448.                 break;
  449.         }
  450.  
  451.         //
  452.         //
  453.         //
  454.         wsprintf(pszPlatform, szFormatPlatform, (LPSTR)pszProcessor,
  455.                  sysinfo.dwProcessorType, sysinfo.dwNumberOfProcessors);
  456.     }
  457.  
  458.     //
  459.     //  return the result
  460.     //
  461.     return (lr);
  462. } // AppGetWindowsVersion()
  463.  
  464.  
  465. //--------------------------------------------------------------------------;
  466. //
  467. //  HFONT AppChooseFont
  468. //
  469. //  Description:
  470. //      This function is a wrapper for the ChooseFont() common dialog.
  471. //      The purpose of this function is to let the user choose a font that
  472. //      looks good to them--regardless of how stupid it really looks.
  473. //
  474. //  Arguments:
  475. //      HWND hwnd: Handle to parent window for chooser dialog.
  476. //
  477. //      HFONT hfont: Handle to current font (default for chooser dialog).
  478. //
  479. //      PLOGFONT plf: Pointer to optional LOGFONT structure to receive a
  480. //      copy of the LOGFONT information for the newly chosen font.
  481. //
  482. //  Return (HFONT):
  483. //      The return value is the newly chosen font. If no new font was chosen
  484. //      then the return value is NULL.
  485. //
  486. //--------------------------------------------------------------------------;
  487.  
  488. HFONT FNGLOBAL AppChooseFont
  489. (
  490.     HWND                    hwnd,
  491.     HFONT                   hfont,
  492.     PLOGFONT                plf
  493. )
  494. {
  495.     LOGFONT             lf;
  496.     CHOOSEFONT          cf;
  497.     BOOL                f;
  498.     HFONT               hfontNew;
  499.  
  500.     //
  501.     //  get the font info for the current font...
  502.     //
  503.     GetObject(hfont, sizeof(LOGFONT), (LPVOID)&lf);
  504.  
  505.     //
  506.     //  fill in the choosefont structure
  507.     //
  508.     cf.lStructSize  = sizeof(CHOOSEFONT);
  509.     cf.hwndOwner    = hwnd;
  510.     cf.hDC          = NULL;
  511.     cf.Flags        = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
  512.     cf.lCustData    = 0;
  513.     cf.lpfnHook     = NULL;
  514.     cf.hInstance    = NULL;
  515.     cf.nFontType    = SCREEN_FONTTYPE;
  516.     cf.lpLogFont    = (LPLOGFONT)&lf;
  517.  
  518.     //
  519.     //  splash a dialog into the user's face..
  520.     //
  521.     hfontNew = NULL;
  522.     f = ChooseFont(&cf);
  523.     if (f)
  524.     {
  525.         //
  526.         //  create the new font..
  527.         //
  528.         hfontNew = CreateFontIndirect(&lf);
  529.         if (NULL == hfontNew)
  530.             return (NULL);
  531.  
  532.         //
  533.         //  copy the logfont structure if caller wants it
  534.         //
  535.         if (NULL != plf)
  536.             *plf = lf;
  537.     }
  538.  
  539.     //
  540.     //  return the new font (if one was chosen)
  541.     //
  542.     return (hfontNew);
  543. } // AppChooseFont()
  544.  
  545.  
  546. //==========================================================================;
  547. //
  548. //  Misc rarely used application dialogs and stuff...
  549. //
  550. //
  551. //==========================================================================;
  552.  
  553. //--------------------------------------------------------------------------;
  554. //
  555. //  BOOL AboutDlgProc
  556. //
  557. //  Description:
  558. //      This dialog procedure is used for the ubiquitous about box.
  559. //
  560. //  Arguments:
  561. //      HWND hwnd: Handle to window.
  562. //
  563. //      UINT uMsg: Message being sent to the window.
  564. //
  565. //      WPARAM wParam: Specific argument to message.
  566. //
  567. //      LPARAM lParam: Specific argument to message.
  568. //
  569. //  Return (BOOL):
  570. //      The return value is specific to the message that was received. For
  571. //      the most part, it is FALSE if this dialog procedure does not handle
  572. //      a message.
  573. //
  574. //  History:
  575. //       1/ 2/93
  576. //
  577. //--------------------------------------------------------------------------;
  578.  
  579. BOOL CALLBACK AboutDlgProc
  580. (
  581.     HWND                    hwnd,
  582.     UINT                    uMsg,
  583.     WPARAM                  wParam,
  584.     LPARAM                  lParam
  585. )
  586. {
  587.     HWND                hwndT;
  588.     PTSTR               pach;
  589.     UINT                u;
  590.  
  591.     switch (uMsg)
  592.     {
  593.         case WM_INITDIALOG:
  594.             //
  595.             //  display some OS version information
  596.             //
  597.             //
  598.             pach = (PTSTR)LocalAlloc(LPTR, APP_MAX_STRING_RC_BYTES);
  599.             if (NULL == pach)
  600.                 return (TRUE);
  601.  
  602.             AppGetWindowsVersion(pach, NULL);
  603.             hwndT = GetDlgItem(hwnd, IDD_ABOUT_VERSION_OS);
  604.             SetWindowText(hwndT, pach);
  605.  
  606.             AppGetWindowsVersion(NULL, pach);
  607.             hwndT = GetDlgItem(hwnd, IDD_ABOUT_VERSION_PLATFORM);
  608.             SetWindowText(hwndT, pach);
  609.             LocalFree((HLOCAL)pach);
  610.             return (TRUE);
  611.  
  612.         case WM_COMMAND:
  613.             u = GET_WM_COMMAND_ID(wParam, lParam);
  614.             if ((IDOK == u) || (IDCANCEL == u))
  615.             {
  616.                 EndDialog(hwnd, (IDOK == u));
  617.             }
  618.             break;
  619.     }
  620.  
  621.     return (FALSE);
  622. } // AboutDlgProc()
  623.  
  624.  
  625. //==========================================================================;
  626. //
  627. //  Initialization and exit code...
  628. //
  629. //
  630. //==========================================================================;
  631.  
  632. //--------------------------------------------------------------------------;
  633. //
  634. //  BOOL MixAppChooseFont
  635. //
  636. //  Description:
  637. //      This function lets the user choose a new font for the script window.
  638. //      After a new font is chosen, the font structure is stored to the
  639. //      .ini file so it can be restored on the next run of this application.
  640. //
  641. //  Arguments:
  642. //      HWND hwnd: Handle to main window.
  643. //
  644. //  Return (BOOL):
  645. //      The return value is TRUE if a new font was chosen. It is FALSE if
  646. //      the user canceled the operation.
  647. //
  648. //  History:
  649. //       2/ 7/93
  650. //
  651. //--------------------------------------------------------------------------;
  652.  
  653. BOOL FNGLOBAL MixAppChooseFont
  654. (
  655.     HWND                    hwnd
  656. )
  657. {
  658.     LOGFONT             lf;
  659.     HWND                hlb;
  660.     HFONT               hfont;
  661.     HFONT               hfontNew;
  662.  
  663.  
  664.     //
  665.     //  get the current font and pass it to the choose font dialog
  666.     //
  667.     hlb   = GetDlgItem(hwnd, IDD_APP_LIST_LINES);
  668.     hfont = GetWindowFont(hlb);
  669.  
  670.     hfontNew = AppChooseFont(hwnd, hfont, &lf);
  671.     if (NULL == hfontNew)
  672.         return (FALSE);
  673.  
  674.     //
  675.     //  select the new font into the script window and delete the old one
  676.     //
  677.     TlbSetFont(gptlbLines, hfontNew, TRUE);
  678.     DeleteFont(hfont);
  679.  
  680.  
  681.     //
  682.     //  save the complete description of the chosen font so there can be
  683.     //  no strangness in the font mapping next run. this is overkill, but
  684.     //  it works...
  685.     //
  686.     AppProfileWriteBytes(gszSecConfig, gszKeyFont, (LPBYTE)&lf, sizeof(lf));
  687.  
  688.     return (TRUE);
  689. } // MixAppChooseFont()
  690.  
  691.  
  692. //--------------------------------------------------------------------------;
  693. //
  694. //  BOOL MixAppSettingsRestore
  695. //
  696. //  Description:
  697. //      This function restores state information for the application. This
  698. //      function is called just after the main window is created (it has
  699. //      not been ShowWindow()'d). This function will generate the call
  700. //      to ShowWindow before returning.
  701. //
  702. //  Arguments:
  703. //      HWND hwnd: Handle to main window that has just been created but
  704. //      not shown.
  705. //
  706. //      int nCmdShow: The state that the application window should show as.
  707. //
  708. //  Return (BOOL):
  709. //      The return value is always TRUE.
  710. //
  711. //  History:
  712. //      05/11/93
  713. //
  714. //--------------------------------------------------------------------------;
  715.  
  716. BOOL FNLOCAL MixAppSettingsRestore
  717. (
  718.     HWND                    hwnd,
  719.     int                     nCmdShow
  720. )
  721. {
  722.     WINDOWPLACEMENT     wp;
  723.     HFONT               hfont;
  724.     LOGFONT             lf;
  725.     RECT                rc;
  726.     RECT                rcWindow;
  727.     POINT               pt;
  728.     int                 n;
  729.     BOOL                f;
  730.  
  731.  
  732.     //
  733.     //  restore the user's preferred font.
  734.     //
  735.     hfont = NULL;
  736.     f = AppProfileReadBytes(gszSecConfig, gszKeyFont, (LPBYTE)&lf, sizeof(lf));
  737.     if (f)
  738.     {
  739.         hfont = CreateFontIndirect(&lf);
  740.     }
  741.  
  742.     if (NULL == hfont)
  743.     {
  744.         hfont = GetStockFont(SYSTEM_FONT);
  745.     }
  746.  
  747.     TlbSetFont(gptlbLines, hfont, TRUE);
  748.  
  749.  
  750.     //
  751.     //  grab the stored window position and size from the .ini file...
  752.     //  there must be four arguments stored or the entry is considered
  753.     //  invalid.
  754.     //
  755.     f = AppProfileReadBytes(gszSecConfig, gszKeyWindow,
  756.                             (LPBYTE)&rcWindow, sizeof(rcWindow));
  757.     if (f)
  758.     {
  759.         //
  760.         //  to make sure the user can always get at the window, check to
  761.         //  see if the midpoint of the caption is visible--if it is not,
  762.         //  then default to the default position used when creating the
  763.         //  window.
  764.         //
  765.         n = (rcWindow.right - rcWindow.left) / 2;
  766.         pt.x = (n + rcWindow.left);
  767.  
  768.         n = GetSystemMetrics(SM_CYCAPTION) / 2 + GetSystemMetrics(SM_CXFRAME);
  769.         pt.y = (n + rcWindow.top);
  770.  
  771.         GetWindowRect(GetDesktopWindow(), &rc);
  772.         if (PtInRect(&rc, pt))
  773.         {
  774.             //
  775.             //  fill out the window placement structure--default the
  776.             //  maximized and minimized states to default placement by
  777.             //  getting its current placement.
  778.             //
  779.             wp.length = sizeof(wp);
  780.             GetWindowPlacement(hwnd, &wp);
  781.  
  782.             wp.showCmd          = nCmdShow;
  783.             wp.rcNormalPosition = rcWindow;
  784.  
  785.             SetWindowPlacement(hwnd, &wp);
  786.             return (TRUE);
  787.         }
  788.     }
  789.  
  790.     //
  791.     //  show defaulted and succeed
  792.     //
  793.     ShowWindow(hwnd, nCmdShow);
  794.     return (TRUE);
  795. } // MixAppSettingsRestore()
  796.  
  797.  
  798. //--------------------------------------------------------------------------;
  799. //
  800. //  BOOL MixAppSettingsSave
  801. //
  802. //  Description:
  803. //      This function saves the current state information for the application.
  804. //      It is called just before the main window is closed (destroyed); or
  805. //      as Windows is exiting (query end session).
  806. //
  807. //      Note that this function should not destroy any resources--it can
  808. //      be called at any time to save a snapshot of the application state.
  809. //
  810. //  Arguments:
  811. //      HWND hwnd: Handle to main window that will be destroyed shortly.
  812. //
  813. //  Return (BOOL):
  814. //      The return value is always TRUE.
  815. //
  816. //  History:
  817. //      05/11/93
  818. //
  819. //--------------------------------------------------------------------------;
  820.  
  821. BOOL FNLOCAL MixAppSettingsSave
  822. (
  823.     HWND                    hwnd
  824. )
  825. {
  826.     WINDOWPLACEMENT     wp;
  827.     PRECT               prc;
  828.     BOOL                f;
  829.  
  830.     //
  831.     //  save the current window placement--only store the size and location
  832.     //  of the restored window. maximized and minimized states should
  833.     //  remain defaulted on the next invocation of this application.
  834.     //
  835.     wp.length = sizeof(wp);
  836.     f = GetWindowPlacement(hwnd, &wp);
  837.     if (f)
  838.     {
  839.         prc = &wp.rcNormalPosition;
  840.  
  841.         DPF(1, "WindowPlacement: show=%d, minX=%d, minY=%d, maxX=%d, maxY=%d",
  842.              wp.showCmd, wp.ptMinPosition.x, wp.ptMinPosition.y,
  843.              wp.ptMaxPosition.x, wp.ptMaxPosition.y);
  844.  
  845.         DPF(1, "                 normX=%d, normY=%d, normW=%d, normH=%d",
  846.              prc->left, prc->top, prc->right, prc->bottom);
  847.  
  848.         //
  849.         //  save the _bounding rectangle_ of the restored window state...
  850.         //
  851.         AppProfileWriteBytes(gszSecConfig, gszKeyWindow, (LPBYTE)prc, sizeof(*prc));
  852.     }
  853.  
  854.  
  855.     //
  856.     //  succeed
  857.     //
  858.     return (TRUE);
  859. } // MixAppSettingsSave()
  860.  
  861.  
  862. //--------------------------------------------------------------------------;
  863. //
  864. //  LRESULT AppCreate
  865. //
  866. //  Description:
  867. //      This function is called to handle the WM_CREATE message for the
  868. //      application's window. The application should finish the creation
  869. //      of the window (create controls, allocate resources, etc). The
  870. //      window has not been displayed (CreateWindow[Ex] has not returned).
  871. //
  872. //  Arguments:
  873. //      HWND hwnd: Handle to the window that is in the process of being
  874. //      created.
  875. //
  876. //      LPCREATESTRUCT pcs: Pointer to a CREATESTRUCT that contains info
  877. //      about the window being created.
  878. //
  879. //  Return (LRESULT):
  880. //      The return value should be nonzero if the application wishes to
  881. //      let the window finish being created. A return of zero tells
  882. //      CreateWindow[Ex] to fail the creation of the window.
  883. //
  884. //  History:
  885. //      11/ 8/92
  886. //
  887. //--------------------------------------------------------------------------;
  888.  
  889. LRESULT FNGLOBAL AppCreate
  890. (
  891.     HWND                    hwnd,
  892.     LPCREATESTRUCT          pcs
  893. )
  894. {
  895.     extern TCHAR       gszLineFormatTitle[];
  896.  
  897.     DPF(1, "AppCreate(hwnd=%Xh, cs.x=%d, cs.y=%d, cs.cx=%d, cs.cy=%d)",
  898.             hwnd, pcs->x, pcs->y, pcs->cx, pcs->cy);
  899.  
  900.     //
  901.     //  create the driver selection listbox
  902.     //
  903.     gptlbLines = TlbCreate(hwnd, IDD_APP_LIST_LINES, NULL);
  904.     if (NULL == gptlbLines)
  905.         return (0L);
  906.  
  907.     TlbSetTitleAndTabs(gptlbLines, gszLineFormatTitle, FALSE);
  908.  
  909.  
  910.     //
  911.     //  default to device id zero... a real app would allow configuration
  912.     //  and set to previous selection. but this is not a real app.
  913.     //
  914.     ghmx = MixAppNewDevice(hwnd, NULL, 0);
  915.     if (NULL == ghmx)
  916.     {
  917.         //
  918.         //  must be having a very bad day..
  919.         //
  920.         return (0L);
  921.     }
  922.  
  923.  
  924.     //
  925.     //
  926.     //
  927.     MixAppRefreshLineList(hwnd, gptlbLines);
  928.  
  929.  
  930.     //
  931.     //  return nonzero to succeed the creation of the window
  932.     //
  933.     return (1L);
  934. } // AppCreate()
  935.  
  936.  
  937. //--------------------------------------------------------------------------;
  938. //
  939. //  LRESULT AppQueryEndSession
  940. //
  941. //  Description:
  942. //      This function handles the WM_QUERYENDSESSION. This message is sent
  943. //      by USER when ExitWindows has been called to end the Windows session.
  944. //      This function can stop Windows from exiting if it is not convenient
  945. //      for Windows to end.
  946. //
  947. //      Giving the user the option to save modified data before continueing
  948. //      with the shutdown of Windows is a good idea.
  949. //
  950. //      Telling Windows to continue with the exit procedure does not
  951. //      necessarily mean Windows will exit. All applications are queried
  952. //      for shutdown approval. When the actual decision is made on whether
  953. //      Windows will exit, WM_ENDSESSION will be sent with the result.
  954. //
  955. //  Arguments:
  956. //      HWND hwnd: Handle to window that received the message.
  957. //
  958. //  Return (LRESULT):
  959. //      Returns zero to STOP Windows from exiting. Returns non-zero to
  960. //      allows windows to shut down.
  961. //
  962. //  History:
  963. //       2/ 9/93
  964. //
  965. //--------------------------------------------------------------------------;
  966.  
  967. LRESULT FNGLOBAL AppQueryEndSession
  968. (
  969.     HWND                    hwnd
  970. )
  971. {
  972.     DPF(1, "AppQueryEndSession(hwnd=%Xh)", hwnd);
  973.  
  974.     //
  975.     //  tell Windows to proceed with the shutdown process!
  976.     //
  977.     return (1L);
  978. } // AppQueryEndSession()
  979.  
  980.  
  981. //--------------------------------------------------------------------------;
  982. //
  983. //  LRESULT AppEndSession
  984. //
  985. //  Description:
  986. //      This function is called to handle the WM_ENDSESSION message. This
  987. //      message is generated after the application answers the
  988. //      WM_QUERYENDSESSION message. The purpose of the WM_ENDSESSION
  989. //      message is to tell the application if Windows will be exiting
  990. //      (TRUE  == fEndSession) or the end session was canceled by an
  991. //      application (FALSE == fEndSession).
  992. //
  993. //  Arguments:
  994. //      HWND hwnd: Handle to window that received the message.
  995. //
  996. //      BOOL fEndSession: TRUE if Windows is exiting. FALSE if the end
  997. //      session was canceled.
  998. //
  999. //  Return (LRESULT):
  1000. //      Returns zero if the message is processed. Note that an application
  1001. //      cannot halt the termination of Windows from this message--the
  1002. //      WM_QUERYENDSESSION is the only message that allows that behaviour.
  1003. //      If fEndSession is TRUE, Windows *WILL* exit--whether you like it
  1004. //      or not.
  1005. //
  1006. //  History:
  1007. //       2/ 9/93
  1008. //
  1009. //--------------------------------------------------------------------------;
  1010.  
  1011. LRESULT FNGLOBAL AppEndSession
  1012. (
  1013.     HWND                    hwnd,
  1014.     BOOL                    fEndSession
  1015. )
  1016. {
  1017.     DPF(1, "AppEndSession(hwnd=%Xh, fEndSession=%d)", hwnd, fEndSession);
  1018.  
  1019.     //
  1020.     //  we processed the message, return zero..
  1021.     //
  1022.     return (0L);
  1023. } // AppEndSession()
  1024.  
  1025.  
  1026. //--------------------------------------------------------------------------;
  1027. //
  1028. //  LRESULT AppClose
  1029. //
  1030. //  Description:
  1031. //      This function handles the WM_CLOSE message for the application.
  1032. //      If the application should close, DestroyWindow() must be called
  1033. //      by this function. Otherwise the application will not close.
  1034. //
  1035. //  Arguments:
  1036. //      HWND hwnd: Handle to window that generated the WM_CLOSE message.
  1037. //
  1038. //  Return (LRESULT):
  1039. //      There return value is zero. The DestroyWindow function will have
  1040. //      been called if the application should actually close.
  1041. //
  1042. //  History:
  1043. //       2/ 6/93
  1044. //
  1045. //--------------------------------------------------------------------------;
  1046.  
  1047. LRESULT FNGLOBAL AppClose
  1048. (
  1049.     HWND                    hwnd
  1050. )
  1051. {
  1052.     HWND                hlb;
  1053.     HFONT               hfont;
  1054.     MMRESULT            mmr;
  1055.  
  1056.  
  1057.     DPF(1, "AppClose(hwnd=%Xh)", hwnd);
  1058.  
  1059.     //
  1060.     //  save any settings that should be saved on app termination...
  1061.     //
  1062.     MixAppSettingsSave(hwnd);
  1063.  
  1064.  
  1065.     //
  1066.     //  if the Shift key is held down during the close message, then just
  1067.     //  save the current state but don't destroy the window... this is
  1068.     //  useful if the user does not want to exit the app and rerun it
  1069.     //  to make sure the state is saved--just before the user does something
  1070.     //  that may crash Windows or something..
  1071.     //
  1072.     if (GetKeyState(VK_SHIFT) < 0)
  1073.     {
  1074.         return (0L);
  1075.     }
  1076.  
  1077.  
  1078.     //
  1079.     //  destroy the font we are using... before deleting the font, select
  1080.     //  the system font back into the script window so the font won't
  1081.     //  be 'in use' anymore.
  1082.     //
  1083.     hlb = GetDlgItem(hwnd, IDD_APP_LIST_LINES);
  1084.  
  1085.     hfont = GetWindowFont(hlb);
  1086.     SetWindowFont(hlb, NULL, FALSE);
  1087.     DeleteFont(hfont);
  1088.  
  1089.  
  1090.  
  1091.     //
  1092.     //
  1093.     //
  1094.     if (NULL != ghmx)
  1095.     {
  1096.         mmr = mixerClose(ghmx);
  1097.         if (MMSYSERR_NOERROR != mmr)
  1098.         {
  1099.             AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  1100.                       "mixerClose() failed on hmx=%.04Xh, mmr=%u!",
  1101.                       ghmx, mmr);
  1102.         }
  1103.  
  1104.         ghmx = NULL;
  1105.     }
  1106.  
  1107.  
  1108.     gptlbLines->hlb = NULL;
  1109.     TlbDestroy(gptlbLines);
  1110.     gptlbLines = NULL;
  1111.  
  1112.  
  1113.     //
  1114.     //  make the window close and terminate the application
  1115.     //
  1116.     DestroyWindow(hwnd);
  1117.  
  1118.     return (0L);
  1119. } // AppClose()
  1120.  
  1121.  
  1122. //==========================================================================;
  1123. //
  1124. //
  1125. //
  1126. //
  1127. //==========================================================================;
  1128.  
  1129. //--------------------------------------------------------------------------;
  1130. //
  1131. //  BOOL AppInit
  1132. //
  1133. //  Description:
  1134. //      This function is called to initialize a new instance of the
  1135. //      application. We want to parse our command line, create our window,
  1136. //      allocate resources, etc.
  1137. //
  1138. //      The arguments passed to this function are exactly the same as
  1139. //      those passed to WinMain.
  1140. //
  1141. //  Arguments:
  1142. //      HINSTANCE hinst: Identifies the current instance of the
  1143. //      application.
  1144. //
  1145. //      HINSTANCE hinstPrev: Identifies the previous instance of the
  1146. //      application (NULL if first instance). For Win 32, this argument
  1147. //      is _always_ NULL.
  1148. //
  1149. //      LPTSTR pszCmdLine: Points to null-terminated unparsed command line.
  1150. //      If the application is compiled for Unicode, then this argument is
  1151. //      ignored.
  1152. //
  1153. //      int nCmdShow: How the main window for the application is to be
  1154. //      shown by default.
  1155. //
  1156. //  Return (HWND):
  1157. //      Returns the newly created handle to the applications main window.
  1158. //      This handle is NULL if something went wrong and tells the application
  1159. //      to exit immediately.
  1160. //
  1161. //  History:
  1162. //      11/ 8/92
  1163. //
  1164. //--------------------------------------------------------------------------;
  1165.  
  1166. HWND FNGLOBAL AppInit
  1167. (
  1168.     HINSTANCE               hinst,
  1169.     HINSTANCE               hinstPrev,
  1170.     LPTSTR                  pszCmdLine,
  1171.     int                     nCmdShow
  1172. )
  1173. {
  1174.     LRESULT CALLBACK AppWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1175.  
  1176.     HWND                hwnd;
  1177.     WNDCLASS            wc;
  1178.     UINT                cMixerDevs;
  1179.  
  1180.     DPF(1, "AppInit(hinst=%Xh, hinstPrev=%Xh, pszCmdLine='%s', nCmdShow=%d)",
  1181.             hinst, hinstPrev, pszCmdLine, nCmdShow);
  1182.  
  1183.     LoadString(hinst, IDS_APP_NAME, gszAppName, SIZEOF(gszAppName));
  1184.  
  1185.  
  1186.     //
  1187.     //  WARNING DANGER WARNING DANGER WARNING DANGER WARNING DANGER WARNING
  1188.     //
  1189.     //      BEFORE calling any other mixer API's, we must call the
  1190.     //      mixerGetNumDevs() function to let the mixer thunk library
  1191.     //      dynamically link to all the mixer API's!
  1192.     //
  1193.     //  WARNING DANGER WARNING DANGER WARNING DANGER WARNING DANGER WARNING
  1194.     //
  1195.     cMixerDevs = mixerGetNumDevs();
  1196.     if (0 == cMixerDevs)
  1197.     {
  1198.         AppMsgBox(NULL, MB_OK | MB_ICONEXCLAMATION,
  1199.                   "There are no mixer devices installed. This application is useless.");
  1200.         return (NULL);
  1201.     }
  1202.  
  1203.  
  1204.     //
  1205.     //  determine whether a new window class needs to be registered for
  1206.     //  this application. for Win 16, this only needs to be done for the
  1207.     //  first instance of the application created. for Win 32, this must
  1208.     //  be done for EVERY instance of the application.
  1209.     //
  1210.     if (NULL == hinstPrev)
  1211.     {
  1212.         wc.style         = CS_HREDRAW | CS_VREDRAW;
  1213.         wc.lpfnWndProc   = (WNDPROC)AppWndProc;
  1214.         wc.cbClsExtra    = 0;
  1215.         wc.cbWndExtra    = 0;
  1216.         wc.hInstance     = hinst;
  1217.         wc.hIcon         = LoadIcon(hinst, ICON_APP);
  1218.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  1219.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  1220.         wc.lpszMenuName  = MENU_APP;
  1221.         wc.lpszClassName = gszAppName;
  1222.  
  1223.         if (!RegisterClass(&wc))
  1224.             return (NULL);
  1225.     }
  1226.  
  1227.  
  1228.     //
  1229.     //  create the application's main window
  1230.     //
  1231.     //  style bits available:
  1232.     //      WS_EX_ACCEPTFILES   :  will receive WM_DROPFILES messages
  1233.     //      WS_EX_DLGMODALFRAME :  creates window with double border
  1234.     //      WS_EX_NOPARENTNOTIFY:  won't receive WM_PARENTNOTIFY messages
  1235.     //      WS_EX_TOPMOST       :  puts window in topmost space
  1236.     //      WS_EX_TRANSPARENT   :  a very bizarre style indeed (Win 16 only)
  1237.     //
  1238.     hwnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  1239.                           gszAppName,
  1240.                           gszAppName,
  1241.                           WS_OVERLAPPEDWINDOW,
  1242.                           APP_WINDOW_XOFFSET,
  1243.                           APP_WINDOW_YOFFSET,
  1244.                           APP_WINDOW_WIDTH,
  1245.                           APP_WINDOW_HEIGHT,
  1246.                           NULL,
  1247.                           NULL,
  1248.                           hinst,
  1249.                           NULL);
  1250.  
  1251.     if (NULL == hwnd)
  1252.         return (NULL);
  1253.  
  1254. #ifdef UNICODE
  1255.     //
  1256.     //  the application--which is different than the pszCmdLine argument
  1257.     //  passed through WinMain()...
  1258.     //
  1259.     //  so, skip over the command name to get to the argument string
  1260.     //
  1261.     pszCmdLine = GetCommandLine();
  1262.     if (NULL != pszCmdLine)
  1263.     {
  1264.         while (('\0' != *pszCmdLine) && (' ' != *pszCmdLine++))
  1265.             ;
  1266.     }
  1267. #endif
  1268.  
  1269.  
  1270.     //
  1271.     //
  1272.     //
  1273.     //
  1274.     MixAppSettingsRestore(hwnd, nCmdShow);
  1275.  
  1276.  
  1277.     //
  1278.     //  finally, get the window displayed and return success
  1279.     //
  1280.     //  the ShowWindow call is made during MixAppInit
  1281.     //
  1282. //  ShowWindow(hwnd, nCmdShow);
  1283. //  UpdateWindow(hwnd);
  1284.  
  1285.     return (hwnd);
  1286. } // AppInit()
  1287.  
  1288.  
  1289. //--------------------------------------------------------------------------;
  1290. //
  1291. //  int AppExit
  1292. //
  1293. //  Description:
  1294. //      This function is called just before the application exits from
  1295. //      WinMain. Its purpose is to clean up any resources that were allocated
  1296. //      for running the application: brushes, heaps, etc..
  1297. //
  1298. //  Arguments:
  1299. //      HINSTANCE hinst: Identifies the current instance of the
  1300. //      application that is exiting.
  1301. //
  1302. //      int nResult: The result of the WM_QUIT message (in wParam of the
  1303. //      MSG structure. This argument will usually be 0 (even if the message
  1304. //      loop was never entered).
  1305. //
  1306. //  Return (int):
  1307. //      The return value is usually nResult--be we give this function the
  1308. //      opportunity to modify its value.
  1309. //
  1310. //  History:
  1311. //      11/ 8/92
  1312. //
  1313. //--------------------------------------------------------------------------;
  1314.  
  1315. int FNGLOBAL AppExit
  1316. (
  1317.     HINSTANCE               hinst,
  1318.     int                     nResult
  1319. )
  1320. {
  1321.     DPF(1, "AppExit(hinst=%Xh, nResult=%d)", hinst, nResult);
  1322.  
  1323.     //
  1324.     //
  1325.     //
  1326.     //
  1327.  
  1328.     return (nResult);
  1329. } // AppExit()
  1330.