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 / mciapp / appinit.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  46KB  |  1,457 lines

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