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

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  aainit.c
  13. //
  14. //  Description:
  15. //      This file contains initialization and termination code for the
  16. //      application (as well as some rarely used stuff).
  17. //
  18. //
  19. //==========================================================================;
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #include <mmsystem.h>
  24. #include <commdlg.h>
  25. #ifndef WIN32
  26. #include <shellapi.h>
  27. #endif 
  28. #include <mmreg.h>
  29. #include <msacm.h>
  30. #include <stdarg.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <memory.h>
  35.  
  36. #include "acmthunk.h"
  37. #include "appport.h"
  38. #include "acmapp.h"
  39.  
  40. #include "debug.h"
  41.  
  42.  
  43. //
  44. //
  45. //
  46. TCHAR   gszSecConfig[]          = TEXT("Configuration");
  47.  
  48. TCHAR   gszKeyOptions[]         = TEXT("Options");
  49. TCHAR   gszFormatOptions[]      = TEXT("%u");
  50.  
  51. TCHAR   gszKeyWindow[]          = TEXT("Window");
  52. TCHAR   gszKeyFont[]            = TEXT("Font");
  53. TCHAR   gszKeyInitialDirOpen[]  = TEXT("InitialDirOpen");
  54. TCHAR   gszKeyInitialDirSave[]  = TEXT("InitialDirSave");
  55. TCHAR   gszKeyLastSaveFile[]    = TEXT("LastSaveFile");
  56.  
  57.  
  58. //==========================================================================;
  59. //
  60. //  Application helper functions and rarely called stuff...
  61. //
  62. //
  63. //==========================================================================;
  64.  
  65. //--------------------------------------------------------------------------;
  66. //
  67. //  LRESULT AppWinIniChange
  68. //
  69. //  Description:
  70. //      This function is responsible for handling the WM_WININICHANGE
  71. //      message. This message is sent when modifications have been made
  72. //      to WIN.INI (from SystemParametersInfo() or other sources).
  73. //
  74. //      An application should re-enumerate system metrics (GetSystemMetrics)
  75. //      and system color (GetSystemColors) information that it has cached.
  76. //      Note that checking the section that was modified should be done if
  77. //      some enumerations are time consuming.
  78. //
  79. //  Arguments:
  80. //      HWND hwnd: Handle to window that generated the WM_INITMENUPOPUP
  81. //      message.
  82. //
  83. //      LPCTSTR pszSection: Pointer to section name that has been modified
  84. //      in WIN.INI. Note that this argument might be NULL (sent by apps
  85. //      that were written incorrectly!). If it is NULL, then this application
  86. //      should re-enumerate ALL metrics, colors, etc.
  87. //
  88. //  Return (LRESULT):
  89. //      The return value is zero if the message is processed.
  90. //
  91. //
  92. //--------------------------------------------------------------------------;
  93.  
  94. LRESULT FNGLOBAL AppWinIniChange
  95. (
  96.     HWND                    hwnd,
  97.     LPCTSTR                 pszSection
  98. )
  99. {
  100.     DPF(1, "AppWinIniChanged(hwnd=%Xh, pszSection='%s')",
  101.             hwnd, (NULL == pszSection) ? TEXT("(null)") : pszSection);
  102.  
  103.     //
  104.     //  we processed the message...
  105.     //
  106.     return (0L);
  107. } // AppWinIniChange()
  108.  
  109.  
  110. //--------------------------------------------------------------------------;
  111. //
  112. //  HFONT AppChooseFont
  113. //
  114. //  Description:
  115. //      This function is a wrapper for the ChooseFont() common dialog.
  116. //      The purpose of this function is to let the user choose a font that
  117. //      looks good to them--regardless of how stupid it really looks.
  118. //
  119. //  Arguments:
  120. //      HWND hwnd: Handle to parent window for chooser dialog.
  121. //
  122. //      HFONT hfont: Handle to current font (default for chooser dialog).
  123. //
  124. //      PLOGFONT plf: Pointer to optional LOGFONT structure to receive a
  125. //      copy of the LOGFONT information for the newly chosen font.
  126. //
  127. //  Return (HFONT):
  128. //      The return value is the newly chosen font. If no new font was chosen
  129. //      then the return value is NULL.
  130. //
  131. //
  132. //--------------------------------------------------------------------------;
  133.  
  134. HFONT FNGLOBAL AppChooseFont
  135. (
  136.     HWND                    hwnd,
  137.     HFONT                   hfont,
  138.     PLOGFONT                plf
  139. )
  140. {
  141.     LOGFONT             lf;
  142.     CHOOSEFONT          cf;
  143.     BOOL                f;
  144.     HFONT               hfontNew;
  145.  
  146.     //
  147.     //  get the font info for the current font...
  148.     //
  149.     GetObject(hfont, sizeof(LOGFONT), (LPVOID)&lf);
  150.  
  151.     //
  152.     //  fill in the choosefont structure
  153.     //
  154.     cf.lStructSize  = sizeof(CHOOSEFONT);
  155.     cf.hwndOwner    = hwnd;
  156.     cf.hDC          = NULL;
  157.     cf.Flags        = CF_SCREENFONTS |
  158.                       CF_INITTOLOGFONTSTRUCT |
  159.                       CF_FIXEDPITCHONLY |
  160.                       CF_FORCEFONTEXIST;
  161.     cf.lCustData    = 0;
  162.     cf.lpfnHook     = NULL;
  163.     cf.hInstance    = NULL;
  164.     cf.nFontType    = SCREEN_FONTTYPE;
  165.     cf.lpLogFont    = (LPLOGFONT)&lf;
  166.  
  167.     //
  168.     //  splash a dialog into the user's face..
  169.     //
  170.     hfontNew = NULL;
  171.     f = ChooseFont(&cf);
  172.     if (f)
  173.     {
  174.         //
  175.         //  create the new font..
  176.         //
  177.         hfontNew = CreateFontIndirect(&lf);
  178.         if (NULL == hfontNew)
  179.             return (NULL);
  180.  
  181.         //
  182.         //  copy the logfont structure if caller wants it
  183.         //
  184.         if (NULL != plf)
  185.             *plf = lf;
  186.     }
  187.  
  188.     //
  189.     //  return the new font (if one was chosen)
  190.     //
  191.     return (hfontNew);
  192. } // AppChooseFont()
  193.  
  194.  
  195.  
  196. //--------------------------------------------------------------------------;
  197. //  
  198. //  BOOL AppProfileWriteBytes
  199. //  
  200. //  Description:
  201. //      This function writes a raw structure of bytes to the application's
  202. //      ini section that can later be retrieved using AppProfileReadBytes.
  203. //      This gives an application the ability to write any structure to
  204. //      the ini file and restore it later--very useful.
  205. //
  206. //      NOTE! Starting with Windows for Workgroups 3.1 there are two new
  207. //      profile functions that provide the same functionality of this
  208. //      function. Specifically, these functions are GetPrivateProfileStruct
  209. //      and WritePrivateProfileStruct. These new functions are provided
  210. //      by the Common Controls DLL. The prototypes are as follows:
  211. //
  212. //      BOOL GetPrivateProfileStruct
  213. //      (
  214. //          LPSTR       szSection,
  215. //          LPSTR       szKey,
  216. //          LPBYTE      lpStruct,
  217. //          UINT        uSizeStruct,
  218. //          LPSTR       szFile
  219. //      );
  220. //
  221. //      BOOL WritePrivateProfileStruct
  222. //      (
  223. //          LPSTR       szSection,
  224. //          LPSTR       szKey,
  225. //          LPBYTE      lpStruct,
  226. //          UINT        uSizeStruct,
  227. //          LPSTR       szFile
  228. //      );
  229. //
  230. //      If you are building an application that is for Window for Workgroups
  231. //      or newer versions of Windows, you will probably want to use the
  232. //      above functions.
  233. //
  234. //  Arguments:
  235. //      PTSTR pszSection: Pointer to section for the stored data.
  236. //
  237. //      PTSTR pszKey: Pointer to key name for the stored data.
  238. //  
  239. //      LPBYTE pbStruct: Pointer to the data to be saved.
  240. //  
  241. //      UINT cbStruct: Count in bytes of the data to store.
  242. //  
  243. //  Return (BOOL):
  244. //      The return value is TRUE if the function is successful. It is FALSE
  245. //      if it fails.
  246. //  
  247. //  
  248. //--------------------------------------------------------------------------;
  249.  
  250. BOOL FNGLOBAL AppProfileWriteBytes
  251. (
  252.     PTSTR                   pszSection,
  253.     PTSTR                   pszKey,
  254.     LPBYTE                  pbStruct,
  255.     UINT                    cbStruct
  256. )
  257. {
  258.     static TCHAR achNibbleToChar[] =
  259.     {
  260.         '0', '1', '2', '3', '4', '5', '6', '7',
  261.         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  262.     };
  263.     #define     NIBBLE2CHAR(x)      (achNibbleToChar[x])
  264.     
  265.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  266.     LPTSTR      psz;
  267.     LPTSTR      pch;
  268.     UINT        cchTemp;
  269.     BOOL        fAllocated;
  270.     BOOL        fReturn;
  271.     BYTE        b;
  272.     BYTE        bChecksum;
  273.  
  274.     //
  275.     //  if pbStruct is NULL, then erase the key from the ini file, otherwise
  276.     //  format the raw bytes into a hex string and write that out...
  277.     //
  278.     fAllocated = FALSE;
  279.     psz        = NULL;
  280.     if (NULL != pbStruct)
  281.     {
  282.         //
  283.         //  check if the quick buffer can be used for formatting the output
  284.         //  text--if it cannot, then alloc space for it. note that space
  285.         //  must be available for an ending checksum byte (2 bytes for high
  286.         //  and low nibble) as well as a null terminator.
  287.         //
  288.         psz     = (LPTSTR)ach;
  289.         cchTemp = cbStruct * 2 + 3;
  290.         if (cchTemp > SIZEOF(ach))
  291.         {
  292.             psz = (LPTSTR)GlobalAllocPtr(GHND, cchTemp * sizeof(TCHAR));
  293.             if (NULL == psz)
  294.                 return (FALSE);
  295.  
  296.             fAllocated = TRUE;
  297.         }
  298.   
  299.         //
  300.         //  step through all bytes in the structure and convert it to
  301.         //  a string of hex numbers...
  302.         //
  303.         bChecksum = 0;
  304.         for (pch = psz; 0 != cbStruct; cbStruct--, pbStruct++)
  305.         {
  306.             //
  307.             //  grab the next byte and add into checksum...
  308.             //
  309.             bChecksum += (b = *pbStruct);
  310.       
  311.             *pch++ = NIBBLE2CHAR((b >> (BYTE)4) & (BYTE)0x0F);
  312.             *pch++ = NIBBLE2CHAR(b & (BYTE)0x0F);
  313.         }
  314.  
  315.         //
  316.         //  add the checksum byte to the end and null terminate the hex
  317.         //  dumped string...
  318.         //
  319.         *pch++ = NIBBLE2CHAR((bChecksum >> (BYTE)4) & (BYTE)0x0F);
  320.         *pch++ = NIBBLE2CHAR(bChecksum & (BYTE)0x0F);
  321.         *pch   = '\0';
  322.     }
  323.  
  324.     //
  325.     //  write the string of hex bytes out to the ini file...
  326.     //
  327.     fReturn = WritePrivateProfileString(pszSection, pszKey, psz, gszAppProfile);
  328.  
  329.     //
  330.     //  free the temporary buffer if one was allocated (lots of bytes!)
  331.     //
  332.     if (fAllocated)
  333.         GlobalFreePtr(psz);
  334.   
  335.     return (fReturn);
  336. } // AppProfileWriteBytes
  337.  
  338.  
  339. //--------------------------------------------------------------------------;
  340. //  
  341. //  BOOL AppProfileReadBytes
  342. //  
  343. //  Description:
  344. //      This function reads a previously stored structure of bytes from
  345. //      the application's ini file. This data must have been written with
  346. //      the AppProfileWriteBytes function--it is checksumed to keep bad
  347. //      data from blowing up the application.
  348. //  
  349. //      NOTE! Starting with Windows for Workgroups 3.1 there are two new
  350. //      profile functions that provide the same functionality of this
  351. //      function. Specifically, these functions are GetPrivateProfileStruct
  352. //      and WritePrivateProfileStruct. These new functions are provided
  353. //      by the Common Controls DLL. The prototypes are as follows:
  354. //
  355. //      BOOL GetPrivateProfileStruct
  356. //      (
  357. //          LPSTR       szSection,
  358. //          LPSTR       szKey,
  359. //          LPBYTE      lpStruct,
  360. //          UINT        uSizeStruct,
  361. //          LPSTR       szFile
  362. //      );
  363. //
  364. //      BOOL WritePrivateProfileStruct
  365. //      (
  366. //          LPSTR       szSection,
  367. //          LPSTR       szKey,
  368. //          LPBYTE      lpStruct,
  369. //          UINT        uSizeStruct,
  370. //          LPSTR       szFile
  371. //      );
  372. //
  373. //      If you are building an application that is for Window for Workgroups
  374. //      or newer versions of Windows, you will probably want to use the
  375. //      above functions.
  376. //  
  377. //  Arguments:
  378. //      PTSTR pszSection: Pointer to section that contains the data.
  379. //
  380. //      PTSTR pszKey: Pointer to key that contains the data.
  381. //  
  382. //      LPBYTE pbStruct: Pointer to buffer to receive the data.
  383. //  
  384. //      UINT cbStruct: Number of bytes expected.
  385. //  
  386. //  Return (BOOL):
  387. //      The return value is TRUE if the function is successful. It is FALSE
  388. //      if the function fails (bad checksum, missing key, etc).
  389. //  
  390. //  
  391. //--------------------------------------------------------------------------;
  392.  
  393. BOOL FNGLOBAL AppProfileReadBytes
  394. (
  395.     PTSTR                   pszSection,
  396.     PTSTR                   pszKey,
  397.     LPBYTE                  pbStruct,
  398.     UINT                    cbStruct
  399. )
  400. {
  401.     //
  402.     //  note that the following works for both upper and lower case, and
  403.     //  will return valid values for garbage chars
  404.     //
  405.     #define CHAR2NIBBLE(ch) (BYTE)( ((ch) >= '0' && (ch) <= '9') ?  \
  406.                                 (BYTE)((ch) - '0') :                \
  407.                                 ((BYTE)(10 + (ch) - 'A') & (BYTE)0x0F) )
  408.  
  409.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  410.     LPTSTR      psz;
  411.     LPTSTR      pch;
  412.     UINT        cchTemp;
  413.     UINT        u;
  414.     BOOL        fAllocated;
  415.     BOOL        fReturn;
  416.     BYTE        b;
  417.     BYTE        bChecksum;
  418.     TCHAR       ch;
  419.  
  420.     //
  421.     //  add one the the number of bytes needed to accomodate the checksum
  422.     //  byte placed at the end by AppProfileWriteBytes...
  423.     //
  424.     cbStruct++;
  425.  
  426.     //
  427.     //  check if the quick buffer can be used for retrieving the input
  428.     //  text--if it cannot, then alloc space for it. note that there must
  429.     //  be space available for the null terminator (the +1 below).
  430.     //
  431.     fAllocated = FALSE;
  432.     psz        = (LPTSTR)ach;
  433.     cchTemp    = cbStruct * 2 + 1;
  434.     if (cchTemp > SIZEOF(ach))
  435.     {
  436.         psz = (LPTSTR)GlobalAllocPtr(GHND, cchTemp * sizeof(TCHAR));
  437.         if (NULL == psz)
  438.             return (FALSE);
  439.  
  440.         fAllocated = TRUE;
  441.     }
  442.  
  443.     //
  444.     //  read the hex string... if it is not the correct length, then assume
  445.     //  error and return.
  446.     //
  447.     fReturn = FALSE;
  448.     u = (UINT)GetPrivateProfileString(pszSection, pszKey, gszNull,
  449.                                       psz, cchTemp, gszAppProfile);
  450.     if ((cbStruct * 2) == u)
  451.     {
  452.         bChecksum = 0;
  453.         for (pch = psz; 0 != cbStruct; cbStruct--, pbStruct++)
  454.         {
  455.             ch = *pch++;
  456.             b  = CHAR2NIBBLE(ch) << (BYTE)4;
  457.             ch = *pch++;
  458.             b |= CHAR2NIBBLE(ch);
  459.  
  460.             //
  461.             //  if this is not the final byte (the checksum byte), then 
  462.             //  store it and accumulate checksum..
  463.             //
  464.             if (cbStruct != 1)
  465.                 bChecksum += (*pbStruct = b);
  466.         }
  467.  
  468.         //
  469.         //  check the last byte read against the checksum that we calculated
  470.         //  if they are not equal then return error...
  471.         //
  472.         fReturn = (bChecksum == b);
  473.     }
  474.  
  475.  
  476.     //
  477.     //  free the temporary buffer if one was allocated (lots of bytes!)
  478.     //
  479.     if (fAllocated)
  480.         GlobalFreePtr(psz);
  481.   
  482.     return (fReturn);
  483. } // AppProfileReadBytes
  484.  
  485.  
  486. //==========================================================================;
  487. //
  488. //  Startup and shutdown code...
  489. //
  490. //
  491. //==========================================================================;
  492.  
  493. //--------------------------------------------------------------------------;
  494. //
  495. //  BOOL AcmAppChooseFont
  496. //
  497. //  Description:
  498. //      This function lets the user choose a new font for the script window.
  499. //      After a new font is chosen, the font structure is stored to the
  500. //      .ini file so it can be restored on the next run of this application.
  501. //
  502. //  Arguments:
  503. //      HWND hwnd: Handle to main window.
  504. //
  505. //  Return (BOOL):
  506. //      The return value is TRUE if a new font was chosen. It is FALSE if
  507. //      the user canceled the operation.
  508. //
  509. //
  510. //--------------------------------------------------------------------------;
  511.  
  512. BOOL FNGLOBAL AcmAppChooseFont
  513. (
  514.     HWND                    hwnd
  515. )
  516. {
  517.     LOGFONT             lf;
  518.     HWND                hedit;
  519.     HFONT               hfont;
  520.     HFONT               hfontNew;
  521.  
  522.     hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  523.  
  524.     //
  525.     //  get the current font and pass it to the choose font dialog
  526.     //
  527.     hfont = GetWindowFont(hedit);
  528.  
  529.     hfontNew = AppChooseFont(hwnd, hfont, &lf);
  530.     if (NULL == hfontNew)
  531.         return (FALSE);
  532.  
  533.     //
  534.     //  select the new font into the window and delete the old one
  535.     //
  536.     SetWindowFont(hedit, hfontNew, TRUE);
  537.     DeleteFont(hfont);
  538.  
  539.     ghfontApp = hfontNew;
  540.  
  541.  
  542.     //
  543.     //  save the complete description of the chosen font so there can be
  544.     //  no strangness in the font mapping next run. this is overkill, but
  545.     //  it works...
  546.     //
  547.     AppProfileWriteBytes(gszSecConfig, gszKeyFont, (LPBYTE)&lf, sizeof(lf));
  548.  
  549.     return (TRUE);
  550. } // AcmAppChooseFont()
  551.  
  552.  
  553. //--------------------------------------------------------------------------;
  554. //
  555. //  BOOL AcmAppSettingsRestore
  556. //
  557. //  Description:
  558. //      This function restores state information for the application. This
  559. //      function is called just after the main window is created (it has
  560. //      not been ShowWindow()'d). This function will generate the call
  561. //      to ShowWindow before returning.
  562. //
  563. //  Arguments:
  564. //      HWND hwnd: Handle to main window that has just been created but
  565. //      not shown.
  566. //
  567. //      int nCmdShow: The state that the application window should show as.
  568. //
  569. //  Return (BOOL):
  570. //      The return value is always TRUE.
  571. //
  572. //
  573. //--------------------------------------------------------------------------;
  574.  
  575. BOOL FNLOCAL AcmAppSettingsRestore
  576. (
  577.     HWND                    hwnd,
  578.     int                     nCmdShow
  579. )
  580. {
  581.     WINDOWPLACEMENT     wp;
  582.     LOGFONT             lf;
  583.     RECT                rc;
  584.     RECT                rcWindow;
  585.     POINT               pt;
  586.     int                 n;
  587.     BOOL                f;
  588.  
  589.  
  590.     //
  591.     //  restore the previous Options state...
  592.     //
  593.     gfuAppOptions = GetPrivateProfileInt(gszSecConfig, gszKeyOptions,
  594.                                          gfuAppOptions, gszAppProfile);
  595.  
  596.  
  597.  
  598.     //
  599.     //  restore the user's preferred font.
  600.     //
  601.     ghfontApp = GetStockFont(SYSTEM_FIXED_FONT);
  602.     f = AppProfileReadBytes(gszSecConfig, gszKeyFont, (LPBYTE)&lf, sizeof(lf));
  603.     if (f)
  604.     {
  605.         HFONT   hfont;
  606.  
  607.         hfont = CreateFontIndirect(&lf);
  608.         if (NULL != hfont)
  609.         {
  610.             ghfontApp = hfont;
  611.         }
  612.     }
  613.  
  614.     SetWindowFont(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), ghfontApp, FALSE);
  615.  
  616.  
  617.     //
  618.     //
  619.     //
  620.     GetPrivateProfileString(gszSecConfig, gszKeyInitialDirOpen, gszNull,
  621.                             gszInitialDirOpen, SIZEOF(gszInitialDirOpen),
  622.                             gszAppProfile);
  623.  
  624.     GetPrivateProfileString(gszSecConfig, gszKeyInitialDirSave, gszNull,
  625.                             gszInitialDirSave, SIZEOF(gszInitialDirSave),
  626.                             gszAppProfile);
  627.  
  628.     GetPrivateProfileString(gszSecConfig, gszKeyLastSaveFile, gszNull,
  629.                             gszLastSaveFile, SIZEOF(gszLastSaveFile),
  630.                             gszAppProfile);
  631.  
  632.  
  633.     //
  634.     //  grab the stored window position and size from the .ini file...
  635.     //  there must be four arguments stored or the entry is considered
  636.     //  invalid.
  637.     //
  638.     f = AppProfileReadBytes(gszSecConfig, gszKeyWindow,
  639.                             (LPBYTE)&rcWindow, sizeof(rcWindow));
  640.     if (f)
  641.     {
  642.         //
  643.         //  to make sure the user can always get at the window, check to
  644.         //  see if the midpoint of the caption is visible--if it is not,
  645.         //  then default to the default position used when creating the
  646.         //  window.
  647.         //
  648.         n = (rcWindow.right - rcWindow.left) / 2;
  649.         pt.x = (n + rcWindow.left);
  650.  
  651.         n = GetSystemMetrics(SM_CYCAPTION) / 2 + GetSystemMetrics(SM_CXFRAME);
  652.         pt.y = (n + rcWindow.top);
  653.  
  654.         GetWindowRect(GetDesktopWindow(), &rc);
  655.         if (PtInRect(&rc, pt))
  656.         {
  657.             //
  658.             //  fill out the window placement structure--default the
  659.             //  maximized and minimized states to default placement by
  660.             //  getting its current placement.
  661.             //
  662.             wp.length = sizeof(wp);
  663.             GetWindowPlacement(hwnd, &wp);
  664.  
  665.             wp.showCmd          = nCmdShow;
  666. #if 0
  667.             wp.rcNormalPosition = rcWindow;
  668. #else
  669.             n = rcWindow.right - rcWindow.left;
  670.             wp.rcNormalPosition.right  = wp.rcNormalPosition.left + n;
  671.  
  672.             n = rcWindow.bottom - rcWindow.top;
  673.             wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + n;
  674. #endif
  675.  
  676.             SetWindowPlacement(hwnd, &wp);
  677.             return (TRUE);
  678.         }
  679.     }
  680.  
  681.     //
  682.     //  show defaulted and succeed
  683.     //
  684.     ShowWindow(hwnd, nCmdShow);
  685.  
  686.     return (TRUE);
  687. } // AcmAppSettingsRestore()
  688.  
  689.  
  690. //--------------------------------------------------------------------------;
  691. //
  692. //  BOOL AcmAppSettingsSave
  693. //
  694. //  Description:
  695. //      This function saves the current state information for the application.
  696. //      It is called just before the main window is closed (destroyed); or
  697. //      as Windows is exiting (query end session).
  698. //
  699. //      Note that this function should not destroy any resources--it can
  700. //      be called at any time to save a snapshot of the application state.
  701. //
  702. //  Arguments:
  703. //      HWND hwnd: Handle to main window that will be destroyed shortly.
  704. //
  705. //  Return (BOOL):
  706. //      The return value is always TRUE.
  707. //
  708. //
  709. //--------------------------------------------------------------------------;
  710.  
  711. BOOL FNLOCAL AcmAppSettingsSave
  712. (
  713.     HWND                    hwnd
  714. )
  715. {
  716.     TCHAR               ach[APP_MAX_STRING_RC_CHARS];
  717.     WINDOWPLACEMENT     wp;
  718.     PRECT               prc;
  719.     BOOL                f;
  720.  
  721.     //
  722.     //  save the current option settings--note that we ALWAYS turn off the
  723.     //  debug logging option so the app doesn't try to OutputDebugString
  724.     //  unexpectedly during the next session...
  725.     //
  726.     gfuAppOptions &= ~APP_OPTIONSF_DEBUGLOG;
  727.     if (GetPrivateProfileInt(gszSecConfig, gszKeyOptions, 0, gszAppProfile) != gfuAppOptions)
  728.     {
  729.         wsprintf(ach, gszFormatOptions, gfuAppOptions);
  730.         WritePrivateProfileString(gszSecConfig, gszKeyOptions, ach, gszAppProfile);
  731.     }
  732.  
  733.  
  734.     //
  735.     //
  736.     //
  737.     //
  738.     WritePrivateProfileString(gszSecConfig, gszKeyInitialDirOpen,
  739.                               gszInitialDirOpen, gszAppProfile);
  740.  
  741.     WritePrivateProfileString(gszSecConfig, gszKeyInitialDirSave,
  742.                               gszInitialDirSave, gszAppProfile);
  743.  
  744.     WritePrivateProfileString(gszSecConfig, gszKeyLastSaveFile,
  745.                               gszLastSaveFile, gszAppProfile);
  746.  
  747.  
  748.  
  749.     //
  750.     //  save the current window placement--only store the size and location
  751.     //  of the restored window. maximized and minimized states should
  752.     //  remain defaulted on the next invocation of this application.
  753.     //
  754.     wp.length = sizeof(wp);
  755.     f = GetWindowPlacement(hwnd, &wp);
  756.     if (f)
  757.     {
  758.         prc = &wp.rcNormalPosition;
  759.  
  760.  
  761.         //
  762.         //  save the _bounding rectangle_ of the restored window state...
  763.         //
  764.         AppProfileWriteBytes(gszSecConfig, gszKeyWindow, (LPBYTE)prc, sizeof(*prc));
  765.     }
  766.  
  767.  
  768.     //
  769.     //  succeed
  770.     //
  771.     return (TRUE);
  772. } // AcmAppSettingsSave()
  773.  
  774.  
  775. //--------------------------------------------------------------------------;
  776. //
  777. //  BOOL AcmAppShutdown
  778. //
  779. //  Description:
  780. //      This function is called to gracefully shut down the application.
  781. //      If the application should not be closed, a FALSE value is returned.
  782. //      This function is called for WM_CLOSE and WM_QUERYENDSESSION
  783. //      messages...
  784. //
  785. //  Arguments:
  786. //      HWND hwnd: Handle to main window.
  787. //
  788. //      PACMAPPFILEDESC paafd: Pointer to current file description.
  789. //
  790. //  Return (BOOL):
  791. //      Returns TRUE if the application can proceed with close. Returns
  792. //      FALSE if the application should NOT be closed.
  793. //
  794. //
  795. //--------------------------------------------------------------------------;
  796.  
  797. BOOL FNGLOBAL AcmAppShutdown
  798. (
  799.     HWND                    hwnd,
  800.     PACMAPPFILEDESC         paafd
  801. )
  802. {
  803.     BOOL                f;
  804.  
  805.  
  806.     //
  807.     //  check if the script has been modified without saving. if the user
  808.     //  cancels the operation, then we will NOT close the application.
  809.     //
  810.     f = AcmAppFileSaveModified(hwnd, paafd);
  811.     if (!f)
  812.         return (FALSE);
  813.  
  814.  
  815.     //
  816.     //
  817.     //
  818.     if (NULL != ghadidNotify)
  819.     {
  820.         acmDriverRemove(ghadidNotify, 0L);
  821.         ghadidNotify = NULL;
  822.     }
  823.  
  824.  
  825.     //
  826.     //  save any settings that should be saved on app termination...
  827.     //
  828.     AcmAppSettingsSave(hwnd);
  829.  
  830.  
  831.     //
  832.     //  allow closing of application...
  833.     //
  834.     return (TRUE);
  835. } // AcmAppShutdown()
  836.  
  837.  
  838. //--------------------------------------------------------------------------;
  839. //
  840. //  BOOL AcmAppInit
  841. //
  842. //  Description:
  843. //
  844. //
  845. //  Arguments:
  846. //
  847. //
  848. //  Return (BOOL):
  849. //
  850. //
  851. //--------------------------------------------------------------------------;
  852.  
  853. BOOL FNLOCAL AcmAppInit
  854. (
  855.     HWND                    hwnd,
  856.     PACMAPPFILEDESC         paafd,
  857.     LPTSTR                  pszCmdLine,
  858.     int                     nCmdShow
  859. )
  860. {
  861.     BOOL                f;
  862.     DWORD               dwVersion;
  863.  
  864.  
  865.     //
  866.     //  !!! VERY IMPORTANT !!!
  867.     //
  868.     //  the ACM may or may not be installed. this application is using 
  869.     //  the ACMTHUNK.C file to dynamically link to the ACM. if the
  870.     //  acmThunkInitialize() API fails, then the ACM is *NOT* installed
  871.     //  and none of the API's should be used.
  872.     //
  873.     //  if the ACM *is* installed, then the version MUST be at least
  874.     //  V2.00 for the API's to be available (earlier versions do not
  875.     //  supply the API we need).
  876.     //
  877.     acmThunkInitialize();
  878.  
  879.     dwVersion = acmGetVersion();
  880.     if (0x0200 <= HIWORD(dwVersion))
  881.     {
  882.         MMRESULT        mmr;
  883.  
  884.         gfAcmAvailable = TRUE;
  885.  
  886.         mmr = acmDriverAdd(&ghadidNotify,
  887.                             ghinst,
  888.                             (LPARAM)(UINT)hwnd,
  889.                             WM_ACMAPP_ACM_NOTIFY,
  890.                             ACM_DRIVERADDF_NOTIFYHWND);
  891.         if (MMSYSERR_NOERROR != mmr)
  892.         {
  893.             DPF(0, "!AppCreate: acmDriverAdd failed to add notify window! mmr=%u", mmr);
  894.         }
  895.     }
  896.     else
  897.     {
  898.         if (0L == dwVersion)
  899.         {
  900.             AppMsgBoxId(NULL, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL,
  901.                         IDS_ERROR_ACM_NOT_PRESENT);
  902.         }
  903.         else
  904.         {
  905.             AppMsgBoxId(NULL, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL,
  906.                         IDS_ERROR_ACM_TOO_OLD,
  907.                         HIWORD(dwVersion) >> 8,
  908.                         HIWORD(dwVersion) & 0x00FF);
  909.         }
  910.  
  911.         gfAcmAvailable = FALSE;
  912.     }
  913.  
  914.  
  915.     //
  916.     //
  917.     //
  918.     AcmAppSettingsRestore(hwnd, nCmdShow);
  919.  
  920.     //
  921.     //  strip the command line..
  922.     //
  923.     if (NULL != pszCmdLine)
  924.     {
  925.         while (('\0' != *pszCmdLine) && (' ' == *pszCmdLine))
  926.             pszCmdLine++;
  927.     }
  928.  
  929.     //
  930.     //  if there is a command line, assume it is a filename for a script
  931.     //  and try to open it. otherwise, just initialize the script window.
  932.     //
  933.     if ((NULL != pszCmdLine) && ('\0' != *pszCmdLine))
  934.     {
  935.         //
  936.         //  attempt to open the specified file..
  937.         //
  938.         lstrcpy(paafd->szFilePath, pszCmdLine);
  939.         f = AcmAppFileOpen(hwnd, paafd);
  940.         if (f)
  941.         {
  942.             AppTitle(hwnd, paafd->szFileTitle);
  943.             AcmAppDisplayFileProperties(hwnd, paafd);
  944.         }
  945.         else
  946.         {
  947.             //
  948.             //  opening the command line file was untriumphant..
  949.             //
  950.             AppMsgBoxId(hwnd, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL,
  951.                         IDS_ERROR_OPEN_FAILED, (LPSTR)paafd->szFilePath);
  952.  
  953.  
  954.             paafd->szFilePath[0]  = '\0';
  955.             paafd->szFileTitle[0] = '\0';
  956.             AppFileNew(hwnd, paafd, FALSE);
  957.         }
  958.     }
  959.     else
  960.     {
  961.         AppFileNew(hwnd, paafd, FALSE);
  962.     }
  963.  
  964.     return (TRUE);
  965. } // AcmAppInit()
  966.  
  967.  
  968. //--------------------------------------------------------------------------;
  969. //
  970. //  BOOL AcmAppExit
  971. //
  972. //  Description:
  973. //
  974. //
  975. //  Arguments:
  976. //
  977. //
  978. //  Return (BOOL):
  979. //
  980. //
  981. //
  982. //--------------------------------------------------------------------------;
  983.  
  984. BOOL FNGLOBAL AcmAppExit
  985. (
  986.     void
  987. )
  988. {
  989.     acmThunkTerminate();
  990.  
  991.     return (TRUE);
  992. } // AcmAppExit()
  993.  
  994.  
  995. //==========================================================================;
  996. //
  997. //  Initialization and exit code...
  998. //
  999. //
  1000. //==========================================================================;
  1001.  
  1002. //--------------------------------------------------------------------------;
  1003. //
  1004. //  BOOL AppRegisterPenApp
  1005. //
  1006. //  Description:
  1007. //      This function is used to register and de-register an application
  1008. //      as being 'Pen Enhanced.' If the Windows installation is Pen enabled
  1009. //      then this function allows the RC Manager to replace all 'Edit'
  1010. //      controls with 'HEdit' controls.
  1011. //
  1012. //      This function must be called to register the application BEFORE
  1013. //      creating any edit controls.
  1014. //
  1015. //  Arguments:
  1016. //      BOOL fRegister: If this argument is TRUE, the app is registered
  1017. //      with the RC Manager as being Pen aware. If this argument is FALSE
  1018. //      the app is de-registered.
  1019. //
  1020. //  Return (BOOL):
  1021. //      The return value is TRUE if Windows for Pen Computing is installed
  1022. //      on the system. The return value is FALSE if the Windows installation
  1023. //      is not Pen enabled.
  1024. //
  1025. //
  1026. //--------------------------------------------------------------------------;
  1027.  
  1028. BOOL FNLOCAL AppRegisterPenApp
  1029. (
  1030.     BOOL                    fRegister
  1031. )
  1032. {
  1033.     #define RPA_DEFAULT     0x0001
  1034.  
  1035.     typedef void (FAR PASCAL *PENWINREGISTERPROC)(UINT, BOOL);
  1036.  
  1037.     static char                 szRegPenApp[]   = "RegisterPenApp";
  1038.     static PENWINREGISTERPROC   pfnRegPenApp    = NULL;
  1039.  
  1040.     HINSTANCE   hinstPenWin;
  1041.  
  1042.     //
  1043.     //  check if Windows for Pen Computing is installed--and if it is, 
  1044.     //  dyna-link to the RegisterPenApp() function.
  1045.     //
  1046.     //  if Pens are not supported, then return FALSE.
  1047.     //
  1048.     if (NULL == pfnRegPenApp)
  1049.     {
  1050.         hinstPenWin = (HINSTANCE)GetSystemMetrics(SM_PENWINDOWS);
  1051.         if (NULL == hinstPenWin)
  1052.             return (FALSE);
  1053.  
  1054.         pfnRegPenApp = (PENWINREGISTERPROC)GetProcAddress(hinstPenWin, szRegPenApp);
  1055.         if (NULL == pfnRegPenApp)
  1056.             return (FALSE);
  1057.     }
  1058.  
  1059.     //
  1060.     //  either enable or disable the RC Manager's Pen meathooks..
  1061.     //
  1062.     (*pfnRegPenApp)(RPA_DEFAULT, fRegister);
  1063.  
  1064.     return (TRUE);
  1065. } // AppRegisterPenApp()
  1066.  
  1067.  
  1068. //--------------------------------------------------------------------------;
  1069. //
  1070. //  LRESULT AppCreate
  1071. //
  1072. //  Description:
  1073. //      This function is called to handle the WM_CREATE message for the
  1074. //      applications window. The application should finish the creation
  1075. //      of the window (create controls, allocate resources, etc). The
  1076. //      window has not been displayed (CreateWindow[Ex] has not returned).
  1077. //
  1078. //  Arguments:
  1079. //      HWND hwnd: Handle to the window that is in the process of being
  1080. //      created.
  1081. //
  1082. //      LPCREATESTRUCT pcs: Pointer to a CREATESTRUCT that contains info
  1083. //      about the window being created.
  1084. //
  1085. //  Return (LRESULT):
  1086. //      The return value should be nonzero if the application wishes to
  1087. //      let the window finish being created. A return of zero tells
  1088. //      CreateWindow[Ex] to fail the creation of the window.
  1089. //
  1090. //
  1091. //--------------------------------------------------------------------------;
  1092.  
  1093. LRESULT FNGLOBAL AppCreate
  1094. (
  1095.     HWND                    hwnd,
  1096.     LPCREATESTRUCT          pcs
  1097. )
  1098. {
  1099.     static TCHAR        szEdit[]    = TEXT("edit");
  1100.  
  1101.     HWND                hedit;
  1102.  
  1103.     DPF(1, "AppCreate(hwnd=%Xh, cs.x=%d, cs.y=%d, cs.cx=%d, cs.cy=%d)",
  1104.             hwnd, pcs->x, pcs->y, pcs->cx, pcs->cy);
  1105.  
  1106.     //
  1107.     //  create the driver selection listbox
  1108.     //
  1109.     hedit = CreateWindow(szEdit, gszNull,
  1110.                          ES_LEFT | ES_MULTILINE | WS_TABSTOP |
  1111.                          ES_AUTOVSCROLL | ES_AUTOHSCROLL |
  1112.                          ES_NOHIDESEL | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
  1113.                          WS_VISIBLE | WS_CHILD | ES_READONLY,
  1114.                          0, 0, 0, 0, hwnd, (HMENU)IDD_ACMAPP_EDIT_DISPLAY,
  1115.                          pcs->hInstance, NULL);
  1116.     if (NULL == hedit)
  1117.         return (0L);
  1118.  
  1119.  
  1120.     //
  1121.     //  return nonzero to succeed the creation of the window
  1122.     //
  1123.     return (1L);
  1124. } // AppCreate()
  1125.  
  1126.  
  1127. //--------------------------------------------------------------------------;
  1128. //
  1129. //  LRESULT AppQueryEndSession
  1130. //
  1131. //  Description:
  1132. //      This function handles the WM_QUERYENDSESSION. This message is sent
  1133. //      by USER when ExitWindows has been called to end the Windows session.
  1134. //      This function can stop Windows from exiting if it is not convenient
  1135. //      for Windows to end.
  1136. //
  1137. //      Giving the user the option to save modified data before continueing
  1138. //      with the shutdown of Windows is a good idea.
  1139. //
  1140. //      Telling Windows to continue with the exit procedure does not
  1141. //      necessarily mean Windows will exit. All applications are queried
  1142. //      for shutdown approval. When the actual decision is made on whether
  1143. //      Windows will exit, WM_ENDSESSION will be sent with the result.
  1144. //
  1145. //  Arguments:
  1146. //      HWND hwnd: Handle to window that received the message.
  1147. //
  1148. //  Return (LRESULT):
  1149. //      Returns zero to STOP Windows from exiting. Returns non-zero to
  1150. //      allows windows to shut down.
  1151. //
  1152. //
  1153. //--------------------------------------------------------------------------;
  1154.  
  1155. LRESULT FNGLOBAL AppQueryEndSession
  1156. (
  1157.     HWND                    hwnd
  1158. )
  1159. {
  1160.     BOOL                f;
  1161.  
  1162.     DPF(1, "AppQueryEndSession(hwnd=%Xh)", hwnd);
  1163.  
  1164.     //
  1165.     //  attempt to shut down--if this fails (user canceled it, etc) then
  1166.     //  do NOT allow the Windows to exit.
  1167.     //
  1168.     f = AcmAppShutdown(hwnd, &gaafd);
  1169.     if (!f)
  1170.         return (0L);
  1171.  
  1172.  
  1173.     //
  1174.     //  tell Windows to proceed with the shutdown process!
  1175.     //
  1176.     return (1L);
  1177. } // AppQueryEndSession()
  1178.  
  1179.  
  1180. //--------------------------------------------------------------------------;
  1181. //
  1182. //  LRESULT AppEndSession
  1183. //
  1184. //  Description:
  1185. //      This function is called to handle the WM_ENDSESSION message. This
  1186. //      message is generated after the application answers the
  1187. //      WM_QUERYENDSESSION message. The purpose of the WM_ENDSESSION
  1188. //      message is to tell the application if Windows will be exiting
  1189. //      (TRUE  == fEndSession) or the end session was canceled by an
  1190. //      application (FALSE == fEndSession).
  1191. //
  1192. //  Arguments:
  1193. //      HWND hwnd: Handle to window that received the message.
  1194. //
  1195. //      BOOL fEndSession: TRUE if Windows is exiting. FALSE if the end
  1196. //      session was canceled.
  1197. //
  1198. //  Return (LRESULT):
  1199. //      Returns zero if the message is processed. Note that an application
  1200. //      cannot halt the termination of Windows from this message--the
  1201. //      WM_QUERYENDSESSION is the only message that allows that behaviour.
  1202. //      If fEndSession is TRUE, Windows *WILL* exit--whether you like it
  1203. //      or not.
  1204. //
  1205. //
  1206. //--------------------------------------------------------------------------;
  1207.  
  1208. LRESULT FNGLOBAL AppEndSession
  1209. (
  1210.     HWND                    hwnd,
  1211.     BOOL                    fEndSession
  1212. )
  1213. {
  1214.     DPF(1, "AppEndSession(hwnd=%Xh, fEndSession=%d)", hwnd, fEndSession);
  1215.  
  1216.     //
  1217.     //  we processed the message, return zero..
  1218.     //
  1219.     return (0L);
  1220. } // AppEndSession()
  1221.  
  1222.  
  1223. //--------------------------------------------------------------------------;
  1224. //
  1225. //  LRESULT AppClose
  1226. //
  1227. //  Description:
  1228. //      This function handles the WM_CLOSE message for the application.
  1229. //      If the application should close, DestroyWindow() must be called
  1230. //      by this function. Otherwise the application will not close.
  1231. //
  1232. //  Arguments:
  1233. //      HWND hwnd: Handle to window that generated the WM_CLOSE message.
  1234. //
  1235. //  Return (LRESULT):
  1236. //      There return value is zero. The DestroyWindow function will have
  1237. //      been called if the application should actually close.
  1238. //
  1239. //--------------------------------------------------------------------------;
  1240.  
  1241. LRESULT FNGLOBAL AppClose
  1242. (
  1243.     HWND                    hwnd
  1244. )
  1245. {
  1246.     HWND                hedit;
  1247.     HFONT               hfont;
  1248.     BOOL                f;
  1249.  
  1250.     //
  1251.     //  if the Shift key is held down during the close message, then just
  1252.     //  save the current state but don't destroy the window... this is
  1253.     //  useful if the user does not want to exit the app and rerun it
  1254.     //  to make sure the state is saved--just before the user does something
  1255.     //  that may crash Windows or something..
  1256.     //
  1257.     if (GetKeyState(VK_SHIFT) < 0)
  1258.     {
  1259.         //
  1260.         //  save any settings that should be saved on app termination...
  1261.         //
  1262.         AcmAppSettingsSave(hwnd);
  1263.         return (0L);
  1264.     }
  1265.  
  1266.     //
  1267.     //  attempt to shut down--if this fails (user canceled it, etc) then
  1268.     //  do NOT allow the window to be destroyed.
  1269.     //
  1270.     f = AcmAppShutdown(hwnd, &gaafd);
  1271.     if (!f)
  1272.         return (0L);
  1273.  
  1274.  
  1275.  
  1276.     //
  1277.     //  destroy the font we are using... before deleting the font, select
  1278.     //  the system font back into the window so the font won't be 'in use'
  1279.     //  anymore.
  1280.     //
  1281.     hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1282.  
  1283.     hfont = GetWindowFont(hedit);
  1284.     SetWindowFont(hedit, NULL, FALSE);
  1285.     DeleteFont(hfont);
  1286.  
  1287.     ghfontApp = NULL;
  1288.  
  1289.     //
  1290.     //  make the window close and terminate the application
  1291.     //
  1292.     DestroyWindow(hwnd);
  1293.  
  1294.     return (0L);
  1295. } // AppClose()
  1296.  
  1297.  
  1298. //--------------------------------------------------------------------------;
  1299. //
  1300. //  BOOL AppInit
  1301. //
  1302. //  Description:
  1303. //      This function is called to initialize a new instance of the
  1304. //      application. We want to parse our command line, create our window,
  1305. //      allocate resources, etc.
  1306. //
  1307. //      The arguments passed to this function are exactly the same as
  1308. //      those passed to WinMain.
  1309. //
  1310. //  Arguments:
  1311. //      HINSTANCE hinst: Identifies the current instance of the
  1312. //      application.
  1313. //
  1314. //      HINSTANCE hinstPrev: Identifies the previous instance of the
  1315. //      application (NULL if first instance). For Win 32, this argument
  1316. //      is _always_ NULL.
  1317. //
  1318. //      LPTSTR pszCmdLine: Points to null-terminated unparsed command line.
  1319. //      If the application is compiled for Unicode, then this argument is
  1320. //      ignored.
  1321. //
  1322. //      int nCmdShow: How the main window for the application is to be
  1323. //      shown by default.
  1324. //
  1325. //  Return (HWND):
  1326. //      Returns the newly created handle to the applications main window.
  1327. //      This handle is NULL if something went wrong and tells the application
  1328. //      to exit immediately.
  1329. //
  1330. //
  1331. //--------------------------------------------------------------------------;
  1332.  
  1333. HWND FNGLOBAL AppInit
  1334. (
  1335.     HINSTANCE               hinst,
  1336.     HINSTANCE               hinstPrev,
  1337.     LPTSTR                  pszCmdLine,
  1338.     int                     nCmdShow
  1339. )
  1340. {
  1341.     HWND                hwnd;
  1342.     WNDCLASS            wc;
  1343.  
  1344.     DPF(1, "AppInit(hinst=%Xh, hinstPrev=%Xh, pszCmdLine='%s', nCmdShow=%d)",
  1345.             hinst, hinstPrev, pszCmdLine, nCmdShow);
  1346.  
  1347.     LoadString(hinst, IDS_APP_NAME, gszAppName, SIZEOF(gszAppName));
  1348.     LoadString(hinst, IDS_FILE_UNTITLED, gszFileUntitled, SIZEOF(gszFileUntitled));
  1349.  
  1350.  
  1351.     //
  1352.     //  determine whether a new window class needs to be registered for
  1353.     //  this application. for Win 16, this only needs to be done for the
  1354.     //  first instance of the application created. for Win 32, this must
  1355.     //  be done for EVERY instance of the application.
  1356.     //
  1357.     if (NULL == hinstPrev)
  1358.     {
  1359.         wc.style         = CS_HREDRAW | CS_VREDRAW;
  1360.         wc.lpfnWndProc   = (WNDPROC)AppWndProc;
  1361.         wc.cbClsExtra    = 0;
  1362.         wc.cbWndExtra    = 0;
  1363.         wc.hInstance     = hinst;
  1364.         wc.hIcon         = LoadIcon(hinst, ICON_APP);
  1365.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  1366.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  1367.         wc.lpszMenuName  = MENU_APP;
  1368.         wc.lpszClassName = gszAppName;
  1369.  
  1370.         if (!RegisterClass(&wc))
  1371.             return (NULL);
  1372.     }
  1373.  
  1374.  
  1375.     //
  1376.     //  if Windows for Pen Computing is installed, then allow the RC
  1377.     //  Manager to replace all edit controls created from this point on
  1378.     //  with hedit controls
  1379.     //
  1380.     AppRegisterPenApp(TRUE);
  1381.  
  1382.  
  1383.     //
  1384.     //  create the application's main window
  1385.     //
  1386.     //  style bits available:
  1387.     //      WS_EX_ACCEPTFILES   :  will receive WM_DROPFILES messages
  1388.     //      WS_EX_DLGMODALFRAME :  creates window with double border
  1389.     //      WS_EX_NOPARENTNOTIFY:  won't receive WM_PARENTNOTIFY messages
  1390.     //      WS_EX_TOPMOST       :  puts window in topmost space
  1391.     //      WS_EX_TRANSPARENT   :  a very bizarre style indeed (Win 16 only)
  1392.     //
  1393.     hwnd = CreateWindowEx(WS_EX_ACCEPTFILES | WS_EX_NOPARENTNOTIFY,
  1394.                           gszAppName,
  1395.                           gszAppName,
  1396.                           WS_OVERLAPPEDWINDOW,
  1397.                           APP_WINDOW_XOFFSET,
  1398.                           APP_WINDOW_YOFFSET,
  1399.                           APP_WINDOW_WIDTH,
  1400.                           APP_WINDOW_HEIGHT,
  1401.                           NULL,
  1402.                           NULL,
  1403.                           hinst,
  1404.                           NULL);
  1405.  
  1406.     if (NULL == hwnd)
  1407.         return (NULL);
  1408.  
  1409.  
  1410. #ifdef UNICODE
  1411.     //
  1412.     //  GetCommandLine() returns a pointer to our command line. but this
  1413.     //  command line includes the complete command line used to launch
  1414.     //  the application--which is different than the pszCmdLine argument
  1415.     //  passed through WinMain()...
  1416.     //
  1417.     //  so, skip over the command name to get to the argument string
  1418.     //
  1419.     pszCmdLine = GetCommandLine();
  1420.     if (NULL != pszCmdLine)
  1421.     {
  1422.         while (('\0' != *pszCmdLine) && (' ' != *pszCmdLine++))
  1423.             ;
  1424.     }
  1425. #endif
  1426.  
  1427.  
  1428.     //
  1429.     //
  1430.     //
  1431.     //
  1432.     AcmAppInit(hwnd, &gaafd, pszCmdLine, nCmdShow);
  1433.  
  1434.  
  1435.     //
  1436.     //  finally, get the window displayed and return success
  1437.     //
  1438.     //  the ShowWindow call is made during AcmAppInit
  1439.     //
  1440. //  ShowWindow(hwnd, nCmdShow);
  1441. //  UpdateWindow(hwnd);
  1442.  
  1443.     return (hwnd);
  1444. } // AppInit()
  1445.  
  1446.  
  1447. //--------------------------------------------------------------------------;
  1448. //
  1449. //  int AppExit
  1450. //
  1451. //  Description:
  1452. //      This function is called just before the application exits from
  1453. //      WinMain. Its purpose is to clean up any resources that were allocated
  1454. //      for running the application: brushes, heaps, etc..
  1455. //
  1456. //  Arguments:
  1457. //      HINSTANCE hinst: Identifies the current instance of the
  1458. //      application that is exiting.
  1459. //
  1460. //      int nResult: The result of the WM_QUIT message (in wParam of the
  1461. //      MSG structure. This argument will usually be 0 (even if the message
  1462. //      loop was never entered).
  1463. //
  1464. //  Return (int):
  1465. //      The return value is usually nResult--be we give this function the
  1466. //      opportunity to modify its value.
  1467. //
  1468. //
  1469. //--------------------------------------------------------------------------;
  1470.  
  1471. int FNGLOBAL AppExit
  1472. (
  1473.     HINSTANCE               hinst,
  1474.     int                     nResult
  1475. )
  1476. {
  1477.     DPF(1, "AppExit(hinst=%Xh, nResult=%d)", hinst, nResult);
  1478.  
  1479.     AcmAppExit();
  1480.  
  1481.     //
  1482.     //  if Windows for Pen Computing is installed, then de-register the
  1483.     //  application so the RC Manager knows we will no longer need its
  1484.     //  services...
  1485.     //
  1486.     AppRegisterPenApp(FALSE);
  1487.  
  1488.     return (nResult);
  1489. } // AppExit()
  1490.  
  1491.  
  1492. //==========================================================================;
  1493. //
  1494. //  Misc rarely used application dialogs and stuff...
  1495. //
  1496. //
  1497. //==========================================================================;
  1498.  
  1499. //--------------------------------------------------------------------------;
  1500. //
  1501. //  BOOL AboutDlgProc
  1502. //
  1503. //  Description:
  1504. //      This dialog procedure is used for the ubiquitous about box.
  1505. //
  1506. //  Arguments:
  1507. //      HWND hwnd: Handle to window.
  1508. //
  1509. //      UINT uMsg: Message being sent to the window.
  1510. //
  1511. //      WPARAM wParam: Specific argument to message.
  1512. //
  1513. //      LPARAM lParam: Specific argument to message.
  1514. //
  1515. //  Return (BOOL):
  1516. //      The return value is specific to the message that was received. For
  1517. //      the most part, it is FALSE if this dialog procedure does not handle
  1518. //      a message.
  1519. //
  1520. //
  1521. //--------------------------------------------------------------------------;
  1522.  
  1523. BOOL FNEXPORT AboutDlgProc
  1524. (
  1525.     HWND                    hwnd,
  1526.     UINT                    uMsg,
  1527.     WPARAM                  wParam,
  1528.     LPARAM                  lParam
  1529. )
  1530. {
  1531.     UINT                u;
  1532.  
  1533.     switch (uMsg)
  1534.     {
  1535.         case WM_INITDIALOG:
  1536.             return (TRUE);
  1537.  
  1538.         case WM_COMMAND:
  1539.             u = GET_WM_COMMAND_ID(wParam, lParam);
  1540.             if ((IDOK == u) || (IDCANCEL == u))
  1541.             {
  1542.                 EndDialog(hwnd, (IDOK == u));
  1543.             }
  1544.             break;
  1545.     }
  1546.  
  1547.     return (FALSE);
  1548. } // AboutDlgProc()
  1549.