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

Windows编程

开发平台:

Visual C++

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