home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / tutsamp / perclien / perclien.cpp < prev    next >
C/C++ Source or Header  |  1997-08-30  |  29KB  |  808 lines

  1. /*+==========================================================================
  2.   File:      PERCLIEN.CPP
  3.  
  4.   Summary:   Main implementation for the PERCLIEN client application. This
  5.              client loads and accesses the connectable COPageList COM
  6.              object housed in a separate in-process COM Server (PERSERVE
  7.              built in the sibling PERSERVE directory). The COPageList COM
  8.              object is persistent and manages the page list data.
  9.  
  10.              Using the data in COPageList, PERCLIEN displays the page list
  11.              and allows the user to create, open, and edit various page
  12.              types kept in the list. The page editing is done in separate
  13.              child windows. Each page type has data that is managed by
  14.              appropriate COM servers. The PERTEXT server houses COTextPage
  15.              COM objects. The PERDRAW server houses CODrawPage COM
  16.              objects. The COPageList, COTextPage, and CODrawPage objects
  17.              each use a different kind of COM object persistence.
  18.              COPageList exposes IPersistStream for its persistence
  19.              features. COTextPage exposes IPersistStreamInit. CODrawPage
  20.              exposes IPersistStorage.
  21.  
  22.              All of the data content in the page list, text pages, and
  23.              draw pages is stored in one compound file managed by this
  24.              PERCLIEN client. Files of this type have the .PAG extension.
  25.  
  26.              To run PERCLIEN you must build the PERSERVE, PERTEXT, and
  27.              PERDRAW samples first.
  28.  
  29.              For a comprehensive tutorial code tour of PERCLIEN's contents
  30.              and offerings see the tutorial PERCLIEN.HTM file. For
  31.              more specific technical details on the internal workings see
  32.              the comments dispersed throughout the PERCLIEN source code.
  33.              For more details on the PERSERVE.DLL that PERCLIEN works with
  34.              see the PERSERVE.HTM file in the main tutorial directory.
  35.              For more details on the PERTEXT.DLL that PERCLIEN works with
  36.              see the PERTEXT.HTM file in the main tutorial directory.
  37.              For more details on the PERDRAW.DLL that PERCLIEN works with
  38.              see the PERDRAW.HTM file in the main tutorial directory.
  39.  
  40.   Classes:   CMainWindow.
  41.  
  42.   Functions: InitApplication, WinMain
  43.  
  44.   Origin:    5-24-96: atrent - Editor-inheritance from the STOCLIEN source.
  45.  
  46. ----------------------------------------------------------------------------
  47.   This file is part of the Microsoft COM Tutorial Code Samples.
  48.  
  49.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  50.  
  51.   This source code is intended only as a supplement to Microsoft
  52.   Development Tools and/or on-line documentation.  See these other
  53.   materials for detailed information regarding Microsoft code samples.
  54.  
  55.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  56.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  57.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  58.   PARTICULAR PURPOSE.
  59. ==========================================================================+*/
  60.  
  61. /*--------------------------------------------------------------------------
  62.   We include WINDOWS.H for all Win32 applications.
  63.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  64.   We include OLECTL.H because it has definitions for connectable objects.
  65.   We include INITGUID.H only once (here) in the entire app because we
  66.     will be defining GUIDs and want them as constants in the data segment.
  67.   We include COMMDLG.H because we will be using the Open File
  68.     and potentially other Common dialogs.
  69.   We include APPUTIL.H because we will be building this application using
  70.     the convenient Virtual Window and Dialog classes and other
  71.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  72.   We include IPAGES.H and PAGEGUID.H for the common page-related Interface
  73.     class, GUID, and CLSID specifications.
  74.   We include RESDEF.H because it has the resource definitions specific
  75.     to this application.
  76.   We include PAGEFILE.H because it has the C++ class used for compound file
  77.     storage of page list data.
  78.   We include LISTWIN.H because CGuiList creates and uses a CListWin to
  79.     encapsulate the standard listbox control window.
  80.   We include GUILIST.H because it has the C++ class used for GUI display
  81.     of the page list.
  82.   We include PERCLIEN.H because it has the CMainWindow class definition.
  83. ---------------------------------------------------------------------------*/
  84. #include <windows.h>
  85. #include <ole2.h>
  86. #include <olectl.h>
  87. #include <initguid.h>
  88. #include <commdlg.h>
  89. #include <apputil.h>
  90. #include <ipages.h>
  91. #include <pageguid.h>
  92. #include "resdef.h"
  93. #include "pagefile.h"
  94. #include "listwin.h"
  95. #include "guilist.h"
  96. #include "perclien.h"
  97.  
  98.  
  99. // Work storage for the user-entered page title.
  100. TCHAR g_szPageTitle[PAGE_TITLE_SIZE] = TEXT(PAGE_UNTITLED_STR);
  101.  
  102.  
  103. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  104.   Method:   CMainWindow::CMainWindow
  105.  
  106.   Summary:  CMainWindow Constructor.
  107.  
  108.   Args:     .
  109.  
  110.   Returns:  .
  111. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  112. CMainWindow::CMainWindow()
  113. {
  114.   // Ensure these member variable strings are null strings.
  115.   m_szFileName[0] = 0;
  116.   m_szFileTitle[0] = 0;
  117.  
  118.   // Fill in the Open File Name Common Dialog's OPENFILENAME structure.
  119.   m_ofnFile.lStructSize = sizeof(OPENFILENAME);
  120.   m_ofnFile.hwndOwner = m_hWnd;
  121.   m_ofnFile.hInstance = m_hInst;
  122.   m_ofnFile.lpstrFilter = TEXT(OFN_DEFAULTFILES_STR);
  123.   m_ofnFile.lpstrCustomFilter = NULL;
  124.   m_ofnFile.nMaxCustFilter = 0;
  125.   m_ofnFile.nFilterIndex = 1;
  126.   m_ofnFile.lpstrFile = m_szFileName;
  127.   m_ofnFile.nMaxFile = MAX_PATH;
  128.   m_ofnFile.lpstrInitialDir = TEXT(".");
  129.   m_ofnFile.lpstrFileTitle = m_szFileTitle;
  130.   m_ofnFile.nMaxFileTitle = MAX_PATH;
  131.   m_ofnFile.lpstrTitle = TEXT(OFN_DEFAULTTITLE_STR);
  132.   m_ofnFile.lpstrDefExt = NULL;
  133.   m_ofnFile.Flags = OFN_HIDEREADONLY;
  134.  
  135.   m_pGuiList = NULL;
  136. }
  137.  
  138.  
  139. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  140.   Method:   CMainWindow::~CMainWindow
  141.  
  142.   Summary:  CMainWindow Destructor.  Destruction of the main window
  143.             indicates that the application should quit and thus the
  144.             PostQuitMessage API is called.
  145.  
  146.   Args:     .
  147.  
  148.   Returns:  .
  149. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  150. CMainWindow::~CMainWindow()
  151. {
  152.   // CMainWindow is derived from CVirWindow which traps the WM_DESTROY
  153.   // message and causes a delete of CMainWindow which in turn causes this
  154.   // destructor to run. The WM_DESTROY results when the window is destoyed
  155.   // after a close of the window. Prior to exiting the main message loop:
  156.  
  157.   // We delete the CGuiList object that was made in InitInstance.
  158.   DELETE_POINTER(m_pGuiList);
  159.  
  160.   // We then post a WM_QUIT message to cause an exit of the main
  161.   // message loop and an exit of this instance of the application.
  162.   PostQuitMessage(0);
  163. }
  164.  
  165.  
  166. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  167.   Method:   CMainWindow::InitInstance
  168.  
  169.   Summary:  Instantiates an instance of the main application window.
  170.             This method must be called only once, immediately after
  171.             window class construction.  We take care to delete 'this'
  172.             CMainWindow if we must return the error condition FALSE.
  173.  
  174.   Args:     HINSTANCE hInstance,
  175.               Handle of the application instance.
  176.             LPSTR pszCmdLine,
  177.               Pointer to the application's invocation command line.
  178.             int nCmdShow)
  179.               Command to pass to ShowWindow.
  180.  
  181.   Modifies: m_szHelpFile
  182.  
  183.   Returns:  BOOL.
  184.               TRUE if succeeded.
  185.               FALSE if failed.
  186. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  187. BOOL CMainWindow::InitInstance(
  188.        HINSTANCE hInstance,
  189.        LPSTR pszCmdLine,
  190.        int nCmdShow)
  191. {
  192.   BOOL bOk = FALSE;
  193.   HWND hWnd = NULL;
  194.   HRESULT hr = E_FAIL;
  195.  
  196.   // Create the CGuiList C++ object.
  197.   m_pGuiList = new CGuiList;
  198.  
  199.   if (NULL != m_pGuiList)
  200.   {
  201.     // Note, the Create method sets the m_hWnd member so we don't
  202.     // need to set it explicitly here first. Here is the create of this
  203.     // window.  Size the window reasonably. Create sets both m_hInst and
  204.     // m_hWnd. This creates the main client window.
  205.     hWnd = Create(
  206.              TEXT(MAIN_WINDOW_CLASS_NAME_STR),
  207.              TEXT(MAIN_WINDOW_TITLE_STR),
  208.              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
  209.                | WS_MAXIMIZEBOX | WS_THICKFRAME,
  210.              CW_USEDEFAULT,
  211.              CW_USEDEFAULT,
  212.              ::GetSystemMetrics(SM_CXSCREEN)*1/3,
  213.              ::GetSystemMetrics(SM_CYSCREEN)*1/3,
  214.              NULL,
  215.              NULL,
  216.              hInstance);
  217.     if (NULL != hWnd)
  218.     {
  219.       if (pszCmdLine[0] == 0)
  220.         pszCmdLine = NULL;
  221.  
  222. #if defined(UNICODE)
  223.       {
  224.         WCHAR wszUc[MAX_PATH];
  225.  
  226.         if (NULL != pszCmdLine)
  227.         {
  228.           // Convert from Ansi to Unicode.
  229.           AnsiToUc(pszCmdLine, wszUc, MAX_PATH);
  230.           // Init the new GuiList.
  231.           bOk = m_pGuiList->Init(m_hInst, m_hWnd, wszUc);
  232.         }
  233.         else
  234.           bOk = m_pGuiList->Init(m_hInst, m_hWnd, NULL);
  235.       }
  236. #else
  237.       // Init the new GuiList.
  238.       bOk = m_pGuiList->Init(m_hInst, m_hWnd, pszCmdLine);
  239. #endif
  240.  
  241.       if (bOk)
  242.       {
  243.         // Ensure the new window is shown on screen and content
  244.         // is painted.
  245.         ::ShowWindow(m_hWnd, nCmdShow);
  246.         ::UpdateWindow(m_hWnd);
  247.  
  248.         // Build a path to where the help file should be (it should be in
  249.         // the same directory as the .EXE but with the .HTM extension).
  250.         MakeFamilyPath(hInstance, m_szHelpFile, TEXT(HELP_FILE_EXT));
  251.  
  252.         // Try to open the page list compound file and populate the
  253.         // main page list. Open either the default PERCLIEN.PAG
  254.         // or the one specified on the invocation command line.
  255.         // Load will create/load the default PERCLIEN.PAG if no specified
  256.         // .PAG file is found.
  257.         hr = m_pGuiList->Load();
  258.         if (SUCCEEDED(hr))
  259.         {
  260.           // If the COPageList COM object was created and reconstituted
  261.           // by loading the .PAG file then show its Page List.
  262.           hr = m_pGuiList->Show(0);
  263.         }
  264.         bOk = SUCCEEDED(hr);
  265.         if (!bOk)
  266.           HrMsgId(m_hInst, m_hWnd, IDS_NOSERVER, hr);
  267.       }
  268.     }
  269.   }
  270.  
  271.   if (!bOk)
  272.   {
  273.     DELETE_POINTER(m_pGuiList);
  274.   }
  275.  
  276.   return (bOk);
  277. }
  278.  
  279.  
  280. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  281.   Method:   CMainWindow::DoCommand
  282.  
  283.   Summary:  Dispatch and handle the main menu commands.
  284.  
  285.   Args:     WPARAM wParam,
  286.               First message parameter.
  287.             LPARAM lParam)
  288.               Second message parameter.
  289.  
  290.   Modifies: m_ofnFile, ...
  291.  
  292.   Returns:  LRESULT
  293.               Standard Windows WindowProc return value.
  294. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  295. LRESULT CMainWindow::DoCommand(
  296.           WPARAM wParam,
  297.           LPARAM lParam)
  298. {
  299.   LRESULT lResult = FALSE;
  300.   HMENU hMenu  = ::GetMenu(m_hWnd);
  301.  
  302.   switch (LOWORD(wParam))
  303.   {
  304.     //----------------------------------------------------------------------
  305.     // Handle File Menu Commands.
  306.     //----------------------------------------------------------------------
  307.     case IDM_FILE_NEW:
  308.       // Create an empty compound file; ask CGuiList to save itself to it.
  309.       m_pGuiList->New();
  310.       break;
  311.     case IDM_FILE_OPEN:
  312.       // Open existing compound file; ask CGuiList to load itself from it.
  313.       m_pGuiList->Open();
  314.       break;
  315.     case IDM_FILE_SAVE:
  316.       // Ask all pages to save to current compound file.
  317.       m_pGuiList->Save();
  318.       break;
  319.     case IDM_FILE_SAVEAS:
  320.       // Create new compound file and ask all pages to save to it.
  321.       m_pGuiList->SaveAs();
  322.       break;
  323.     case IDM_FILE_EXIT:
  324.       // The user commands us to exit this application so we tell the
  325.       // Main window to close itself.
  326.       ::PostMessage(m_hWnd, WM_CLOSE, 0, 0);
  327.       break;
  328.  
  329.     //----------------------------------------------------------------------
  330.     // Handle Page Menu Commands.
  331.     //----------------------------------------------------------------------
  332.     case IDM_PAGE_OPEN:
  333.       // Open the selected page in the list.
  334.       m_pGuiList->PageOpen();
  335.       break;
  336.     case IDM_PAGE_TITLE:
  337.       // Edit a new title for the selected page in the list.
  338.       m_pGuiList->PageTitle();
  339.       break;
  340.     case IDM_PAGE_NEWTEXT:
  341.       // Create new Text page.
  342.       m_pGuiList->PageAdd(PAGETYPE_TEXT);
  343.       break;
  344.     case IDM_PAGE_NEWDRAW:
  345.       // Create new Drawing page.
  346.       m_pGuiList->PageAdd(PAGETYPE_DRAWING);
  347.       break;
  348.     case IDM_PAGE_DELETE:
  349.       // Delete the selected page in the list.
  350.       m_pGuiList->PageDelete();
  351.       break;
  352.  
  353.     //----------------------------------------------------------------------
  354.     // Handle Help Menu Commands.
  355.     //----------------------------------------------------------------------
  356.     case IDM_HELP_CONTENTS:
  357.       // We have some stubbed support here for bringing up the main online
  358.       // Help for this application. Assumed to be in an .HTM file located
  359.       // next to the .EXE file of the current executable.
  360.       ReadHelp(m_hWnd, m_szHelpFile);
  361.       break;
  362.     case IDM_HELP_TUTORIAL:
  363.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  364.       // tutorial narrative file associated with this tutorial code sample.
  365.       ReadTutorial(m_hInst, m_hWnd, TEXT(HTML_FILE_EXT));
  366.       break;
  367.     case IDM_HELP_PERSERVE:
  368.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  369.       // tutorial narrative file associated with the PERSERVE COM server.
  370.       ReadTutorial(m_hInst, m_hWnd, TEXT(SERVER_PERSERVE_STR));
  371.       break;
  372.     case IDM_HELP_PERTEXT:
  373.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  374.       // tutorial narrative file associated with the PERTEXT COM server.
  375.       ReadTutorial(m_hInst, m_hWnd, TEXT(SERVER_PERTEXT_STR));
  376.       break;
  377.     case IDM_HELP_PERDRAW:
  378.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  379.       // tutorial narrative file associated with the PERDRAW COM server.
  380.       ReadTutorial(m_hInst, m_hWnd, TEXT(SERVER_PERDRAW_STR));
  381.       break;
  382.     case IDM_HELP_READSOURCE:
  383.       // Call the APPUTIL utility function ReadSource to allow the
  384.       // user to open and read any of the source files of PERCLIEN.
  385.       ReadSource(m_hWnd, &m_ofnFile);
  386.       break;
  387.     case IDM_HELP_ABOUT:
  388.       {
  389.         CAboutBox dlgAboutBox;
  390.  
  391.         // Show the standard About Box dialog for this EXE by telling the
  392.         // dialog C++ object to show itself by invoking its ShowDialog
  393.         // method.  Pass it this EXE instance and the parent window handle.
  394.         // Use a dialog resource ID for the dialog template stored in
  395.         // this EXE module's resources.
  396.         dlgAboutBox.ShowDialog(
  397.           m_hInst,
  398.           MAKEINTRESOURCE(IDM_HELP_ABOUT),
  399.           m_hWnd);
  400.       }
  401.       break;
  402.  
  403.     //----------------------------------------------------------------------
  404.     // Handle ListWin Commands (ie, from the child list box control).
  405.     //----------------------------------------------------------------------
  406.     case IDC_LISTWIN:
  407.       switch (HIWORD(wParam))
  408.       {
  409.         case LBN_DBLCLK:
  410.           // User Double Clicked. Open the selected page in the list.
  411.           m_pGuiList->PageOpen();
  412.           break;
  413.         case LBN_SELCHANGE:
  414.           // User changed the page selection.
  415.           break;
  416.         default:
  417.           break;
  418.       }
  419.       break;
  420.  
  421.     default:
  422.       // Defer all messages NOT handled here to the Default Window Proc.
  423.       lResult = ::DefWindowProc(m_hWnd, WM_COMMAND, wParam, lParam);
  424.       break;
  425.   }
  426.  
  427.   return(lResult);
  428. }
  429.  
  430.  
  431. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  432.   Method:   CDlgPageProps::DialogProc
  433.  
  434.   Summary:  Dialog proc for the Page Properties dialog box. This
  435.             DialogProc method definition overrides the same-named pure
  436.             virtual function in abstract base class CVirDialog thus giving
  437.             unique message dispatching behavior to this derivation of
  438.             CVirDialog. The remaining behavior of CDlgPageProps is
  439.             inherited from CVirDialog and is common to all CVirDialogs.
  440.  
  441.   Args:     HWND hWndDlg,
  442.               Handle to the dialog.
  443.             UINT uMsg,
  444.               Windows message to dialog.
  445.             WPARAM wParam,
  446.               First message parameter (word sized).
  447.             LPARAM lParam)
  448.               Second message parameter (long sized).
  449.  
  450.   Returns:  BOOL.  TRUE if message was handled; FALSE otherwise.
  451. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  452. BOOL CDlgPageProps::DialogProc(
  453.        HWND hWndDlg,
  454.        UINT uMsg,
  455.        WPARAM wParam,
  456.        LPARAM lParam)
  457. {
  458.   BOOL bResult = TRUE;
  459.   HWND hCtrl = GetDlgItem(hWndDlg, IDC_EDIT_PGTITLE);
  460.  
  461.   switch (uMsg)
  462.   {
  463.     case WM_INITDIALOG:
  464.       SetDlgItemText(hWndDlg, IDC_EDIT_PGTITLE, g_szPageTitle);
  465.       SetFocus(hCtrl);
  466.       bResult = FALSE;
  467.       break;
  468.  
  469.     case WM_COMMAND:
  470.       {
  471.         WORD wCmd = LOWORD(wParam);
  472.  
  473.         if (wCmd == IDOK)
  474.         {
  475.           // Obtain the machine name from the edit control and store
  476.           // it where other functions can get it.
  477.           GetDlgItemText(
  478.             hWndDlg,
  479.             IDC_EDIT_PGTITLE,
  480.             g_szPageTitle,
  481.             PAGE_TITLE_SIZE);
  482.           ::EndDialog(hWndDlg, TRUE);
  483.         }
  484.         else if (wCmd == IDCANCEL)
  485.           ::EndDialog(hWndDlg, FALSE);
  486.       }
  487.       break;
  488.  
  489.     default:
  490.       bResult = FALSE;
  491.       break;
  492.   }
  493.  
  494.   return(bResult);
  495. }
  496.  
  497.  
  498. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  499.   Method:   CMainWindow::WindowProc
  500.  
  501.   Summary:  Main window procedure for this window object.  See CVirWindow
  502.             in the APPUTIL library (APPUTIL.CPP) for details on how this
  503.             method gets called by the global WindowProc.
  504.  
  505.   Args:     UINT uMsg,
  506.               Windows message that is "sent" to this window.
  507.             WPARAM wParam,
  508.               First message parameter.
  509.             LPARAM lParam)
  510.               Second message parameter.
  511.  
  512.   Returns:  LRESULT
  513.               Standard Windows WindowProc return value.
  514. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  515. LRESULT CMainWindow::WindowProc(
  516.           UINT uMsg,
  517.           WPARAM wParam,
  518.           LPARAM lParam)
  519. {
  520.   LRESULT lResult = FALSE;
  521.  
  522.   switch (uMsg)
  523.   {
  524.     case WM_CREATE:
  525.       break;
  526.  
  527.     case WM_SIZE:
  528.       // Handle a resize of this window.
  529.       m_wWidth = LOWORD(lParam);
  530.       m_wHeight = HIWORD(lParam);
  531.       // Inform CGuiList and CListWin of the change.
  532.       m_pGuiList->Resize(m_wWidth, m_wHeight);
  533.       break;
  534.  
  535.     case WM_COMMAND:
  536.       // Dispatch and handle any Menu command messages received.
  537.       lResult = DoCommand(wParam, lParam);
  538.       break;
  539.  
  540.     case WM_USER_PAGECHANGED:
  541.       // An open page was edit/changed.
  542.       m_pGuiList->PageChanged(lParam);
  543.       break;
  544.  
  545.     case WM_USER_PAGECLOSED:
  546.       // A separate page edit window was closed.
  547.       m_pGuiList->PageClosed(lParam);
  548.       break;
  549.  
  550.     case WM_CHAR:
  551.       if (wParam == 0x1b)
  552.       {
  553.         // Exit this app if user hits ESC key.
  554.         ::PostMessage(m_hWnd, WM_CLOSE, 0, 0);
  555.       }
  556.       break;
  557.  
  558.     case WM_CLOSE:
  559.       // The user selected Close on the main window's System menu
  560.       // or Exit on the File menu.
  561.       // If there is data that has not been saved then ask user
  562.       // if it should be saved. If user cancels then cancel the exit.
  563.       if (IDCANCEL == m_pGuiList->AskSave())
  564.         break;
  565.     case WM_QUIT:
  566.       // If the app is being quit then close any associated help windows.
  567.     default:
  568.       // Defer all messages NOT handled above to the Default Window Proc.
  569.       lResult = ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
  570.       break;
  571.   }
  572.  
  573.   return(lResult);
  574. }
  575.  
  576.  
  577. /*F+F++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  578.   Function: UnicodeOk
  579.  
  580.   Summary:  Checks if the platform will handle unicode versions of
  581.             Win32 string API calls.
  582.  
  583.   Args:     void
  584.  
  585.   Returns:  BOOL
  586.               TRUE if unicode support; FALSE if not.
  587. ------------------------------------------------------------------------F-F*/
  588. BOOL UnicodeOk(void)
  589. {
  590.   BOOL bOk = TRUE;
  591.   TCHAR szUserName[MAX_STRING_LENGTH];
  592.   DWORD dwSize = MAX_STRING_LENGTH;
  593.  
  594.   if (!GetUserName(szUserName, &dwSize))
  595.     bOk = ERROR_CALL_NOT_IMPLEMENTED == GetLastError() ? FALSE : TRUE;
  596.  
  597.   return bOk;
  598. }
  599.  
  600.  
  601. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  602.   Function: InitApplication
  603.  
  604.   Summary:  Initializes the application and registers its main window
  605.             class. InitApplication is called only once (in WinMain).
  606.  
  607.   Args:     HINSTANCE hInstance)
  608.               Handle to the first instance of the application.
  609.  
  610.   Returns:  BOOL.
  611.               TRUE if success.
  612.               FALSE if fail.
  613. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  614. BOOL InitApplication(
  615.        HINSTANCE hInstance)
  616. {
  617.   BOOL bOk;
  618.   // The window class for all instances of the main frame window.
  619.   WNDCLASSEX wcf;
  620.  
  621.   // Assign the appropriate values for this main frame window class.
  622.   wcf.cbSize        = sizeof(WNDCLASSEX);
  623.   wcf.cbClsExtra    = 0;            // No per-class extra data.
  624.   wcf.cbWndExtra    = 0;            // No per-window extra data.
  625.   wcf.hInstance     = hInstance;    // Application module instance.
  626.   wcf.lpfnWndProc   = &WindowProc;  // Global Window Procedure (defined in
  627.                                     // APPUTIL for all CVirWindows).
  628.   wcf.hCursor       = LoadCursor(NULL, IDC_ARROW); // Load app cursor.
  629.   wcf.hIcon         = (HICON) LoadIcon(            // Load app icon.
  630.                                 hInstance,
  631.                                 TEXT("AppIcon"));
  632.   wcf.hIconSm       = (HICON) LoadImage(           // Load small icon.
  633.                                 hInstance,
  634.                                 TEXT("AppIcon"),
  635.                                 IMAGE_ICON,
  636.                                 16, 16,
  637.                                 0);
  638.   wcf.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);  // Default backgnd color.
  639.   wcf.style         = CS_HREDRAW | CS_VREDRAW;          // Class style(s).
  640.   wcf.lpszClassName = TEXT(MAIN_WINDOW_CLASS_NAME_STR); // Class name.
  641.   wcf.lpszMenuName  = TEXT(MAIN_WINDOW_CLASS_MENU_STR); // Menu name.
  642.   // Register the window class and return FALSE if unsuccesful.
  643.   bOk = RegisterClassEx(&wcf);
  644.  
  645.   if (bOk)
  646.   {
  647.     // Assign the appropriate values for the text page window class.
  648.     wcf.lpszClassName = TEXT(TEXT_WINDOW_CLASS_NAME_STR); // Class name.
  649.     wcf.lpszMenuName  = TEXT(TEXT_WINDOW_CLASS_MENU_STR); // Menu name.
  650.     // Register the window class and return FALSE if unsuccesful.
  651.     bOk = RegisterClassEx(&wcf);
  652.   }
  653.  
  654.   if (bOk)
  655.   {
  656.     // Assign the appropriate values for the drawing page window class.
  657.     wcf.hCursor       = LoadCursor(                  // Load pen cursor.
  658.                           hInstance,
  659.                           TEXT("PenCursor"));
  660.     wcf.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); // Backgnd color.
  661.     wcf.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Class style(s).
  662.     wcf.lpszClassName = TEXT(DRAW_WINDOW_CLASS_NAME_STR);   // Class name.
  663.     wcf.lpszMenuName  = TEXT(DRAW_WINDOW_CLASS_MENU_STR);   // Menu name.
  664.     // Register the window class and return FALSE if unsuccesful.
  665.     bOk = RegisterClassEx(&wcf);
  666.   }
  667.  
  668.   return (bOk);
  669. }
  670.  
  671.  
  672. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  673.   Function: WinMain
  674.  
  675.   Summary:  The Windows main entry point function for this application.
  676.             Initializes the application, the COM Libraries, and starts
  677.             the main application message loop.
  678.  
  679.   Args:     HINSTANCE hInstance,
  680.               Instance handle; a new one for each invocation of this app.
  681.             HINSTANCE hPrevInstance,
  682.               Instance handle of the previous instance. NULL in Win32.
  683.             LPSTR pszCmdLine,
  684.               Windows passes a pointer to the application's
  685.               invocation command line.
  686.             int nCmdShow)
  687.               Bits telling the show state of the application.
  688.  
  689.   Returns:  int
  690.               msg.wParam (upon exit of message loop).
  691.               FALSE if this instance couldn't initialize and run.
  692. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  693. extern "C" int PASCAL WinMain(
  694.                         HINSTANCE hInstance,
  695.                         HINSTANCE hPrevInstance,
  696.                         LPSTR pszCmdLine,
  697.                         int nCmdShow)
  698. {
  699.   CMainWindow* pWin = NULL;
  700.   MSG msg;
  701.   HACCEL hAccel;
  702.   int iRun = FALSE;
  703.  
  704.   // If we were compiled for UNICODE and the platform seems OK with this
  705.   // then proceed.  Else we error and exit the app.
  706.   if (UnicodeOk())
  707.   {
  708.     // Call to initialize the COM Library.  Use the SUCCEEDED macro
  709.     // to detect success.  If fail then exit app with error message.
  710.     // Tell COM that this client process and all subordinate threads
  711.     // will live in an apartment threaded world.
  712.     if (SUCCEEDED(CoInitialize(NULL)))
  713.     {
  714.       // If we succeeded in initializing the COM Library we proceed to
  715.       // initialize the application.  If we can't init the application
  716.       // then we signal shut down with an error message exit.
  717.       iRun = InitApplication(hInstance);
  718.       if (iRun)
  719.       {
  720.         // Assume we'll set iRun to TRUE when initialization is done.
  721.         iRun = FALSE;
  722.         // We are still go for running so we try to create a nifty new
  723.         // CMainWindow object for this app instance.
  724.         pWin = new CMainWindow;
  725.         if (NULL != pWin)
  726.         {
  727.           // Now we initialize an instance of the new CMainWindow.
  728.           // This includes creating the main window.  Note: if
  729.           // InitInstance fails then it would have already deleted
  730.           // pWin so we wouldn't need to delete it here.
  731.           if (pWin->InitInstance(hInstance, pszCmdLine, nCmdShow))
  732.           {
  733.             // Load the keyboard accelerators from the resources.
  734.             hAccel = LoadAccelerators(hInstance, TEXT("AppAccel"));
  735.             if (NULL != hAccel)
  736.             {
  737.               // Signal App Initialization is successfully done.
  738.               iRun = TRUE;
  739.             }
  740.           }
  741.         }
  742.       }
  743.  
  744.       if (iRun)
  745.       {
  746.         // If we initialized the app instance properly then we are still
  747.         // go for running.  We then start up the main message pump for
  748.         // the application.
  749.         while (GetMessage(&msg, NULL, 0, 0))
  750.         {
  751.           if (!TranslateAccelerator(pWin->GetHwnd(), hAccel, &msg))
  752.           {
  753.             TranslateMessage(&msg);
  754.             DispatchMessage(&msg);
  755.           }
  756.         }
  757.  
  758.         // We also ask COM to unload any unused COM Servers, including our
  759.         // friend, PERSERVE.
  760.         CoFreeUnusedLibraries();
  761.  
  762.         // We'll pass to Windows the reason why we exited the message loop.
  763.         iRun = msg.wParam;
  764.       }
  765.       else
  766.       {
  767.         // We failed to Initialize the application. Put up error message
  768.         // box saying that application couldn't be initialized.  Parent
  769.         // window is desktop (ie, NULL).
  770.         ErrorBox(hInstance, NULL, IDS_APPINITFAILED);
  771.         DELETE_POINTER(pWin);
  772.       }
  773.  
  774.       // We're exiting this app (either normally or by init failure) so
  775.       // shut down the COM Library.
  776.       CoUninitialize();
  777.     }
  778.     else
  779.     {
  780.       // We failed to Initialize the COM Library. Put up error message box
  781.       // saying that COM Library couldn't be initialized.  Parent window
  782.       // is desktop (ie, NULL).
  783.       ErrorBox(hInstance, NULL, IDS_COMINITFAILED);
  784.     }
  785.   }
  786.   else
  787.   {
  788.     // If we were compiled for UNICODE but the platform has problems with
  789.     // this then indicate an error and exit the app immediately.
  790.     CHAR szMsg[MAX_STRING_LENGTH];
  791.  
  792.     if (LoadStringA(
  793.           hInstance,
  794.           IDS_NOUNICODE,
  795.           szMsg,
  796.           MAX_STRING_LENGTH))
  797.     {
  798.       MessageBoxA(
  799.         NULL,
  800.         szMsg,
  801.         ERROR_TITLE_STR,
  802.         MB_OK | MB_ICONEXCLAMATION);
  803.     }
  804.   }
  805.  
  806.   return iRun;
  807. }
  808.