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 / conclien / conclien.cpp next >
C/C++ Source or Header  |  1997-08-30  |  25KB  |  698 lines

  1. /*+==========================================================================
  2.   File:      CONCLIEN.CPP
  3.  
  4.   Summary:   Based largely on the FRECLIEN.EXE application code, this
  5.              client loads and accesses the Connectable DllSndBall
  6.              component provided in a separate in-process COM Server
  7.              (CONSERVE built in the sibling CONSERVE directory).  Thus to
  8.              run CONCLIEN you must build CONSERVE first. This client
  9.              application is meant to exercise the CONSERVE in-process
  10.              server and illustrate the use of event sinks in the client
  11.              which connect to connection points in the server-housed
  12.              connectable object, COBall.  This objec maintains logic and
  13.              data to simulate a ball bouncing inside of an enclosed
  14.              2-dimensional area. The client continuously moves and
  15.              displays the virtual ball and listens for sink notifications
  16.              when the ball bounces. Different Sounds are issued when the
  17.              ball hits and bounces off the top, sides, and bottom of the
  18.              bounding rectangle.
  19.  
  20.              There is no GUI behavior in the server--it is all in this
  21.              client.  This client instantiates one instance of the
  22.              server's COBall COM object and then moves and displays it.
  23.              There is a minimal menu in CONCLIEN. All the action is
  24.              automatic. The main application window's client area is used
  25.              for visual display of the moving ball.
  26.  
  27.              For a comprehensive tutorial code tour of CONCLIEN's contents
  28.              and offerings see the tutorial CONCLIEN.HTM file. For
  29.              more specific technical details on the internal workings see
  30.              the comments dispersed throughout the CONCLIEN source code.
  31.              For more details on the CONSERVE.DLL that CONCLIEN works with
  32.              see the CONSERVE.HTM file in the main tutorial directory.
  33.  
  34.   Classes:   CMainWindow
  35.  
  36.   Functions: InitApplication, WinMain
  37.  
  38.   Origin:    5-30-96: atrent - Editor-inheritance from the FRECLIEN source.
  39.  
  40. ----------------------------------------------------------------------------
  41.   This file is part of the Microsoft COM Tutorial Code Samples.
  42.  
  43.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  44.  
  45.   This source code is intended only as a supplement to Microsoft
  46.   Development Tools and/or on-line documentation.  See these other
  47.   materials for detailed information regarding Microsoft code samples.
  48.  
  49.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  50.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  51.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  52.   PARTICULAR PURPOSE.
  53. ==========================================================================+*/
  54.  
  55. /*--------------------------------------------------------------------------
  56.   We include WINDOWS.H for all Win32 applications.
  57.   We include OLE2.H because we will be calling the COM/OLE libraries.
  58.   We include OLECTL.H because it has definitions for connectable objects.
  59.   We include INITGUID.H only once (here) in the entire app because we
  60.     will be defining GUIDs and want them as constants in the data segment.
  61.   We include COMMDLG.H because we will be using the Open File and
  62.     potentially other Common dialogs.
  63.   We include APPUTIL.H because we will be building this application using
  64.     the convenient Virtual Window and Dialog classes and other
  65.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  66.   We include IBALL.H and BALLGUID.H for the common Ball-related Interface
  67.     class, GUID, and CLSID specifications.
  68.   We include GUIBALL.H because it has the C++ class used for GUI display
  69.     of the moving ball.
  70.   We include CONCLIEN.H because it has class and resource definitions
  71.     specific to this CONCLIEN application.
  72. ---------------------------------------------------------------------------*/
  73. #include <windows.h>
  74. #include <ole2.h>
  75. #include <olectl.h>
  76. #include <initguid.h>
  77. #include <commdlg.h>
  78. #include <apputil.h>
  79. #include <iball.h>
  80. #include <ballguid.h>
  81. #include "guiball.h"
  82. #include "conclien.h"
  83.  
  84.  
  85. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  86.   Method:   CMainWindow::CMainWindow
  87.  
  88.   Summary:  CMainWindow Constructor.
  89.  
  90.   Args:     .
  91.  
  92.   Modifies: .
  93.  
  94.   Returns:  .
  95. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  96. CMainWindow::CMainWindow()
  97. {
  98.   // Ensure these member variable strings are null strings.
  99.   m_szFileName[0] = 0;
  100.   m_szFileTitle[0] = 0;
  101.  
  102.   // Fill in the Open File Name Common Dialog's OPENFILENAME structure.
  103.   m_ofnFile.lStructSize = sizeof(OPENFILENAME);
  104.   m_ofnFile.hwndOwner = m_hWnd;
  105.   m_ofnFile.hInstance = m_hInst;
  106.   m_ofnFile.lpstrFilter = TEXT(OFN_DEFAULTFILES_STR);
  107.   m_ofnFile.lpstrCustomFilter = NULL;
  108.   m_ofnFile.nMaxCustFilter = 0;
  109.   m_ofnFile.nFilterIndex = 1;
  110.   m_ofnFile.lpstrFile = m_szFileName;
  111.   m_ofnFile.nMaxFile = MAX_PATH;
  112.   m_ofnFile.lpstrInitialDir = TEXT(".");
  113.   m_ofnFile.lpstrFileTitle = m_szFileTitle;
  114.   m_ofnFile.nMaxFileTitle = MAX_PATH;
  115.   m_ofnFile.lpstrTitle = TEXT(OFN_DEFAULTTITLE_STR);
  116.   m_ofnFile.lpstrDefExt = NULL;
  117.   m_ofnFile.Flags = OFN_HIDEREADONLY;
  118.  
  119.   m_pMsgBox  = NULL;
  120.   m_pGuiBall = NULL;
  121. }
  122.  
  123.  
  124. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  125.   Method:   CMainWindow::~CMainWindow
  126.  
  127.   Summary:  CMainWindow Destructor.  Destruction of the main window
  128.             indicates that the application should quit and thus the
  129.             PostQuitMessage API is called.
  130.  
  131.   Args:     .
  132.  
  133.   Modifies: .
  134.  
  135.   Returns:  .
  136. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  137. CMainWindow::~CMainWindow()
  138. {
  139.   // CMainWindow is derived from CVirWindow which traps the WM_DESTROY
  140.   // message and causes a delete of CMainWindow which in turn causes this
  141.   // destructor to run. The WM_DESTROY results when the window is destoyed
  142.   // after a close of the window. Prior to exiting the main message loop:
  143.  
  144.   // We delete the CGuiBall and CMsgBox objects that were made in
  145.   // Initinstance.
  146.   DELETE_POINTER(m_pGuiBall);
  147.   DELETE_POINTER(m_pMsgBox);
  148.  
  149.   // We then post a WM_QUIT message to cause an exit of the main thread's
  150.   // message loop and an exit of this instance of the application.
  151.   PostQuitMessage(0);
  152. }
  153.  
  154.  
  155. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  156.   Method:   CMainWindow::InitInstance
  157.  
  158.   Summary:  Instantiates an instance of the main application window.
  159.             This method must be called only once, immediately after
  160.             window class construction.  We take care to delete 'this'
  161.             CMainWindow if we must return the error condition FALSE.
  162.  
  163.   Args:     HINSTANCE hInstance,
  164.               Handle of the application instance.
  165.             int nCmdShow)
  166.               Command to pass to ShowWindow.
  167.  
  168.   Modifies: m_szHelpFile, m_pMsgBox.
  169.  
  170.   Returns:  BOOL.
  171.               TRUE if succeeded.
  172.               FALSE if failed.
  173. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  174. BOOL CMainWindow::InitInstance(
  175.        HINSTANCE hInstance,
  176.        int nCmdShow)
  177. {
  178.   BOOL bOk = FALSE;
  179.   HWND hWnd = NULL;
  180.   HRESULT hr;
  181.  
  182.   // Create the Message Box and Message Log objects.
  183.   m_pMsgBox = new CMsgBox;
  184.  
  185.   // Create the CGuiBall object.
  186.   m_pGuiBall = new CGuiBall;
  187.  
  188.   if (NULL != m_pMsgBox && NULL != m_pGuiBall)
  189.   {
  190.     // Note, the Create method sets the m_hWnd member so we don't
  191.     // need to set it explicitly here first. Here is the create of this
  192.     // window.  Size the window reasonably. Create sets both m_hInst and
  193.     // m_hWnd. This creates the main client window.
  194.     hWnd = Create(
  195.              TEXT(MAIN_WINDOW_CLASS_NAME_STR),
  196.              TEXT(MAIN_WINDOW_TITLE_STR),
  197.              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
  198.                | WS_MAXIMIZEBOX | WS_THICKFRAME,
  199.              CW_USEDEFAULT,
  200.              CW_USEDEFAULT,
  201.              ::GetSystemMetrics(SM_CXSCREEN)*2/5,
  202.              ::GetSystemMetrics(SM_CYSCREEN)*2/5,
  203.              NULL,
  204.              NULL,
  205.              hInstance);
  206.     if (NULL != hWnd)
  207.     {
  208.       // Init the new GuiBall.
  209.       bOk = m_pGuiBall->Init(m_hWnd);
  210.       if (bOk)
  211.       {
  212.         // Ensure the new window is shown on screen and content
  213.         // is painted.
  214.         ::ShowWindow(m_hWnd, nCmdShow);
  215.         ::UpdateWindow(m_hWnd);
  216.  
  217.         // Build a path to where the help file should be (it should be in
  218.         // the same directory as the .EXE but with the .HTM extension.
  219.         MakeFamilyPath(hInstance, m_szHelpFile, TEXT(HELP_FILE_EXT));
  220.  
  221.         // Init the Message Box object.
  222.         bOk = m_pMsgBox->Init(m_hInst, m_hWnd);
  223.  
  224.         // Connect the new Ball Sink in this client to receive event
  225.         // calls from a COBall source in the server.
  226.         hr = m_pGuiBall->ConnectBallSink();
  227.         if (SUCCEEDED(hr))
  228.         {
  229.           HMENU hMenu  = ::GetMenu(m_hWnd);
  230.  
  231.           ::CheckMenuItem(
  232.               hMenu,
  233.               IDM_SOUND_BALL_ON,
  234.               MF_BYCOMMAND | MF_CHECKED);
  235.           ::CheckMenuItem(
  236.               hMenu,
  237.               IDM_SOUND_BALL_OFF,
  238.               MF_BYCOMMAND | MF_UNCHECKED);
  239.         }
  240.       }
  241.     }
  242.   }
  243.  
  244.   if (!bOk)
  245.   {
  246.     DELETE_POINTER(m_pMsgBox);
  247.     DELETE_POINTER(m_pGuiBall);
  248.   }
  249.  
  250.   return (bOk);
  251. }
  252.  
  253.  
  254. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  255.   Method:   CMainWindow::DoMenu
  256.  
  257.   Summary:  Dispatch and handle the main menu commands.
  258.  
  259.   Args:     WPARAM wParam,
  260.               First message parameter (word sized).
  261.             LPARAM lParam)
  262.               Second message parameter (long sized).
  263.  
  264.   Modifies: m_ofnFile, ...
  265.  
  266.   Returns:  LRESULT
  267.               Standard Windows WindowProc return value.
  268. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  269. LRESULT CMainWindow::DoMenu(
  270.           WPARAM wParam,
  271.           LPARAM lParam)
  272. {
  273.   LRESULT lResult = FALSE;
  274.   HMENU hMenu  = ::GetMenu(m_hWnd);
  275.  
  276.   switch (LOWORD(wParam))
  277.   {
  278.     //----------------------------------------------------------------------
  279.     // Handle File Menu Commands.
  280.     //----------------------------------------------------------------------
  281.     case IDM_FILE_EXIT:
  282.       // The user commands us to exit this application so we tell the
  283.       // Main window to close itself.
  284.       ::PostMessage(m_hWnd, WM_CLOSE, 0, 0);
  285.       break;
  286.  
  287.     //----------------------------------------------------------------------
  288.     // Handle Sound Menu Commands.
  289.     //----------------------------------------------------------------------
  290.     case IDM_SOUND_BALL_ON:
  291.       // Connect the client's sound event Ball Sink to the COBall event
  292.       // source in the server. Set the proper checkmark indicator on
  293.       // the menu selections as well.
  294.       {
  295.         HRESULT hr;
  296.         HMENU hMenu  = ::GetMenu(m_hWnd);
  297.         BOOL bConnected = ::GetMenuState(
  298.                               hMenu,
  299.                               IDM_SOUND_BALL_ON,
  300.                               MF_BYCOMMAND) & MF_CHECKED;
  301.         if (!bConnected)
  302.         {
  303.           hr = m_pGuiBall->ConnectBallSink();
  304.           if (SUCCEEDED(hr))
  305.           {
  306.             ::CheckMenuItem(
  307.                 hMenu,
  308.                 IDM_SOUND_BALL_ON,
  309.                 MF_BYCOMMAND | MF_CHECKED);
  310.             ::CheckMenuItem(
  311.                 hMenu,
  312.                 IDM_SOUND_BALL_OFF,
  313.                 MF_BYCOMMAND | MF_UNCHECKED);
  314.           }
  315.         }
  316.       }
  317.       break;
  318.     case IDM_SOUND_BALL_OFF:
  319.       // Disconnect the client's sound event Ball Sink from the COBall
  320.       // event source in the server. Set the proper checkmark indicator on
  321.       // the menu selections as well.
  322.       {
  323.         HRESULT hr;
  324.         HMENU hMenu  = ::GetMenu(m_hWnd);
  325.         BOOL bDisConnected = ::GetMenuState(
  326.                                 hMenu,
  327.                                 IDM_SOUND_BALL_OFF,
  328.                                 MF_BYCOMMAND) & MF_CHECKED;
  329.         if (!bDisConnected)
  330.         {
  331.           hr = m_pGuiBall->DisconnectBallSink();
  332.           if (SUCCEEDED(hr))
  333.           {
  334.             ::CheckMenuItem(
  335.                 hMenu,
  336.                 IDM_SOUND_BALL_ON,
  337.                 MF_BYCOMMAND | MF_UNCHECKED);
  338.             ::CheckMenuItem(
  339.                 hMenu,
  340.                 IDM_SOUND_BALL_OFF,
  341.                 MF_BYCOMMAND | MF_CHECKED);
  342.           }
  343.         }
  344.       }
  345.       break;
  346.  
  347.     //----------------------------------------------------------------------
  348.     // Handle Help Menu Commands.
  349.     //----------------------------------------------------------------------
  350.     case IDM_HELP_CONTENTS:
  351.       // We have some stubbed support here for bringing up the online
  352.       // Help for this application.
  353.       ReadHelp(m_hWnd, m_szHelpFile);
  354.       break;
  355.     case IDM_HELP_TUTORIAL:
  356.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  357.       // tutorial narrative file associated with this tutorial code sample.
  358.       ReadTutorial(m_hInst, m_hWnd, TEXT(HTML_FILE_EXT));
  359.       break;
  360.     case IDM_HELP_TUTSERVER:
  361.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  362.       // tutorial narrative file associated with the COM server.
  363.       ReadTutorial(m_hInst, m_hWnd, TEXT(SERVER_TUTFILE_STR));
  364.       break;
  365.     case IDM_HELP_READSOURCE:
  366.       // Call the APPUTIL utility function ReadSource to allow the
  367.       // user to open and read any of the source files of CONCLIEN.
  368.       ReadSource(m_hWnd, &m_ofnFile);
  369.       break;
  370.     case IDM_HELP_ABOUT:
  371.       {
  372.         CAboutBox dlgAboutBox;
  373.  
  374.         // Show the standard About Box dialog for this EXE by telling the
  375.         // dialog C++ object to show itself by invoking its ShowDialog
  376.         // method.  Pass it this EXE instance and the parent window handle.
  377.         // Use a dialog resource ID for the dialog template stored in
  378.         // this EXE module's resources.
  379.         dlgAboutBox.ShowDialog(
  380.           m_hInst,
  381.           MAKEINTRESOURCE(IDM_HELP_ABOUT),
  382.           m_hWnd);
  383.       }
  384.       break;
  385.  
  386.     default:
  387.       // Defer all messages NOT handled here to the Default Window Proc.
  388.       lResult = ::DefWindowProc(m_hWnd, WM_COMMAND, wParam, lParam);
  389.       break;
  390.   }
  391.  
  392.   return(lResult);
  393. }
  394.  
  395.  
  396. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  397.   Method:   CMainWindow::WindowProc
  398.  
  399.   Summary:  Main window procedure for this window object.  See CVirWindow
  400.             in the APPUTIL library (APPUTIL.CPP) for details on how this
  401.             method gets called by the global WindowProc.
  402.  
  403.   Args:     UINT uMsg,
  404.               Windows message that is "sent" to this window.
  405.             WPARAM wParam,
  406.               First message parameter (word sized).
  407.             LPARAM lParam)
  408.               Second message parameter (long sized).
  409.  
  410.   Modifies: ...
  411.  
  412.   Returns:  LRESULT
  413.               Standard Windows WindowProc return value.
  414. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  415. LRESULT CMainWindow::WindowProc(
  416.           UINT uMsg,
  417.           WPARAM wParam,
  418.           LPARAM lParam)
  419. {
  420.   LRESULT lResult = FALSE;
  421.  
  422.   switch (uMsg)
  423.   {
  424.     case WM_CREATE:
  425.       break;
  426.  
  427.     case WM_MEASUREITEM:
  428.       // Get setup for painting text in this window.
  429.       {
  430.         LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
  431.         lpmis->itemHeight = m_tm.tmHeight + m_tm.tmExternalLeading;
  432.         lpmis->itemWidth = m_wWidth;
  433.         lResult = TRUE;
  434.       }
  435.  
  436.     case WM_SIZE:
  437.       // Handle a resize of this window.
  438.       // Clear window and Restart the ball from upper left.
  439.       m_wWidth = LOWORD(lParam);
  440.       m_wHeight = HIWORD(lParam);
  441.       m_pGuiBall->Restart();
  442.       // Turn off sounds if app is minimized.
  443.       if (SIZE_MINIMIZED == wParam)
  444.         DoMenu(IDM_SOUND_BALL_OFF, 0);
  445.       break;
  446.  
  447.     case WM_TIMER:
  448.       // This is our timed attempt to continuously move & paint the ball.
  449.       // In this app PaintBall both moves and paints the ball.
  450.       m_pGuiBall->PaintBall();
  451.       break;
  452.  
  453.     case WM_COMMAND:
  454.       // Dispatch and handle any Menu command messages received.
  455.       lResult = DoMenu(wParam, lParam);
  456.       break;
  457.  
  458.     case WM_CHAR:
  459.       if (wParam == 0x1b)
  460.       {
  461.         // Exit this app if user hits ESC key.
  462.         PostMessage(m_hWnd,WM_CLOSE,0,0);
  463.         break;
  464.       }
  465.     case WM_LBUTTONUP:
  466.     case WM_PAINT:
  467.       // If something major happened or user clicks or hits key then
  468.       // repaint the whole window.
  469.       m_pGuiBall->PaintWin();
  470.       break;
  471.  
  472.     case WM_CLOSE:
  473.       // The user selected Close on the main window's System menu
  474.       // or Exit on the File menu.
  475.     case WM_QUIT:
  476.       // If the app is being quit then close any associated help windows.
  477.     default:
  478.       // Defer all messages NOT handled here to the Default Window Proc.
  479.       lResult = ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
  480.       break;
  481.   }
  482.  
  483.   return(lResult);
  484. }
  485.  
  486.  
  487. /*F+F++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  488.   Function: UnicodeOk
  489.  
  490.   Summary:  Checks if the platform will handle unicode versions of
  491.             Win32 string API calls.
  492.  
  493.   Args:     void
  494.  
  495.   Returns:  BOOL
  496.               TRUE if unicode support; FALSE if not.
  497. ------------------------------------------------------------------------F-F*/
  498. BOOL UnicodeOk(void)
  499. {
  500.   BOOL bOk = TRUE;
  501.   TCHAR szUserName[MAX_STRING_LENGTH];
  502.   DWORD dwSize = MAX_STRING_LENGTH;
  503.  
  504.   if (!GetUserName(szUserName, &dwSize))
  505.     bOk = ERROR_CALL_NOT_IMPLEMENTED == GetLastError() ? FALSE : TRUE;
  506.  
  507.   return bOk;
  508. }
  509.  
  510.  
  511. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  512.   Function: InitApplication
  513.  
  514.   Summary:  Initializes the application and registers its main window
  515.             class. InitApplication is called only once (in WinMain).
  516.  
  517.   Args:     HINSTANCE hInstance)
  518.               Handle to the first instance of the application.
  519.  
  520.   Returns:  BOOL.
  521.               TRUE if success.
  522.               FALSE if fail.
  523. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  524. BOOL InitApplication(
  525.        HINSTANCE hInstance)
  526. {
  527.   BOOL bOk;
  528.   // The window class for all instances of the main frame window.
  529.   WNDCLASSEX wcf;
  530.  
  531.   // Assign the appropriate values for this main frame window class.
  532.   wcf.cbSize        = sizeof(WNDCLASSEX);
  533.   wcf.cbClsExtra    = 0;            // No per-class extra data.
  534.   wcf.cbWndExtra    = 0;            // No per-window extra data.
  535.   wcf.hInstance     = hInstance;    // Application module instance.
  536.   wcf.lpfnWndProc   = &WindowProc;  // Global Window Procedure (defined in
  537.                                     // APPUTIL for all CVirWindows).
  538.   wcf.hCursor       = LoadCursor(NULL, IDC_ARROW); // Load app cursor.
  539.   wcf.hIcon         = (HICON) LoadIcon(            // Load app icon.
  540.                                 hInstance,
  541.                                 TEXT("AppIcon"));
  542.   wcf.hIconSm       = (HICON) LoadImage(           // Load small icon.
  543.                                 hInstance,
  544.                                 TEXT("AppIcon"),
  545.                                 IMAGE_ICON,
  546.                                 16, 16,
  547.                                 0);
  548.   wcf.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); // Backgnd color.
  549.   wcf.style         = CS_HREDRAW | CS_VREDRAW;     // Class style(s).
  550.   wcf.lpszClassName = TEXT(MAIN_WINDOW_CLASS_NAME_STR); // Class name.
  551.   wcf.lpszMenuName  = TEXT(MAIN_WINDOW_CLASS_MENU_STR); // Menu name.
  552.  
  553.   // Register the window class and return FALSE if unsuccesful.
  554.   bOk = RegisterClassEx(&wcf);
  555.  
  556.   return (bOk);
  557. }
  558.  
  559.  
  560. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  561.   Function: WinMain
  562.  
  563.   Summary:  The Windows main entry point function for this application.
  564.             Initializes the application, the COM Libraries, and starts
  565.             the main application message loop.
  566.  
  567.   Args:     HINSTANCE hInstance,
  568.               Instance handle; a new one for each invocation of this app.
  569.             HINSTANCE hPrevInstance,
  570.               Instance handle of the previous instance. NULL in Win32.
  571.             LPSTR lpCmdLine,
  572.               Windows passes a pointer to the application's
  573.               invocation command line.
  574.             int nCmdShow)
  575.               Bits telling the show state of the application.
  576.  
  577.   Returns:  int
  578.               msg.wParam (upon exit of message loop).
  579.               FALSE if this instance couldn't initialize and run.
  580. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  581. extern "C" int PASCAL WinMain(
  582.                         HINSTANCE hInstance,
  583.                         HINSTANCE hPrevInstance,
  584.                         LPSTR lpCmdLine,
  585.                         int nCmdShow)
  586. {
  587.   CMainWindow* pWin = NULL;
  588.   MSG msg;
  589.   HACCEL hAccel;
  590.   int iRun = FALSE;
  591.  
  592.   // If we were compiled for UNICODE and the platform seems OK with this
  593.   // then proceed.  Else we error and exit the app.
  594.   if (UnicodeOk())
  595.   {
  596.     // Call to initialize the COM Library.  Use the SUCCEEDED macro
  597.     // to detect success.  If fail then exit app with error message.
  598.     // Tell COM that this client process and all subordinate threads
  599.     // will live in a single-threaded apartment world.
  600.     if (SUCCEEDED(CoInitialize(NULL)))
  601.     {
  602.       // If we succeeded in initializing the COM Library we proceed to
  603.       // initialize the application.  If we can't init the application
  604.       // then we signal shut down with an error message exit.
  605.       iRun = InitApplication(hInstance);
  606.       if (iRun)
  607.       {
  608.         // Assume we'll set iRun to TRUE when initialization is done.
  609.         iRun = FALSE;
  610.         // We are still go for running so we try to create a nifty new
  611.         // CMainWindow object for this app instance.
  612.         pWin = new CMainWindow;
  613.         if (NULL != pWin)
  614.         {
  615.           // Now we initialize an instance of the new CMainWindow.
  616.           // This includes creating the main window.
  617.           if (pWin->InitInstance(hInstance, nCmdShow))
  618.           {
  619.             // Load the keyboard accelerators from the resources.
  620.             hAccel = LoadAccelerators(hInstance, TEXT("AppAccel"));
  621.             if (NULL != hAccel)
  622.             {
  623.               // Signal App Initialization is successfully done.
  624.               iRun = TRUE;
  625.             }
  626.           }
  627.         }
  628.       }
  629.  
  630.       if (iRun)
  631.       {
  632.         // If we initialized the app instance properly then we are still
  633.         // go for running.  We then start up the main message pump for
  634.         // the application.
  635.         while (GetMessage(&msg, NULL, 0, 0))
  636.         {
  637.           if (!TranslateAccelerator(pWin->GetHwnd(), hAccel, &msg))
  638.           {
  639.             TranslateMessage(&msg);
  640.             DispatchMessage(&msg);
  641.           }
  642.         }
  643.  
  644.         // We also ask COM to unload any unused COM Servers, including our
  645.         // friend, CONSERVE.
  646.         CoFreeUnusedLibraries();
  647.  
  648.         // We'll pass to Windows the reason why we exited the message loop.
  649.         iRun = msg.wParam;
  650.       }
  651.       else
  652.       {
  653.         // We failed to initialize the application. Put up error message
  654.         // box saying that application couldn't be initialized.  Parent
  655.         // window is desktop (ie, NULL). Exit the failed application
  656.         // (ie, by returning FALSE to WinMain).
  657.         ErrorBox(hInstance, NULL, IDS_APPINITFAILED);
  658.  
  659.         // Delete the CMainWindow object.
  660.         DELETE_POINTER(pWin);
  661.       }
  662.  
  663.       // We're exiting this app (either normally or by init failure) so
  664.       // shut down the COM Library.
  665.       CoUninitialize();
  666.     }
  667.     else
  668.     {
  669.       // We failed to Initialize the COM Library. Put up error message box
  670.       // saying that COM Library couldn't be initialized.  Parent window
  671.       // is desktop (ie, NULL). Exit the failed application (ie, by
  672.       // returning FALSE to WinMain).
  673.       ErrorBox(hInstance, NULL, IDS_COMINITFAILED);
  674.     }
  675.   }
  676.   else
  677.   {
  678.     // If we were compiled for UNICODE but the platform has problems with
  679.     // this then indicate an error and exit the app immediately.
  680.     CHAR szMsg[MAX_STRING_LENGTH];
  681.  
  682.     if (LoadStringA(
  683.           hInstance,
  684.           IDS_NOUNICODE,
  685.           szMsg,
  686.           MAX_STRING_LENGTH))
  687.     {
  688.       MessageBoxA(
  689.         NULL,
  690.         szMsg,
  691.         ERROR_TITLE_STR,
  692.         MB_OK | MB_ICONEXCLAMATION);
  693.     }
  694.   }
  695.  
  696.   return iRun;
  697. }
  698.