home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / classlib / cframe.cpp < prev    next >
C/C++ Source or Header  |  1996-05-23  |  33KB  |  1,370 lines

  1. /*
  2.  * CFRAME.CPP
  3.  * Sample Code Class Libraries
  4.  *
  5.  * Generic CFrame class that manages either SDI or MDI clients as
  6.  * well as typical File, Edit, Window, and Help commands.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include <windows.h>
  17. #include <memory.h>
  18.  
  19. extern "C"
  20.     {
  21.     #include <commdlg.h>
  22.     }
  23.  
  24. #include "classlib.h"
  25.  
  26.  
  27.  
  28. /*
  29.  * CFrame::CFrame
  30.  * CFrame::~CFrame
  31.  *
  32.  * Constructor Parameters:
  33.  *  hInst           HINSTANCE from WinMain
  34.  *  hInstPrev       HINSTANCE from WinMain
  35.  *  pszCmdLine      LPSTR from WinMain
  36.  *  nCmdShow        int from WinMain
  37.  */
  38.  
  39. CFrame::CFrame(HINSTANCE hInst, HINSTANCE hInstPrev
  40.     , LPSTR pszCmdLine, int nCmdShow)
  41.     : CWindow(hInst)
  42.     {
  43.     m_hInstPrev =hInstPrev;
  44.     m_nCmdShow  =nCmdShow;
  45.  
  46.    #ifdef WIN32
  47.     //This gives us the Unicode version if necessary
  48.     m_pszCmdLine=GetCommandLine();
  49.    #else
  50.     m_pszCmdLine=pszCmdLine;
  51.    #endif
  52.  
  53.     m_ppszCmdArgs=NULL;
  54.     m_cCmdArgs=0;
  55.     m_fCmdsParsed=FALSE;
  56.  
  57.     m_fLastEnable=(BOOL)-1; //Uninitialized
  58.     m_fLastPaste =(BOOL)-1; //Uninitialized
  59.  
  60.     m_phMenu=NULL;
  61.     m_hBmp  =NULL;
  62.     m_pST   =NULL;
  63.  
  64.     m_pTB   =NULL;
  65.     m_pSL   =NULL;
  66.     m_pCL   =NULL;
  67.     return;
  68.     }
  69.  
  70.  
  71.  
  72. CFrame::~CFrame(void)
  73.     {
  74.     m_fClosing=TRUE;
  75.  
  76.     //Accelerators freed automatically.
  77.  
  78.     //Free the toolbar bitmaps
  79.     if (NULL!=m_hBmp)
  80.         DeleteObject(m_hBmp);
  81.  
  82.     if (NULL!=m_pCL)
  83.         delete m_pCL;
  84.  
  85.     if (NULL!=m_pSL)
  86.         delete m_pSL;
  87.  
  88.     if (NULL!=m_pTB)
  89.         delete m_pTB;
  90.  
  91.     //Free the menu handle array
  92.     if (NULL!=m_phMenu)
  93.         delete []((UINT *)m_phMenu);
  94.  
  95.     //Free the stringtable.
  96.     if (NULL!=m_pST)
  97.         delete m_pST;
  98.  
  99.     //Free the command-line argument pointer array
  100.     if (NULL!=m_ppszCmdArgs)
  101.         delete []m_ppszCmdArgs;
  102.  
  103.     m_fClosing=FALSE;
  104.     return;
  105.     }
  106.  
  107.  
  108. /*
  109.  * CFrame::ParseCommandLine
  110.  *
  111.  * Purpose:
  112.  *  Before other initialization, parse the command line arguments
  113.  *  since derived classes may need the arguments before calling
  114.  *  Init below.
  115.  *
  116.  * Return Value:
  117.  *  BOOL            TRUE if parsing succeeded, FALSE otherwise.
  118.  */
  119.  
  120. BOOL CFrame::ParseCommandLine(void)
  121.     {
  122.     LPTSTR     *ppsz=NULL;
  123.     LPTSTR      psz, pszT;
  124.     int         cArgs=0;
  125.  
  126.     if (m_fCmdsParsed)
  127.         return TRUE;
  128.  
  129.     psz=PszWhiteSpaceScan(m_pszCmdLine, TRUE);
  130.  
  131.    #ifdef WIN32
  132.     //Skip the first argument which is the EXE name in Win32
  133.     psz=PszWhiteSpaceScan(psz, FALSE);
  134.     psz=PszWhiteSpaceScan(psz, TRUE);
  135.    #endif
  136.  
  137.     for (pszT=psz; *pszT!=0; )
  138.         {
  139.         cArgs++;
  140.  
  141.         //Skip to the end of this argument
  142.         pszT=PszWhiteSpaceScan(pszT, FALSE);
  143.  
  144.         //Stop if we hit the end of the string
  145.         if ((TCHAR)0==*pszT)
  146.             break;
  147.  
  148.         //Skip whitespace to the next argument
  149.         pszT=PszWhiteSpaceScan(pszT, TRUE);
  150.         }
  151.  
  152.     /*
  153.      * Now allocate a pointer array to each argument in the
  154.      * command line and null terminate each argument.
  155.      */
  156.     if (0!=cArgs)
  157.         {
  158.         int i;
  159.  
  160.         ppsz=new LPTSTR[cArgs];
  161.  
  162.         if (NULL==ppsz)
  163.             return FALSE;
  164.  
  165.         for (i=0; i < cArgs; i++)
  166.             {
  167.             ppsz[i]=psz;
  168.  
  169.             psz=PszWhiteSpaceScan(psz, FALSE);
  170.  
  171.             if ((TCHAR)0!=*psz)
  172.                 pszT=psz;
  173.  
  174.             psz=PszWhiteSpaceScan(psz, TRUE);
  175.             *pszT=(TCHAR)0;
  176.             }
  177.         }
  178.  
  179.     m_ppszCmdArgs=ppsz;
  180.     m_cCmdArgs=cArgs;
  181.     m_fCmdsParsed=TRUE;
  182.     return TRUE;
  183.     }
  184.  
  185.  
  186.  
  187.  
  188.  
  189. /*
  190.  * CFrame::Init
  191.  *
  192.  * Purpose:
  193.  *  Initializer for a CFrame object containing anything prone to
  194.  *  failure.
  195.  *
  196.  * Parameters:
  197.  *  pFI             PFRAMEINIT containing initialization parameters.
  198.  *
  199.  * Return Value:
  200.  *  BOOL            TRUE if initialization succeeded, FALSE
  201.  *                  otherwise. If FALSE is returned, the caller must
  202.  *                  guarantee that the destructor is called promptly
  203.  *                  to insure cleanup.
  204.  */
  205.  
  206. BOOL CFrame::Init(PFRAMEINIT pFI)
  207.     {
  208.     RECT                rc;
  209.     HMENU               hMenu;
  210.     UINT                uTemp;
  211.     TOOLDISPLAYDATA     tdd;
  212.  
  213.     m_fInit=TRUE;
  214.  
  215.     //1.  Create our stringtable
  216.     m_pST=new CStringTable(m_hInst);
  217.  
  218.     if (!m_pST->Init(pFI->idsMin, pFI->idsMax))
  219.         return FALSE;
  220.  
  221.  
  222.     /*
  223.      * 2.  Register the classes we need for this application.
  224.      *     We have our main (frame) window, document windows (for
  225.      *     either MDI or SDI, and Polyline windows which are the
  226.      *     editing controls.  This separate virtual function allows
  227.      *     applications to add additional classes.
  228.      */
  229.     if (NULL==m_hInstPrev)
  230.         {
  231.         if (!RegisterAllClasses())
  232.             return FALSE;
  233.         }
  234.  
  235.  
  236.     /*
  237.      * 3.  Create the main window, the toolbar, and the status line.
  238.      */
  239.     m_pCL=NULL;
  240.  
  241.     m_hWnd=CreateWindow(SZCLASSFRAME, PSZ(IDS_CAPTION)
  242.         , WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN
  243.         , pFI->x, pFI->y, pFI->cx, pFI->cy
  244.         , NULL, NULL, m_hInst, this);
  245.  
  246.     if (NULL==m_hWnd)
  247.         return FALSE;
  248.  
  249.     GetClientRect(m_hWnd, &rc);
  250.  
  251.     UIToolConfigureForDisplay(&tdd);
  252.     m_dxB=tdd.cxButton;
  253.     m_dyB=tdd.cyButton;
  254.     m_cyBar=tdd.cyBar;
  255.  
  256.     m_pTB=new CToolBar(m_hInst);
  257.  
  258.     if (!m_pTB->Init(m_hWnd, ID_GIZMOBAR, m_cyBar))
  259.         return FALSE;
  260.  
  261.     m_pSL=new CStatusLine(m_hInst);
  262.  
  263.     if (!m_pSL->Init(m_hWnd, ID_STATSTRIP, CYSTATSTRIP))
  264.         return FALSE;
  265.  
  266.  
  267.     //Initialize the status line for automated WM_MENUSELECT processing
  268.     if (!m_pSL->MessageMap(m_hWnd, m_hInst, IDR_STATMESSAGEMAP
  269.         , pFI->idsStatMin, pFI->idsStatMax, CCHMESSAGEMAX
  270.         , pFI->idStatMenuMin, pFI->idStatMenuMax, ID_MESSAGEREADY
  271.         , ID_MESSAGEEMPTY, ID_MENUSYS))
  272.         return FALSE;
  273.  
  274.     rc.top+=m_cyBar;
  275.  
  276.     /*
  277.      * 4.  Create the client window that owns documents.  This
  278.      *     client also creates an advise sink and gives it to
  279.      *     each document to notify the frame of events.
  280.      *
  281.      *     Also allocate space for the menu handle array and store
  282.      *     the popup handles.  Get the menu handle of the Window
  283.      *     menu specifically for later processing.
  284.      */
  285.  
  286.     m_pCL=CreateCClient();
  287.     hMenu=GetMenu(m_hWnd);
  288.  
  289.    #ifdef MDI
  290.     //Save this for UpdateMenus.  Stays NULL in SDI
  291.     m_hMenuWindow=GetSubMenu(hMenu, pFI->iPosWindowMenu);
  292.    #endif
  293.  
  294.     if (!m_pCL->Init(m_hMenuWindow, &rc))
  295.         return FALSE;
  296.  
  297.     m_phMenu=new HMENU[pFI->cMenus];
  298.  
  299.     for (uTemp=0; uTemp < pFI->cMenus; uTemp++)
  300.         m_phMenu[uTemp]=GetSubMenu(hMenu, uTemp);
  301.  
  302.  
  303.     /*
  304.      * 5.  Initialize fancy things like the toolbar.  If a derived
  305.      *     class wants more tool images, they can copy the first
  306.      *     two in the standard image set and this code will still
  307.      *     load it.  This code just won't reference it.
  308.      */
  309.  
  310.     m_hBmp=LoadBitmap(m_hInst, MAKEINTRESOURCE(tdd.uIDImages));
  311.  
  312.     if (NULL==m_hBmp)
  313.         return FALSE;
  314.  
  315.     //Create all the tools, and uninitialize working flags
  316.     CreateToolbar();
  317.     UpdateToolbar();
  318.     m_fLastEnable=(BOOL)-1; //Uninitialized
  319.     m_fLastPaste =(BOOL)-1; //Uninitialized
  320.  
  321.     m_hAccel=LoadAccelerators(m_hInst
  322.         , MAKEINTRESOURCE(IDR_ACCELERATORS));
  323.  
  324.     if (NULL==m_hAccel)
  325.         return FALSE;
  326.  
  327.     /*
  328.      * 6.  In the default implementation PreShowInit does not do
  329.      *     anything, but is called here to allow derivations to
  330.      *     hook the function and modify m_nCmdShow before we
  331.      *     call ShowWindow.  This is one such place where OLE affects
  332.      *     a derivation, because servers will change m_nCmdShow to
  333.      *     SW_HIDE if started with -Embedding.
  334.      */
  335.     if (!PreShowInit())
  336.         return FALSE;
  337.  
  338.  
  339.     /*
  340.      * 7.  Handle window visibility appropriately after giving
  341.      *     PreShowInit a chance to modify it.
  342.      */
  343.     ShowWindow(m_hWnd, m_nCmdShow);
  344.     UpdateWindow(m_hWnd);
  345.  
  346.  
  347.     /*
  348.      * 8.  Parse the command line and take appropriate action.  The
  349.      *     derived class may have called ParseCommandLine earlier, so
  350.      *     m_fCmdsParsed tells us if we still need to call it.
  351.      */
  352.     if (!m_fCmdsParsed)
  353.         ParseCommandLine();
  354.  
  355.     OpenInitialFiles();
  356.  
  357.     m_fInit=FALSE;
  358.     return TRUE;
  359.     }
  360.  
  361.  
  362.  
  363.  
  364.  
  365. /*
  366.  * CFrame::CreateCClient
  367.  *
  368.  * Purpose:
  369.  *  Creates a CClient object for use in this frame.  This function
  370.  *  is overrided by derived classes to create a different type of
  371.  *  CClient.
  372.  *
  373.  * Return Value:
  374.  *  PCClient         Pointer to the new CClient object.
  375.  */
  376.  
  377. PCClient CFrame::CreateCClient(void)
  378.     {
  379.     return new CClient(m_hInst, this);
  380.     }
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388. /*
  389.  * CFrame::RegisterAllClasses
  390.  *
  391.  * Purpose:
  392.  *  Registers all classes used in this application.
  393.  *
  394.  * Return Value:
  395.  *  BOOL            TRUE if registration succeeded, FALSE otherwise.
  396.  */
  397.  
  398. BOOL CFrame::RegisterAllClasses(void)
  399.     {
  400.     WNDCLASS        wc;
  401.  
  402.     //Field that are the same for all windows.
  403.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  404.     wc.hInstance     = m_hInst;
  405.     wc.cbClsExtra    = 0;
  406.  
  407.     //Register the Frame window
  408.     wc.lpfnWndProc   = FrameWndProc;
  409.     wc.cbWndExtra    = CBFRAMEWNDEXTRA;
  410.     wc.hIcon         = LoadIcon(m_hInst, TEXT("Icon"));
  411.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  412.     wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
  413.     wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU);
  414.     wc.lpszClassName = SZCLASSFRAME;
  415.  
  416.     if (!RegisterClass(&wc))
  417.         return FALSE;
  418.  
  419.    #ifndef MDI
  420.     wc.lpfnWndProc   = SDIClientWndProc;
  421.     wc.cbWndExtra    = CBCLIENTWNDEXTRA;
  422.     wc.hIcon         = NULL;
  423.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  424.     wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
  425.     wc.lpszMenuName  = NULL;
  426.     wc.lpszClassName = SZCLASSSDICLIENT;
  427.  
  428.     if (!RegisterClass(&wc))
  429.         return FALSE;
  430.    #endif
  431.  
  432.     wc.lpfnWndProc   = DocumentWndProc;
  433.     wc.cbWndExtra    = CBDOCUMENTWNDEXTRA;
  434.     wc.hIcon         = LoadIcon(m_hInst
  435.                            , MAKEINTRESOURCE(IDR_DOCUMENTICON));
  436.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  437.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  438.     wc.lpszMenuName  = NULL;
  439.     wc.lpszClassName = SZCLASSDOCUMENT;
  440.  
  441.     if (!RegisterClass(&wc))
  442.         return FALSE;
  443.  
  444.     return TRUE;
  445.     }
  446.  
  447.  
  448.  
  449.  
  450.  
  451. /*
  452.  * CFrame::PreShowInit
  453.  *
  454.  * Purpose:
  455.  *  Called from Init before intially showing the window.  We do
  456.  *  whatever else we want here, modifying nCmdShow as necessary
  457.  *  which affects ShowWindow in Init.
  458.  *
  459.  * Return Value:
  460.  *  BOOL            TRUE if this initialization succeeded, FALSE
  461.  *                  otherwise.
  462.  */
  463.  
  464. BOOL CFrame::PreShowInit(void)
  465.     {
  466.     return TRUE;
  467.     }
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475. /*
  476.  * CFrame::OpenInitialFiles
  477.  *
  478.  * Purpose:
  479.  *  Opens any files that were present on the command line.
  480.  */
  481.  
  482. void CFrame::OpenInitialFiles(void)
  483.     {
  484.     UINT        i;
  485.     PCDocument  pDoc;
  486.  
  487.     //Create a new document if we have nothing specific to open
  488.     if (0==m_cCmdArgs)
  489.         {
  490.         pDoc=m_pCL->NewDocument(TRUE);
  491.  
  492.         if (NULL!=pDoc)
  493.             pDoc->Load(TRUE, NULL);
  494.  
  495.         UpdateToolbar();
  496.         return;
  497.         }
  498.  
  499.     //Iterate over the arguments and see if there's any filenames
  500.     for (i=0; i < m_cCmdArgs; i++)
  501.         {
  502.         LPTSTR      psz=m_ppszCmdArgs[i];
  503.  
  504.         if (NULL==psz)
  505.             break;
  506.  
  507.         //Skip switches prefixed with / and -
  508.         if ((TCHAR)0!=*psz && TEXT('/')!=*psz && TEXT('-')!=*psz)
  509.             {
  510.             pDoc=m_pCL->NewDocument(TRUE);
  511.  
  512.             if (NULL!=pDoc)
  513.                 pDoc->Load(TRUE, psz);
  514.             }
  515.  
  516.         UpdateToolbar();
  517.         }
  518.  
  519.     return;
  520.     }
  521.  
  522.  
  523.  
  524.  
  525. /*
  526.  * CFrame::CreateToolbar
  527.  *
  528.  * Purpose:
  529.  *  Procedure to create all the necessary toolbar buttons.
  530.  *
  531.  * Return Value:
  532.  *  UINT            Number of tools added to the bar.
  533.  */
  534.  
  535. UINT CFrame::CreateToolbar(void)
  536.     {
  537.     UINT            uState=GIZMO_NORMAL;
  538.     UINT            utCmd =GIZMOTYPE_BUTTONCOMMAND;
  539.     UINT            utEx  =GIZMOTYPE_BUTTONATTRIBUTEEX;
  540.  
  541.     //File New, Open, Close, Save, Import
  542.     m_pTB->Add(utCmd, 0, IDM_FILENEW,   m_dxB, m_dyB, NULL, NULL
  543.         , 3, uState);
  544.     m_pTB->Add(utCmd, 1, IDM_FILEOPEN,  m_dxB, m_dyB, NULL, NULL
  545.         , 4, uState);
  546.     m_pTB->Add(utCmd, 2, IDM_FILECLOSE, m_dxB, m_dyB, NULL, m_hBmp
  547.         , 0, uState);
  548.     m_pTB->Add(utCmd, 3, IDM_FILESAVE,  m_dxB, m_dyB, NULL, NULL
  549.         , 5, uState);
  550.  
  551.     //Separator
  552.     m_pTB->Add(GIZMOTYPE_SEPARATOR,   4, 0, 6, m_dyB, NULL, NULL
  553.         , 0, uState);
  554.  
  555.     //Edit Undo, Cut, Copy, Paste
  556.     m_pTB->Add(utCmd, 5, IDM_EDITUNDO,  m_dxB, m_dyB, NULL, m_hBmp
  557.         , 1, uState);
  558.     m_pTB->Add(utCmd, 6, IDM_EDITCUT,   m_dxB, m_dyB, NULL, NULL
  559.         , 0, uState);
  560.     m_pTB->Add(utCmd, 7, IDM_EDITCOPY,  m_dxB, m_dyB, NULL, NULL
  561.         , 1, uState);
  562.     m_pTB->Add(utCmd, 8, IDM_EDITPASTE, m_dxB, m_dyB, NULL, NULL
  563.         , 2, uState);
  564.  
  565.     return 9;
  566.     }
  567.  
  568.  
  569.  
  570. /*
  571.  * CFrame::MessageLoop
  572.  *
  573.  * Purpose:
  574.  *  Spins in a standard message loop (with accelerators) until
  575.  *  WM_QUIT is found after which it returns.
  576.  *
  577.  * Return Value:
  578.  *  WPARAM          Contents of msg.wParam from WM_QUIT.
  579.  */
  580.  
  581. WPARAM CFrame::MessageLoop(void)
  582.     {
  583.     MSG     msg;
  584.  
  585.     while (GetMessage(&msg, NULL, 0,0 ))
  586.         {
  587.         if (!m_pCL->TranslateAccelerator(&msg))
  588.             {
  589.             if (!TranslateAccelerator(m_hWnd, m_hAccel, &msg))
  590.                 {
  591.                 TranslateMessage(&msg);
  592.                 DispatchMessage(&msg);
  593.                 }
  594.             }
  595.         }
  596.  
  597.     return msg.wParam;
  598.     }
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605. /*
  606.  * CFrame::FMessageHook
  607.  *
  608.  * Purpose:
  609.  *  Provides a derivation of the base CFrame class to hook all
  610.  *  messages to the window procedure for special processing.
  611.  *  WM_COMMAND is NOT sent here as that goes through OnCommand
  612.  *  instead.
  613.  *
  614.  * Parameters:
  615.  *  <WndProc Parameters>
  616.  *  pLRes           LRESULT * in which to store the return value
  617.  *                  for the message.
  618.  *
  619.  * Return Value:
  620.  *  BOOL            TRUE to prevent further processing, FALSE
  621.  *                  otherwise.
  622.  */
  623.  
  624. BOOL CFrame::FMessageHook(HWND hWnd, UINT iMsg, WPARAM wParam
  625.     , LPARAM lParam, LRESULT *pLRes)
  626.     {
  627.     *pLRes=0;
  628.     return FALSE;
  629.     }
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636. /*
  637.  * CFrame::OnCommand
  638.  *
  639.  * Purpose:
  640.  *  WM_COMMAND handler for the frame window so derivations can
  641.  *  process their messages and then pass the standard commands (like
  642.  *  file open and save) on to the base class.
  643.  *
  644.  * Parameters:
  645.  *  hWnd            HWND of the frame window.
  646.  *  wParam          WPARAM of the message.
  647.  *  lParam          LPARAM of the message.
  648.  *
  649.  * Return Value:
  650.  *  LRESULT         Return value for the message.
  651.  */
  652.  
  653. LRESULT CFrame::OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  654.     {
  655.     PCDocument      pDoc;
  656.     TCHAR           szFile[CCHPATHMAX];
  657.     BOOL            fOK;
  658.     UINT            uTemp;
  659.     UINT            uType;
  660.     PCHourglass     pHour;
  661.  
  662.     COMMANDPARAMS(wID, wCode, hWndMsg);
  663.  
  664.     /*
  665.      * Don't bother with anything during first initialization,
  666.      * skipping many toolbar notifications.
  667.      */
  668.     if (m_fInit)
  669.         return 0L;
  670.  
  671.     pDoc=m_pCL->ActiveDocument();
  672.  
  673.  
  674.     switch (wID)
  675.         {
  676.         case IDM_FILENEW:
  677.             if (!m_pCL->SDIVerify())
  678.                 break;
  679.  
  680.             pHour=new CHourglass;
  681.             pDoc=m_pCL->NewDocument(TRUE);
  682.  
  683.             //Insure the document is untitled.
  684.             if (NULL!=pDoc)
  685.                 pDoc->Load(TRUE, NULL);
  686.  
  687.             delete pHour;
  688.             break;
  689.  
  690.  
  691.         case IDM_FILEOPEN:
  692.             if (!m_pCL->SDIVerify())
  693.                 break;
  694.  
  695.             szFile[0]=0;
  696.             fOK=SaveOpenDialog(szFile, CCHPATHMAX, IDS_FILEOPEN
  697.                 , TRUE, &uType);
  698.  
  699.             if (!fOK)
  700.                 return 0L;
  701.  
  702.             pDoc=m_pCL->NewDocument(FALSE);
  703.  
  704.             if (NULL==pDoc)
  705.                 return 0L;
  706.  
  707.             pHour=new CHourglass;
  708.             uTemp=pDoc->Load(TRUE, szFile);
  709.             delete pHour;
  710.  
  711.             pDoc->ErrorMessage(uTemp);
  712.  
  713.             //Close the new doc on failure, show on success.
  714.             if (DOCERR_NONE!=uTemp)
  715.                 m_pCL->CloseDocument(pDoc);
  716.             else
  717.                 m_pCL->ShowDocument(pDoc, TRUE);
  718.  
  719.             return (DOCERR_NONE==uTemp);
  720.  
  721.  
  722.         case IDM_FILECLOSE:
  723.             //Ask if you want to save.
  724.             if (!m_pCL->FCleanVerify(pDoc))
  725.                 return 0L;
  726.  
  727.             m_pCL->CloseDocument(pDoc);
  728.             UpdateToolbar();
  729.             break;
  730.  
  731.  
  732.         case IDM_FILESAVE:
  733.             //If we get this from the toolbar, we may need Save As
  734.             fOK=pDoc->FQuerySave();
  735.  
  736.             if (fOK)
  737.                 {
  738.                 //Save using current document name and version
  739.                 pHour=new CHourglass;
  740.                 uTemp=pDoc->Save(0, NULL);
  741.                 delete pHour;
  742.  
  743.                 pDoc->ErrorMessage(uTemp);
  744.                 return (DOCERR_NONE==uTemp);
  745.                 }
  746.  
  747.             //FALL through to File/Save As for no name documents.
  748.  
  749.  
  750.         case IDM_FILESAVEAS:
  751.             //Go get a filename, then save it.
  752.             pDoc->FilenameGet(szFile, CCHPATHMAX);
  753.  
  754.             fOK=SaveOpenDialog(szFile, CCHPATHMAX, IDS_FILESAVEAS
  755.                 , FALSE, &uType);
  756.  
  757.             if (!fOK)
  758.                 return 0L;
  759.  
  760.             pHour=new CHourglass;
  761.             uTemp=pDoc->Save(uType, szFile);
  762.             delete pHour;
  763.             pDoc->ErrorMessage(uTemp);
  764.             return (DOCERR_NONE==uTemp);
  765.  
  766.  
  767.         case IDM_FILEEXIT:
  768.             PostMessage(hWnd, WM_CLOSE, 0, 0L);
  769.             break;
  770.  
  771.  
  772.         case IDM_EDITCUT:
  773.         case IDM_EDITCOPY:
  774.             pHour=new CHourglass;
  775.             pDoc->Clip(hWnd, (IDM_EDITCUT==wID));
  776.             delete pHour;
  777.  
  778.             //Update the toolbar as appropriate.
  779.             m_pTB->Enable(IDM_EDITPASTE, pDoc->FQueryPaste());
  780.             break;
  781.  
  782.  
  783.         case IDM_EDITUNDO:
  784.             pDoc->Undo();
  785.             break;
  786.  
  787.         case IDM_EDITPASTE:
  788.             pHour=new CHourglass;
  789.             pDoc->Paste(hWnd);
  790.             delete pHour;
  791.             break;
  792.  
  793.  
  794.         //These commands don't happen in SDI builds; not on the menu
  795.         case IDM_WINDOWCASCADE:
  796.             m_pCL->OnWindowCommand(WM_MDICASCADE, 0);
  797.             break;
  798.  
  799.         case IDM_WINDOWTILEHORZ:
  800.             m_pCL->OnWindowCommand(WM_MDITILE, MDITILE_HORIZONTAL);
  801.             break;
  802.  
  803.         case IDM_WINDOWTILEVERT:
  804.             m_pCL->OnWindowCommand(WM_MDITILE, MDITILE_VERTICAL);
  805.             break;
  806.  
  807.         case IDM_WINDOWICONS:
  808.             m_pCL->OnWindowCommand(WM_MDIICONARRANGE, 0);
  809.             break;
  810.  
  811.         case IDM_HELPABOUT:
  812.             DialogBox(m_hInst, MAKEINTRESOURCE(IDD_ABOUT)
  813.                 , m_hWnd, (DLGPROC)AboutProc);
  814.             break;
  815.  
  816.         default:
  817.            return m_pCL->DefaultFrameProc(hWnd, WM_COMMAND, wParam
  818.                , lParam);
  819.         }
  820.  
  821.     return 0L;
  822.     }
  823.  
  824.  
  825.  
  826.  
  827.  
  828. /*
  829.  * CFrame::OnDocumentDataChange
  830.  *
  831.  * Purpose:
  832.  *  Most of the CDocumentAdviseSink notifications we get are fairly
  833.  *  standard implementations.  When data in the document changes,
  834.  *  however, there's probably more special things we can do, so we
  835.  *  keep this simple case simple with this hook, not forcing a
  836.  *  derived class to reimplement CDocumentAdviseSink.
  837.  *
  838.  * Parameters:
  839.  *  pDoc            PCDocument notifying the sink.
  840.  */
  841.  
  842. void CFrame::OnDocumentDataChange(PCDocument pDoc)
  843.     {
  844.     return;
  845.     }
  846.  
  847.  
  848.  
  849.  
  850.  
  851. /*
  852.  * CFrame::OnDocumentActivate
  853.  *
  854.  * Purpose:
  855.  *  Most of the CDocumentAdviseSink notifications we get are fairly
  856.  *  standard implementations.  When the current document changes,
  857.  *  however, there's probably more UI that frame derivations need
  858.  *  to do, so we allow the hook here.
  859.  *
  860.  * Parameters:
  861.  *  pDoc            PCDocument notifying the sink.
  862.  */
  863.  
  864. void CFrame::OnDocumentActivate(PCDocument pDoc)
  865.     {
  866.     return;
  867.     }
  868.  
  869.  
  870.  
  871.  
  872.  
  873.  
  874. /*
  875.  * CFrame::SaveOpenDialog
  876.  *
  877.  * Purpose:
  878.  *  Invokes the COMMDLG.DLL GetOpenFileName dialog and retrieves
  879.  *  a filename for saving or opening.
  880.  *
  881.  * Parameters:
  882.  *  pszFile         LPTSTR buffer to receive the entered filename.
  883.  *  cchFile         UINT length of pszFile
  884.  *  idsCaption      UINT of  string to use in the caption bar.
  885.  *  fOpen           BOOL indicating if we want file open or save.
  886.  *  puType          UINT * in which we store the selected type.
  887.  *                  Can be NULL.
  888.  *
  889.  * Return Value:
  890.  *  BOOL            TRUE if the function retrieved a filename,
  891.  *                  FALSE if the user pressed CANCEL.
  892.  */
  893.  
  894. BOOL CFrame::SaveOpenDialog(LPTSTR pszFile, UINT cchFile
  895.     , UINT idsCaption, BOOL fOpen, UINT *puType)
  896.     {
  897.     OPENFILENAME        ofn;
  898.     TCHAR               szFilter[80];
  899.     UINT                cch;
  900.     BOOL                fRet;
  901.    #ifdef DEBUG
  902.     DWORD               dwErr;
  903.    #endif
  904.  
  905.     if (NULL==pszFile)
  906.         return FALSE;
  907.  
  908.     memset(&ofn, 0, sizeof(OPENFILENAME));
  909.     ofn.lStructSize      =sizeof(OPENFILENAME);
  910.     ofn.hwndOwner        =m_hWnd;
  911.  
  912.     if (fOpen)
  913.         lstrcpy(szFilter, PSZ(IDS_FILEOPENFILTER));
  914.     else
  915.         lstrcpy(szFilter, PSZ(IDS_FILESAVEFILTER));
  916.  
  917.     cch=lstrlen(szFilter);
  918.     ReplaceCharWithNull(szFilter, szFilter[cch-1]);
  919.  
  920.     ofn.lpstrFilter      =szFilter;
  921.     ofn.nFilterIndex     =1L;
  922.  
  923.     ofn.lpstrTitle       =PSZ(idsCaption);
  924.     ofn.lpstrFile        =pszFile;
  925.     ofn.nMaxFile         =cchFile;
  926.  
  927.     ofn.lpstrDefExt      =PSZ(IDS_DEFEXT);
  928.  
  929.     if (fOpen)
  930.         {
  931.         ofn.Flags=OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  932.         fRet=GetOpenFileName(&ofn);
  933.         }
  934.     else
  935.         {
  936.         ofn.Flags=OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
  937.         fRet=GetSaveFileName(&ofn);
  938.         }
  939.  
  940.     if (fRet || NULL!=puType)
  941.         *puType=(UINT)ofn.nFilterIndex;
  942.  
  943.    #ifdef DEBUG
  944.     dwErr=CommDlgExtendedError();
  945.    #endif
  946.     return fRet;
  947.     }
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954. /*
  955.  * CFrame::ReplaceCharWithNull
  956.  *
  957.  * Purpose:
  958.  *  Walks a null-terminated string and replaces a given character
  959.  *  with a zero for use with the SaveOpenDialog member.
  960.  *
  961.  * Parameters:
  962.  *  psz             LPTSTR to the string to process.
  963.  *  ch              int character to replace.
  964.  *
  965.  * Return Value:
  966.  *  int             Number of characters replaced.  -1 if psz is NULL
  967.  */
  968.  
  969. UINT CFrame::ReplaceCharWithNull(LPTSTR psz, int ch)
  970.     {
  971.     UINT            cChanged=0;
  972.  
  973.     if (NULL==psz)
  974.         return 0;
  975.  
  976.     while ((TCHAR)0!=*psz)
  977.         {
  978.         if (ch==*psz)
  979.             {
  980.             *psz=0;
  981.             cChanged++;
  982.             }
  983.  
  984.         psz++;
  985.         }
  986.  
  987.     return cChanged;
  988.     }
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995. /*
  996.  * CFrame::PszWhiteSpaceScan
  997.  *
  998.  * Purpose:
  999.  *  Skips characters in a string until a whitespace or non-whitespace
  1000.  *  character is seen.  Whitespace is defined as \n, \r, \t, or ' '.
  1001.  *
  1002.  * Parameters:
  1003.  *  psz             LPTSTR to string to manipulate
  1004.  *  fSkip           BOOL  TRUE if we want to skip whitespace.
  1005.  *                  FALSE if we want to skip anything but whitespace.
  1006.  *
  1007.  * Return Value:
  1008.  *  LPTSTR          Pointer to first character in the string that
  1009.  *                  either non-whitespace (fSkip=TRUE) or
  1010.  *                  whitespace (fSkip=FALSE), which may be the
  1011.  *                  null terminator.
  1012.  */
  1013.  
  1014. LPTSTR CFrame::PszWhiteSpaceScan(LPTSTR psz, BOOL fSkip)
  1015.     {
  1016.     TCHAR       ch;
  1017.     BOOL        fWhite;
  1018.  
  1019.     while (ch=*psz)
  1020.         {
  1021.         //Not too sure how this localizes...
  1022.         fWhite=(TEXT('\n')==ch || TEXT('\r')==ch
  1023.             || TEXT('\t')==ch || TEXT(' ')==ch);
  1024.  
  1025.         //Too bad C doesn't have a logical XOR (^^) operator.
  1026.         if ((fSkip && !fWhite) || (!fSkip && fWhite))
  1027.             break;
  1028.  
  1029.         psz++;
  1030.         }
  1031.  
  1032.     return psz;
  1033.     }
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040. //PUBLIC FUNCTIONS
  1041.  
  1042.  
  1043.  
  1044.  
  1045. /*
  1046.  * CFrame::AskAndSave
  1047.  *
  1048.  * Purpose:
  1049.  *  If a document is closed and is dirty the client window we own
  1050.  *  will get the document's filename and call us here.  We will
  1051.  *  ask the user if they want to save that file and if so, send a
  1052.  *  message to our frame window to execute the Save command.
  1053.  *
  1054.  * Parameters:
  1055.  *  pszDoc          LPTSTR name of the document.  If the first
  1056.  *                  character is 0 then we use (Untitled).
  1057.  *
  1058.  * Return Value:
  1059.  *  BOOL            TRUE if the user saved or didn't; FALSE on
  1060.  *                  if the user pressed cancel.
  1061.  */
  1062.  
  1063. BOOL CFrame::AskAndSave(LPTSTR pszDoc)
  1064.     {
  1065.     BOOL            fRet=TRUE;
  1066.     UINT            uRet;
  1067.     TCHAR           szTemp[CCHFILENAMEMAX+100];
  1068.  
  1069.     if (NULL==pszDoc)
  1070.         return FALSE;
  1071.  
  1072.     if ((TCHAR)0==*pszDoc)
  1073.         pszDoc=PSZ(IDS_UNTITLED);
  1074.     else
  1075.         {
  1076.         GetFileTitle(pszDoc, szTemp, CCHFILENAMEMAX);
  1077.         lstrcpy(pszDoc, szTemp);
  1078.         }
  1079.  
  1080.     wsprintf(szTemp, PSZ(IDS_FILEDIRTY), pszDoc);
  1081.  
  1082.     uRet=MessageBox(m_hWnd, szTemp, PSZ(IDS_CAPTION)
  1083.         , MB_YESNOCANCEL | MB_ICONEXCLAMATION);
  1084.  
  1085.     /*
  1086.      * If the user wants to save, tell the window to execute the
  1087.      * command.
  1088.      */
  1089.     if (IDYES==uRet)
  1090.         {
  1091.         /*
  1092.          * The following is code taken from IDM_SAVE and IDM_SAVEAS
  1093.          * cases inside OnCommand above.  It's copied here to
  1094.          * allow processing of the return value from pDoc->Save.
  1095.          */
  1096.         PCDocument      pDoc;
  1097.         TCHAR           szFile[CCHPATHMAX];
  1098.         BOOL            fOK;
  1099.         UINT            uTemp;
  1100.         UINT            uType;
  1101.         PCHourglass     pHour;
  1102.  
  1103.         pDoc=m_pCL->ActiveDocument();
  1104.  
  1105.         fOK=pDoc->FQuerySave();
  1106.  
  1107.         if (fOK)
  1108.             {
  1109.             //Save using current document name and version
  1110.             pHour=new CHourglass;
  1111.             uTemp=pDoc->Save(0, NULL);
  1112.             delete pHour;
  1113.  
  1114.             pDoc->ErrorMessage(uTemp);
  1115.  
  1116.             //This return code is for CFrame::AskAndSave
  1117.             return (DOCERR_NONE==uTemp);
  1118.             }
  1119.  
  1120.         //Go get a filename, then save it.
  1121.         pDoc->FilenameGet(szFile, CCHPATHMAX);
  1122.  
  1123.         fOK=SaveOpenDialog(szFile, CCHPATHMAX, IDS_FILESAVEAS
  1124.             , FALSE, &uType);
  1125.  
  1126.         if (!fOK)
  1127.             return 0L;
  1128.  
  1129.         pHour=new CHourglass;
  1130.         uTemp=pDoc->Save(uType, szFile);
  1131.         delete pHour;
  1132.         pDoc->ErrorMessage(uTemp);
  1133.  
  1134.         return (DOCERR_NONE==uTemp);
  1135.         }
  1136.  
  1137.     //TRUE for No, False for Cancel
  1138.     return (IDCANCEL!=uRet);
  1139.     }
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145. /*
  1146.  * CFrame::UpdateMenus
  1147.  *
  1148.  * Purpose:
  1149.  *  Handles the WM_INITMENU message for the frame window.  Depending
  1150.  *  on the existence of an active window, menu items are selectively
  1151.  *  enabled and disabled.
  1152.  *
  1153.  * Parameters:
  1154.  *  hMenu           HMENU of the menu to intialize
  1155.  *  iMenu           UINT position of the menu.
  1156.  */
  1157.  
  1158. void CFrame::UpdateMenus(HMENU hMenu, UINT iMenu)
  1159.     {
  1160.     PCDocument  pDoc;
  1161.     BOOL        fOK=FALSE;
  1162.     UINT        uTemp;
  1163.     UINT        uTempE;
  1164.     UINT        uTempD;
  1165.  
  1166.     pDoc=m_pCL->ActiveDocument();
  1167.  
  1168.     uTempE=MF_ENABLED | MF_BYCOMMAND;
  1169.     uTempD=MF_DISABLED | MF_GRAYED | MF_BYCOMMAND;
  1170.     uTemp=((NULL!=pDoc) ? uTempE : uTempD);
  1171.  
  1172.     /*
  1173.      * File menu:  If there is no current document window, disable
  1174.      * Close, Save, and Save As.  If there is a document but
  1175.      * it doesn't have a filename, disable save.
  1176.      */
  1177.     if (m_phMenu[0]==hMenu)
  1178.         {
  1179.         EnableMenuItem(hMenu, IDM_FILECLOSE,  uTemp);
  1180.         EnableMenuItem(hMenu, IDM_FILESAVE,   uTemp);
  1181.         EnableMenuItem(hMenu, IDM_FILESAVEAS, uTemp);
  1182.  
  1183.         if (NULL!=pDoc)
  1184.             fOK=pDoc->FQuerySave();
  1185.  
  1186.         EnableMenuItem(hMenu, IDM_FILESAVE, (fOK) ? uTempE : uTempD);
  1187.         }
  1188.  
  1189.  
  1190.     /*
  1191.      * Edit menus:  If there's no document, disable all of it.
  1192.      * If there's a document but no clipboard format available,
  1193.      * disable paste only.
  1194.      */
  1195.     if (m_phMenu[1]==hMenu)
  1196.         {
  1197.         EnableMenuItem(hMenu, IDM_EDITUNDO,  uTemp);
  1198.         EnableMenuItem(hMenu, IDM_EDITCOPY,  uTemp);
  1199.         EnableMenuItem(hMenu, IDM_EDITCUT,   uTemp);
  1200.  
  1201.         /*
  1202.          * Paste has two dependencies; format available and an open
  1203.          * document
  1204.          */
  1205.         if (NULL!=pDoc)
  1206.             fOK=pDoc->FQueryPaste();
  1207.  
  1208.         fOK &=(uTemp==uTempE);
  1209.         EnableMenuItem(hMenu,IDM_EDITPASTE, (fOK) ? uTempE : uTempD);
  1210.         }
  1211.  
  1212.  
  1213.    #ifdef MDI
  1214.     //Window menu:  no document, no commands
  1215.     if (m_hMenuWindow==hMenu)
  1216.         {
  1217.         EnableMenuItem(hMenu, IDM_WINDOWCASCADE,  uTemp);
  1218.         EnableMenuItem(hMenu, IDM_WINDOWTILEHORZ, uTemp);
  1219.         EnableMenuItem(hMenu, IDM_WINDOWTILEVERT, uTemp);
  1220.         EnableMenuItem(hMenu, IDM_WINDOWICONS,    uTemp);
  1221.         }
  1222.    #endif
  1223.  
  1224.     return;
  1225.     }
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235. /*
  1236.  * CFrame::UpdateToolbar
  1237.  *
  1238.  * Purpose:
  1239.  *  Enables and disablest toolbar buttons depending on whether we
  1240.  *  have a document or not and depending on clipboard format
  1241.  *  availability.
  1242.  */
  1243.  
  1244. void CFrame::UpdateToolbar(void)
  1245.     {
  1246.     PCDocument  pDoc;
  1247.     BOOL        fEnable;
  1248.  
  1249.     pDoc=m_pCL->ActiveDocument();
  1250.     fEnable=(NULL!=pDoc);
  1251.  
  1252.     if (m_fLastEnable!=fEnable)
  1253.         {
  1254.         m_fLastEnable=fEnable;
  1255.  
  1256.         //No document, disable just about everything
  1257.         m_pTB->Enable(IDM_FILECLOSE,  fEnable);
  1258.         m_pTB->Enable(IDM_FILESAVE,   fEnable);
  1259.  
  1260.         m_pTB->Enable(IDM_EDITUNDO,  fEnable);
  1261.         m_pTB->Enable(IDM_EDITCUT,   fEnable);
  1262.         m_pTB->Enable(IDM_EDITCOPY,  fEnable);
  1263.         }
  1264.  
  1265.     //Special handling:  clipboard format available, enable paste
  1266.     if (NULL!=pDoc)
  1267.         fEnable &= pDoc->FQueryPaste();
  1268.  
  1269.     //Paste is not enabled unless there's a document too
  1270.     if (m_fLastPaste!=fEnable)
  1271.         {
  1272.         m_fLastPaste=fEnable;
  1273.         m_pTB->Enable(IDM_EDITPASTE, fEnable);
  1274.         }
  1275.  
  1276.     return;
  1277.     }
  1278.  
  1279.  
  1280.  
  1281.  
  1282.  
  1283.  
  1284.  
  1285.  
  1286. /*
  1287.  * CFrame::WindowTitleSet
  1288.  *
  1289.  * Purpose:
  1290.  *  Handles changing the caption bar of a document window.
  1291.  *
  1292.  * Parameters:
  1293.  *  pDoc            PCDocument of the document affected.  If NULL,
  1294.  *                  then we remove titles.
  1295.  *  fDocTitle       BOOL indicating to set the document or the main
  1296.  *                  window captions.  In MDI we may do either, this
  1297.  *                  is ignored in SDI.
  1298.  */
  1299.  
  1300. void CFrame::WindowTitleSet(PCDocument pDoc, BOOL fDocTitle)
  1301.     {
  1302.     TCHAR       szTitle[CCHPATHMAX];
  1303.     TCHAR       szFile[CCHPATHMAX];
  1304.  
  1305.     /*
  1306.      * Go grab the filename.  If we get an emtpy file back, then
  1307.      * we'll use (Untitled).  If we have a NULL document, then we'll
  1308.      * just set the title of the app back to having no filename.
  1309.      */
  1310.     if (NULL!=pDoc)
  1311.         {
  1312.         pDoc->FilenameGet(szTitle, CCHPATHMAX);
  1313.  
  1314.         if ((TCHAR)0==szTitle[0])
  1315.             lstrcpy(szFile, PSZ(IDS_UNTITLED));
  1316.         else
  1317.             {
  1318.             GetFileTitle(szTitle, szFile, sizeof(szFile));
  1319.            #ifndef WIN32
  1320.             AnsiUpper(szFile);
  1321.            #endif
  1322.             }
  1323.         }
  1324.     else
  1325.         szFile[0]=0;
  1326.  
  1327.    #ifndef MDI
  1328.     //SDI always titles the application window
  1329.     fDocTitle=FALSE;
  1330.    #endif
  1331.  
  1332.     if (fDocTitle)
  1333.         {
  1334.         if (NULL!=pDoc)
  1335.             SetWindowText(pDoc->Window(), szFile);
  1336.         }
  1337.     else
  1338.         {
  1339.         if ((TCHAR)0!=szFile[0])
  1340.             {
  1341.             wsprintf(szTitle, TEXT("%s - %s"), PSZ(IDS_CAPTION)
  1342.                 , (LPTSTR)szFile);
  1343.             SetWindowText(m_hWnd, szTitle);
  1344.             }
  1345.         else
  1346.             SetWindowText(m_hWnd, PSZ(IDS_CAPTION));
  1347.         }
  1348.  
  1349.     return;
  1350.     }
  1351.  
  1352.  
  1353.  
  1354.  
  1355. /*
  1356.  * CFrame::StatusLine (inline)
  1357.  *
  1358.  * Purpose:
  1359.  *  Returns the status line object pointer to the caller so they can
  1360.  *  display status messages.
  1361.  *
  1362.  * Return Value:
  1363.  *  PCStatusLine    Pointer to the status line object.
  1364.  */
  1365.  
  1366. PCStatusLine inline CFrame::StatusLine(void)
  1367.     {
  1368.     return m_pSL;
  1369.     }
  1370.