home *** CD-ROM | disk | FTP | other *** search
/ PC Press 1997 July / Sezamfile97_2.iso / windows / program / activex / axtsamp.exe / TSBRANCH.EXE / EXESKEL / EXESKEL.CPP next >
C/C++ Source or Header  |  1996-12-29  |  21KB  |  600 lines

  1. /*+==========================================================================
  2.   File:      EXESKEL.CPP
  3.  
  4.   Summary:   Implementation file for the general .EXE application skeleton
  5.              that can be used as a point of departure for more complex COM
  6.              Win32 applications.  It is used as a skeletal base for the
  7.              ActiveX Tutorial series of code samples.
  8.  
  9.              For a comprehensive tutorial code tour of EXESKEL's contents
  10.              and offerings see the tutorial EXESKEL.HTM file. For more
  11.              specific technical details on the internal workings see the
  12.              comments dispersed throughout the EXESKEL source code.
  13.  
  14.   Classes:   CMainWindow
  15.  
  16.   Functions: InitApplication, WinMain
  17.  
  18.   Origin:    7-27-95: atrent - Created based on DFVIEW by stevebl.
  19.  
  20. ----------------------------------------------------------------------------
  21.   This file is part of the Microsoft ActiveX Tutorial Code Samples.
  22.  
  23.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  24.  
  25.   This source code is intended only as a supplement to Microsoft
  26.   Development Tools and/or on-line documentation.  See these other
  27.   materials for detailed information regarding Microsoft code samples.
  28.  
  29.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  30.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  31.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  32.   PARTICULAR PURPOSE.
  33. ==========================================================================+*/
  34.  
  35. /*---------------------------------------------------------------------------
  36.   We include WINDOWS.H for all Win32 applications.
  37.   We include OLE2.H because we will be calling the COM
  38.     Library's CoInitialize and CoUnInitialize calls.
  39.   We include COMMDLG.H because we will be using the Open File and
  40.     potentially other Common dialogs.
  41.   We include APPUTIL.H because we will be building this application using
  42.     the convenient Virtual Window and Dialog classes and other
  43.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  44.   We include EXESKEL.H because it has class and resource definitions
  45.     specific to this EXESKEL application.
  46. ---------------------------------------------------------------------------*/
  47. #include <windows.h>
  48. #include <ole2.h>
  49. #include <commdlg.h>
  50. #include <apputil.h>
  51. #include "exeskel.h"
  52.  
  53.  
  54. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  55.   Method:   CMainWindow::CMainWindow
  56.  
  57.   Summary:  CMainWindow Constructor.
  58.  
  59.   Args:     .
  60.  
  61.   Modifies: .
  62.  
  63.   Returns:  .
  64. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  65. CMainWindow::CMainWindow()
  66. {
  67.   // Ensure these member variable strings are null strings.
  68.   m_szFileName[0] = 0;
  69.   m_szFileTitle[0] = 0;
  70.  
  71.   // Fill in the Common Dialog's OPENFILENAME structure.
  72.   m_ofnFile.lStructSize = sizeof(OPENFILENAME);
  73.   m_ofnFile.hwndOwner = m_hWnd;
  74.   m_ofnFile.hInstance = m_hInst;
  75.   m_ofnFile.lpstrFilter = TEXT(OFN_DEFAULTFILES_STR);
  76.   m_ofnFile.lpstrCustomFilter = NULL;
  77.   m_ofnFile.nMaxCustFilter = 0;
  78.   m_ofnFile.nFilterIndex = 1;
  79.   m_ofnFile.lpstrFile = m_szFileName;
  80.   m_ofnFile.nMaxFile = MAX_PATH;
  81.   m_ofnFile.lpstrInitialDir = TEXT(".");
  82.   m_ofnFile.lpstrFileTitle = m_szFileTitle;
  83.   m_ofnFile.nMaxFileTitle = MAX_PATH;
  84.   m_ofnFile.lpstrTitle = TEXT(OFN_DEFAULTTITLE_STR);
  85.   m_ofnFile.lpstrDefExt = NULL;
  86.   m_ofnFile.Flags = OFN_HIDEREADONLY;
  87. }
  88.  
  89.  
  90. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  91.   Method:   CMainWindow::~CMainWindow
  92.  
  93.   Summary:  CMainWindow Destructor.  Destruction of the main window
  94.             indicates that the application should quit and thus the
  95.             PostQuitMessage API is called.
  96.  
  97.   Args:     .
  98.  
  99.   Modifies: .
  100.  
  101.   Returns:  .
  102. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  103. CMainWindow::~CMainWindow()
  104. {
  105.   // CMainWindow is derived from CVirWindow which traps the WM_DESTROY
  106.   // message and causes a delete of CMainWindow which in turn causes this
  107.   // destructor to run. The WM_DESTROY results when the window is destoyed
  108.   // after a close of the window. Prior to exiting the main message loop
  109.   // we delete the CMsgBox object that was made in Initinstance.
  110.   DELETE_POINTER(m_pMsgBox);
  111.  
  112.   // We then post a WM_QUIT message to cause an exit of the main thread's
  113.   // message loop and an exit of this instance of the application.
  114.   PostQuitMessage(0);
  115. }
  116.  
  117.  
  118. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  119.   Method:   CMainWindow::InitInstance
  120.  
  121.   Summary:  Instantiates an instance of the main application window.
  122.             This method must be called only once, immediately after
  123.             window class construction.  We take care to delete 'this'
  124.             CMainWindow if we must return the error condition FALSE.
  125.  
  126.   Args:     HINSTANCE hInstance,
  127.               Handle of the application instance.
  128.             int nCmdShow)
  129.               Command to pass to ShowWindow.
  130.  
  131.   Modifies: m_szHelpFile, m_pMsgBox.
  132.  
  133.   Returns:  BOOL.
  134.               TRUE if succeeded.
  135.               FALSE if failed.
  136. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  137. BOOL CMainWindow::InitInstance(
  138.        HINSTANCE hInstance,
  139.        int nCmdShow)
  140. {
  141.   BOOL bResult = FALSE;
  142.   HWND hWnd;
  143.  
  144.   // Create the Message Box object.
  145.   m_pMsgBox = new CMsgBox;
  146.  
  147.   if (NULL != m_pMsgBox)
  148.   {
  149.     // Note, the Create method sets the m_hWnd member so we don't
  150.     //   need to set it explicitly here first.
  151.  
  152.     // Here is the create of this window.  Size the window reasonably.
  153.     //   Create sets both m_hInst and m_hWnd.
  154.     hWnd = Create(
  155.              TEXT(MAIN_WINDOW_CLASS_NAME_STR),
  156.              TEXT(MAIN_WINDOW_TITLE_STR),
  157.              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
  158.                | WS_MAXIMIZEBOX | WS_THICKFRAME,
  159.              CW_USEDEFAULT,
  160.              CW_USEDEFAULT,
  161.              ::GetSystemMetrics(SM_CXSCREEN)*2/5,
  162.              ::GetSystemMetrics(SM_CYSCREEN)*2/5,
  163.              NULL,
  164.              NULL,
  165.              hInstance);
  166.     if (hWnd)
  167.     {
  168.       // Ensure the new window is shown on screen and its content is painted.
  169.       ::ShowWindow(m_hWnd, nCmdShow);
  170.       ::UpdateWindow(m_hWnd);
  171.  
  172.       // Build a path to where the help file should be (it should be in
  173.       // the same directory as the .EXE but with the .HLP extension.
  174.       MakeFamilyPath(hInstance, m_szHelpFile, TEXT(HELP_FILE_EXT));
  175.  
  176.       // Init the Message Box object and signal we succeeded initializing
  177.       // the application.
  178.       if (m_pMsgBox->Init(m_hInst, m_hWnd))
  179.         bResult = TRUE;
  180.     }
  181.   }
  182.  
  183.   if (!bResult)
  184.   {
  185.     if (m_pMsgBox)
  186.       delete m_pMsgBox;
  187.     // If Create failed then hWnd == NULL and the window create failed.
  188.     // This means that the WM_NCCREATE returned a -1 (failure) and
  189.     // Windows sends the WM_DESTROY message to the window and an object
  190.     // of the CVirWindow class destroys itself whenever it receives
  191.     // the WM_DESTROY message.  So in that case we don't need to
  192.     // delete 'this'.  We delete 'this' if we succeeded in creating the
  193.     // window but failed in some other way in this initialization.
  194.     if (hWnd)
  195.       delete this;
  196.   }
  197.  
  198.   return (bResult);
  199. }
  200.  
  201.  
  202. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  203.   Method:   CMainWindow::DoMenu
  204.  
  205.   Summary:  Member function to dispatch and handle the main menu commands.
  206.  
  207.   Args:     WPARAM wParam,
  208.               First message parameter (word sized).
  209.             LPARAM lParam)
  210.               Second message parameter (long sized).
  211.  
  212.   Modifies: m_ofnFile.
  213.  
  214.   Returns:  LRESULT
  215.               Standard Windows WindowProc return value.
  216. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  217. LRESULT CMainWindow::DoMenu(
  218.           WPARAM wParam,
  219.           LPARAM lParam)
  220. {
  221.   LRESULT lResult = FALSE;
  222.  
  223.   switch (LOWORD(wParam))
  224.   {
  225.     case IDM_FILE_EXIT:
  226.       // The user commands us to exit this application so we tell the
  227.       // Main window to close itself.
  228.       ::PostMessage(m_hWnd, WM_CLOSE, 0, 0);
  229.       break;
  230.  
  231.     case IDM_HELP_CONTENTS:
  232.       // We have some stubbed support here for bringing up the online
  233.       // Help for this application.
  234.       if (::FileExist(m_szHelpFile))
  235.         ::WinHelp(m_hWnd, m_szHelpFile, HELP_CONTEXT, IDH_CONTENTS);
  236.       else
  237.         m_pMsgBox->ErrorID(IDS_NOHELPFILE);
  238.       break;
  239.  
  240.     case IDM_HELP_TUTORIAL:
  241.       // Call the APPUTIL utility function, ReadTutorial, to Browse the HTML
  242.       // tutorial narrative file associated with this tutorial code sample.
  243.       ReadTutorial(m_hInst, m_hWnd, TEXT(HTML_FILE_EXT));
  244.       break;
  245.  
  246.     case IDM_HELP_READSOURCE:
  247.       // Call the APPUTIL utility function ReadSource to allow the
  248.       // user to open and read any of the source files of EXESKEL.
  249.       ReadSource(m_hWnd, &m_ofnFile);
  250.       break;
  251.  
  252.     case IDM_HELP_ABOUT:
  253.       {
  254.         CAboutBox dlgAboutBox;
  255.  
  256.         // Show the standard About Box dialog for this EXE by telling the
  257.         // dialog C++ object to show itself by invoking its ShowDialog
  258.         // method.  Pass it this EXE instance and the parent window handle.
  259.         // Use a dialog resource ID for the dialog template stored in
  260.         // this EXE module's resources.
  261.         dlgAboutBox.ShowDialog(
  262.           m_hInst,
  263.           MAKEINTRESOURCE(IDM_HELP_ABOUT),
  264.           m_hWnd);
  265.       }
  266.       break;
  267.  
  268.     default:
  269.       // Defer all messages NOT handled here to the Default Window Proc.
  270.       lResult = ::DefWindowProc(m_hWnd, WM_COMMAND, wParam, lParam);
  271.       break;
  272.   }
  273.  
  274.   return(lResult);
  275. }
  276.  
  277.  
  278. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  279.   Method:   CMainWindow::WindowProc
  280.  
  281.   Summary:  Main window procedure for this window object.  See CVirWindow
  282.             in the APPUTIL library (APPUTIL.CPP) for details on how this
  283.             method gets called by the global WindowProc.
  284.  
  285.   Args:     UINT uMsg,
  286.               Windows message that is "sent" to this window.
  287.             WPARAM wParam,
  288.               First message parameter (word sized).
  289.             LPARAM lParam)
  290.               Second message parameter (long sized).
  291.  
  292.   Modifies: ...
  293.  
  294.   Returns:  LRESULT
  295.               Standard Windows WindowProc return value.
  296. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  297. LRESULT CMainWindow::WindowProc(
  298.           UINT uMsg,
  299.           WPARAM wParam,
  300.           LPARAM lParam)
  301. {
  302.   LRESULT lResult = FALSE;
  303.  
  304.   switch (uMsg)
  305.   {
  306.     case WM_CREATE:
  307.       {
  308.         // Setup for painting text in this window.
  309.         HDC hdc = GetDC(m_hWnd);
  310.         ::GetTextMetrics(hdc, &m_tm);
  311.         ::ReleaseDC(m_hWnd, hdc);
  312.       }
  313.       break;
  314.  
  315.     case WM_MEASUREITEM:
  316.       // Get setup for painting text in this window.
  317.       {
  318.         LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
  319.         lpmis->itemHeight = m_tm.tmHeight + m_tm.tmExternalLeading;
  320.         lpmis->itemWidth = m_wWidth;
  321.         lResult = TRUE;
  322.       }
  323.  
  324.     case WM_SIZE:
  325.       // Handle a resize of this window.
  326.       m_wWidth = LOWORD(lParam);
  327.       m_wHeight = HIWORD(lParam);
  328.       break;
  329.  
  330.     case WM_COMMAND:
  331.       // Dispatch and handle any Menu command messages received.
  332.       lResult = DoMenu(wParam, lParam);
  333.       break;
  334.  
  335.     case WM_CLOSE:
  336.       // The user selected Close on the main window's System menu
  337.       // or Exit on the File menu.
  338.     case WM_QUIT:
  339.       // If the app is being quit then close any associated help windows.
  340.       // ::WinHelp(m_hWnd, m_szHelpFile, HELP_QUIT, 0);
  341.     default:
  342.       // Defer all messages NOT handled here to the Default Window Proc.
  343.       lResult = ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
  344.       break;
  345.   }
  346.  
  347.   return(lResult);
  348. }
  349.  
  350.  
  351. /*F+F++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  352.   Function: UnicodeOk
  353.  
  354.   Summary:  Checks if the platform will handle unicode versions of
  355.             Win32 string API calls.
  356.  
  357.   Args:     void
  358.  
  359.   Returns:  BOOL
  360.               TRUE if unicode support; FALSE if not.
  361. ------------------------------------------------------------------------F-F*/
  362. BOOL UnicodeOk(void)
  363. {
  364.   BOOL bOk = TRUE;
  365.   TCHAR szUserName[MAX_STRING_LENGTH];
  366.   DWORD dwSize = MAX_STRING_LENGTH;
  367.  
  368.   if (!GetUserName(szUserName, &dwSize))
  369.     bOk = ERROR_CALL_NOT_IMPLEMENTED == GetLastError() ? FALSE : TRUE;
  370.  
  371.   return bOk;
  372. }
  373.  
  374.  
  375. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  376.   Function: InitApplication
  377.  
  378.   Summary:  Initializes the application and registers its main window
  379.             class. InitApplication is called only once (in WinMain).
  380.  
  381.   Args:     HINSTANCE hInstance)
  382.               Handle to the first instance of the application.
  383.  
  384.   Returns:  BOOL.
  385.               TRUE if success.
  386.               FALSE if fail.
  387. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  388. BOOL InitApplication(
  389.        HINSTANCE hInstance)
  390. {
  391.   BOOL bOK;
  392.   // The window class for all instances of the main frame window.
  393.   WNDCLASSEX wcf;
  394.  
  395.   // Assign the appropriate values for this main frame window class.
  396.   wcf.cbSize        = sizeof(WNDCLASSEX);
  397.   wcf.style         = CS_HREDRAW | CS_VREDRAW; // Class style(s).
  398.   wcf.lpfnWndProc   = &WindowProc;             // Global Window Procedure for
  399.                                                //   all windows of this class.
  400.   wcf.cbClsExtra    = 0;                       // No per-class extra data.
  401.   wcf.cbWndExtra    = 0;                       // No per-window extra data.
  402.   wcf.hInstance     = hInstance;               // Owner of this class.
  403.   wcf.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);       // Default color.
  404.   wcf.lpszMenuName  = TEXT(MAIN_WINDOW_CLASS_MENU_STR); // Menu name from .RC.
  405.   wcf.lpszClassName = TEXT(MAIN_WINDOW_CLASS_NAME_STR); // Class name from .RC.
  406.   wcf.hCursor       = LoadCursor(NULL, IDC_ARROW);      // Cursor.
  407.   wcf.hIcon         = LoadIcon(                         // Icon name from .RC.
  408.                         hInstance,
  409.                         TEXT("AppIcon"));
  410.   wcf.hIconSm       = LoadImage(                        // Load small icon.
  411.                         hInstance,
  412.                         TEXT("AppIcon"),
  413.                         IMAGE_ICON,
  414.                         16, 16,
  415.                         0);
  416.  
  417.   // Register the window class and return FALSE if unsuccesful.
  418.   bOK = RegisterClassEx(&wcf);
  419.   if (!bOK)
  420.   {
  421.     // Assume we are running on NT where RegisterClassEx() is
  422.     // not implemented, so let's try calling RegisterClass().
  423.     bOK = RegisterClass((LPWNDCLASS)&wcf.style);
  424.   }
  425.  
  426.   return (bOK);
  427. }
  428.  
  429.  
  430. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  431.   Function: WinMain
  432.  
  433.   Summary:  The Windows main entry point function for this application.
  434.             Initializes the application, the COM Libraries, and starts
  435.             the main application message loop.
  436.  
  437.   Args:     HINSTANCE hInstance,
  438.               Instance handle; a new one for each invocation of this app.
  439.             HINSTANCE hPrevInstance,
  440.               Instance handle of the previous instance. NULL in Win32.
  441.             LPSTR lpCmdLine,
  442.               Windows passes a pointer to the application's
  443.               invocation command line.
  444.             int nCmdShow)
  445.               Bits telling the show state of the application.
  446.  
  447.   Returns:  int
  448.               msg.wParam (upon exit of message loop).
  449.               FALSE if this instance couldn't initialize and run.
  450. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  451. extern "C" int PASCAL WinMain(
  452.                         HINSTANCE hInstance,
  453.                         HINSTANCE hPrevInstance,
  454.                         LPSTR lpCmdLine,
  455.                         int nCmdShow)
  456. {
  457.   CMainWindow* pWin = NULL;
  458.   MSG msg;
  459.   HACCEL hAccel;
  460.   int iRun = FALSE;
  461.  
  462.   // If we were compiled for UNICODE and the platform seems OK with this
  463.   // then proceed.  Else we error and exit the app.
  464.   if (UnicodeOk())
  465.   {
  466.     // Call to initialize the COM Library.  Use the SUCCEEDED macro
  467.     // to detect success.  If fail then exit app with error message.
  468.     if (SUCCEEDED(CoInitialize(NULL)))
  469.     {
  470.       // If we succeeded in initializing the COM Library we proceed to
  471.       // initialize the application.  If we can't init the application
  472.       // then we signal shut down with an error message exit.
  473.       iRun = InitApplication(hInstance);
  474.  
  475.       if (iRun)
  476.       {
  477.         // Assume we'll set iRun to TRUE when initialization is done.
  478.         iRun = FALSE;
  479.         // We are still go for running so we try to create a nifty new
  480.         // CMainWindow object for this app instance.
  481.         pWin = new CMainWindow;
  482.         if (NULL != pWin)
  483.         {
  484.           // Now we initialize an instance of the new CMainWindow.
  485.           // This includes creating the main window.  Note: if
  486.           // InitInstance fails then it would have already deleted
  487.           // pWin so we wouldn't need to delete it here.
  488.           if (pWin->InitInstance(hInstance, nCmdShow))
  489.           {
  490.             // Load the keyboard accelerators from the resources.
  491.             hAccel = LoadAccelerators(hInstance, TEXT("AppAccel"));
  492.             if (NULL != hAccel)
  493.             {
  494.               // Signal App Initialization is successfully done.
  495.               iRun = TRUE;
  496.             }
  497.             else
  498.             {
  499.               // If we couldn't load the accelerators then we delete
  500.               // CMainWindow, and exit this failed instance of the
  501.               // application (relying on the default iRun = FALSE).
  502.               DELETE_POINTER(pWin);
  503.             }
  504.           }
  505.         }
  506.       }
  507.  
  508.       if (iRun)
  509.       {
  510.         // If we initialized the app instance properly then we are still
  511.         // go for running.  We then start up the main message pump for
  512.         // the application.
  513.         while (GetMessage(&msg, NULL, 0, 0))
  514.         {
  515.           if (!TranslateAccelerator(
  516.                  pWin->GetHwnd(),
  517.                  hAccel,
  518.                  &msg))
  519.           {
  520.             TranslateMessage(&msg);
  521.             DispatchMessage(&msg);
  522.           }
  523.         }
  524.  
  525.         // We'll pass to Windows the reason why we exited the message loop.
  526.         iRun = msg.wParam;
  527.       }
  528.       else
  529.       {
  530.         // We failed to initialize the application--issue an error
  531.         // messagebox.
  532.         TCHAR szMsg[MAX_STRING_LENGTH];
  533.  
  534.         // Load the error message string from the resources.
  535.         if (LoadString(
  536.               hInstance,
  537.               IDS_APPINITFAILED,
  538.               szMsg,
  539.               MAX_STRING_LENGTH))
  540.         {
  541.           // Put up error message box saying that application couldn't be
  542.           // initialized.  Parent window is desktop (ie, NULL).
  543.           MessageBox(
  544.             NULL,
  545.             szMsg,
  546.             TEXT(ERROR_TITLE_STR),
  547.             MB_OK | MB_ICONEXCLAMATION);
  548.         }
  549.       }
  550.  
  551.       // We're exiting this app (either normally or by init failure) so
  552.       // shut down the COM Library.
  553.       CoUninitialize();
  554.     }
  555.     else
  556.     {
  557.       // We failed to Initialize the COM Library.
  558.       TCHAR szMsg[MAX_STRING_LENGTH];
  559.  
  560.       // Load the error message string from the resources.
  561.       if (LoadString(
  562.             hInstance,
  563.             IDS_COMINITFAILED,
  564.             szMsg,
  565.             MAX_STRING_LENGTH))
  566.       {
  567.         // Put up error message box saying that COM Library
  568.         // couldn't be initialized.  Parent window is desktop (ie, NULL).
  569.         // And exit the failed application.
  570.         MessageBox(
  571.           NULL,
  572.           szMsg,
  573.           TEXT(ERROR_TITLE_STR),
  574.           MB_OK | MB_ICONEXCLAMATION);
  575.       }
  576.     }
  577.   }
  578.   else
  579.   {
  580.     // If we were compiled for UNICODE but the platform has problems with
  581.     // this then indicate an error and exit the app immediately.
  582.     CHAR szMsg[MAX_STRING_LENGTH];
  583.  
  584.     if (LoadStringA(
  585.           hInstance,
  586.           IDS_UNICODEFAIL,
  587.           szMsg,
  588.           MAX_STRING_LENGTH))
  589.     {
  590.       MessageBoxA(
  591.         NULL,
  592.         szMsg,
  593.         ERROR_TITLE_STR,
  594.         MB_OK | MB_ICONEXCLAMATION);
  595.     }
  596.   }
  597.  
  598.   return iRun;
  599. }
  600.