home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / activedocument / framer / framer.cpp next >
C/C++ Source or Header  |  1997-08-12  |  33KB  |  1,375 lines

  1. /*
  2.  * FRAMER.CPP
  3.  * Document Objects Framer
  4.  *
  5.  * Sample to demonstrate in-place activation of a DocObject--also
  6.  * activates normal embeddings in separate windows.
  7.  *
  8.  * Copyright (c)1995-1997 Microsoft Corporation, All Rights Reserved
  9.  */
  10.  
  11.  
  12. #define INITGUID
  13. #include "framer.h"
  14.  
  15.  
  16. /*
  17.  * WinMain
  18.  *
  19.  * Purpose:
  20.  *  Main entry point of application.  Should register the app class
  21.  *  if a previous instance has not done so and do any other one-time
  22.  *  initializations.
  23.  */
  24.  
  25. int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrev
  26.     , LPSTR pszCmdLine, int nCmdShow)
  27.     {
  28.     PCFrame         pFR;    
  29.     WPARAM          wRet;
  30.  
  31.     //Attempt to allocate and initialize the application
  32.     pFR=new CFrame(hInst, hPrev, pszCmdLine, nCmdShow);
  33.  
  34.     if (NULL==pFR)
  35.         return 0;
  36.     
  37.     //If we can initialize pFR, start chugging messages
  38.     if (pFR->Init(CMENUS, CW_USEDEFAULT, CW_USEDEFAULT
  39.         , CW_USEDEFAULT, CW_USEDEFAULT))
  40.         wRet=pFR->MessageLoop();
  41.  
  42.     delete pFR;
  43.     return wRet;
  44.     }
  45.  
  46.  
  47.  
  48. /*
  49.  * CFrame::CFrame
  50.  * CFrame::~CFrame
  51.  *
  52.  * Constructor Parameters:
  53.  *  hInst           HINSTANCE from WinMain
  54.  *  hInstPrev       HINSTANCE from WinMain
  55.  *  pszCmdLine      LPSTR from WinMain
  56.  *  nCmdShow        int from WinMain
  57.  */
  58.  
  59. CFrame::CFrame(HINSTANCE hInst, HINSTANCE hInstPrev
  60.     , LPSTR pszCmdLine, int nCmdShow)    
  61.     {
  62.     m_hInst=hInst;
  63.     m_hWnd=NULL;
  64.     m_hInstPrev=hInstPrev;
  65.     m_nCmdShow=nCmdShow;
  66.  
  67.     m_phMenu=NULL;
  68.     m_hAccel=NULL;
  69.     m_hWndClient=NULL;
  70.  
  71.     m_fInitialized=FALSE;
  72.     m_pIStorage=NULL;
  73.     m_dwIDCounter=0;
  74.  
  75.     m_hMenuOrg=NULL;
  76.     m_hMenuTop=NULL;
  77.     m_hMenuHelp=NULL;
  78.     m_fInObjectHelp=FALSE;
  79.     m_fUsingOurHelp=FALSE;
  80.             
  81.     m_fHaveObject=FALSE;
  82.     m_hWndObj=NULL;
  83.  
  84.     m_pSite=NULL;
  85.     m_fOurMenuShowing=TRUE;
  86.     SetRect(&m_bwIP, 0, 0, 0, 0);
  87.     m_fInContextHelp=FALSE;
  88.     m_pIOleIPActiveObject=NULL;
  89.  
  90.     return;
  91.     }
  92.  
  93.  
  94.  
  95. CFrame::~CFrame(void)
  96.     {
  97.     if (NULL!=m_hWndClient)
  98.         DestroyWindow(m_hWndClient);
  99.     
  100.     //Frees the temp file.
  101.     ReleaseInterface(m_pIStorage);
  102.     
  103.     //m_pSite cleaned up in Close
  104.  
  105.     //Accelerators freed automatically.
  106.  
  107.     //Destroy the special help menu
  108.     if (NULL!=m_hMenuHelp)
  109.         DestroyMenu(m_hMenuHelp);
  110.  
  111.     //Free the menu handle array
  112.     if (NULL!=m_phMenu)
  113.         delete []((UINT *)m_phMenu);
  114.  
  115.     if (m_fInitialized)
  116.         OleUninitialize();
  117.  
  118.     return;
  119.     }
  120.  
  121.  
  122. /*
  123.  * CFrame::Init
  124.  *
  125.  * Purpose:
  126.  *  Initializer for a CFrame object containing anything prone to
  127.  *  failure.
  128.  *
  129.  * Parameters:
  130.  *  cMenus          UINT number of menus on the frame
  131.  *  x, y, cx, cy    int location and size of frame window 
  132.  *
  133.  * Return Value:
  134.  *  BOOL            TRUE if initialization succeeded, FALSE
  135.  *                  otherwise. If FALSE is returned, the caller must
  136.  *                  guarantee that the destructor is called promptly
  137.  *                  to insure cleanup.
  138.  */
  139.  
  140. BOOL CFrame::Init(UINT cMenus, int x, int y, int cx, int cy)
  141.     {
  142.     HMENU               hMenu;
  143.     UINT                uTemp;
  144.     RECT                rc;
  145.  
  146.     //1.  Initialize OLE
  147.     if (SUCCEEDED(OleInitialize(NULL)))
  148.         m_fInitialized=TRUE;
  149.     else
  150.         return FALSE;
  151.  
  152.  
  153.     //2.  Register window classes
  154.     if (NULL==m_hInstPrev)
  155.         {
  156.         if (!RegisterAllClasses())
  157.             return FALSE;
  158.         }
  159.  
  160.  
  161.     //3.  Create the main window and client-area window
  162.     m_hWnd=CreateWindow(SZCLASSFRAME, TEXT("DocObject Framer")
  163.         , WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN
  164.         , x, y, cx, cy, NULL, NULL, m_hInst, this);
  165.         
  166.     if (NULL==m_hWnd)
  167.         return FALSE;
  168.  
  169.     GetClientRect(m_hWnd, &rc);
  170.  
  171.     m_hWndClient=CreateWindow(SZCLASSCLIENT, SZCLASSCLIENT
  172.         , WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_CLIPSIBLINGS
  173.         , rc.left, rc.top, rc.right-rc.left
  174.         , rc.bottom-rc.top, m_hWnd, NULL, m_hInst, this);
  175.  
  176.     if (NULL==m_hWndClient)
  177.         return FALSE;
  178.  
  179.     //4. Allocate menu array for use with in-place menu merging.
  180.     m_phMenu=new HMENU[cMenus];
  181.     hMenu=GetMenu(m_hWnd);
  182.     m_hMenuOrg=hMenu;
  183.  
  184.     for (uTemp=0; uTemp < cMenus; uTemp++)
  185.         m_phMenu[uTemp]=GetSubMenu(hMenu, uTemp);
  186.  
  187.     //Also load the special help menu
  188.     m_hMenuHelp=LoadMenu(m_hInst
  189.         , MAKEINTRESOURCE(IDR_MENUHELP));
  190.  
  191.     //5.  Load accelerators
  192.     m_hAccel=LoadAccelerators(m_hInst
  193.         , MAKEINTRESOURCE(IDR_ACCELERATORS));
  194.  
  195.     if (NULL==m_hAccel)
  196.         return FALSE;
  197.  
  198.  
  199.     //6.  Make us all visible.
  200.     ShowWindow(m_hWnd, m_nCmdShow);
  201.     UpdateWindow(m_hWnd);
  202.  
  203.  
  204.     /*
  205.      * 7.  Create a temp file for all embedded files.  Note that in this
  206.      *     sample we don't save any changes to DocObjects because we 
  207.      *     don't manage any storage directly.
  208.      */      
  209.     if (FAILED(StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE
  210.         | STGM_SHARE_EXCLUSIVE | STGM_CREATE| STGM_DELETEONRELEASE
  211.         , 0, &m_pIStorage)))
  212.         return FALSE;
  213.  
  214.     return TRUE;
  215.     }
  216.  
  217.  
  218.  
  219.  
  220.  
  221. /*
  222.  * CFrame::RegisterAllClasses
  223.  *
  224.  * Purpose:
  225.  *  Registers all classes used in this application.
  226.  *
  227.  * Return Value:
  228.  *  BOOL            TRUE if registration succeeded, FALSE otherwise.
  229.  */
  230.  
  231. BOOL CFrame::RegisterAllClasses(void)
  232.     {
  233.     WNDCLASS        wc;
  234.  
  235.     //Field that are the same for all windows.
  236.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  237.     wc.hInstance     = m_hInst;
  238.     wc.cbClsExtra    = 0;
  239.  
  240.     //Register the Frame window
  241.     wc.lpfnWndProc   = FrameWndProc;
  242.     wc.cbWndExtra    = CBFRAMEWNDEXTRA;
  243.     wc.hIcon         = LoadIcon(m_hInst, TEXT("Icon"));
  244.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  245.     wc.hbrBackground = NULL;
  246.     wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU);
  247.     wc.lpszClassName = SZCLASSFRAME;
  248.  
  249.     if (!RegisterClass(&wc))
  250.         return FALSE;
  251.  
  252.  
  253.     //Register the do-nothing Client window
  254.     wc.lpfnWndProc   = ClientWndProc;
  255.     wc.cbWndExtra    = CBCLIENTWNDEXTRA;
  256.     wc.hIcon         = NULL;
  257.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  258.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  259.     wc.lpszMenuName  = NULL;
  260.     wc.lpszClassName = SZCLASSCLIENT;
  261.  
  262.     if (!RegisterClass(&wc))
  263.         return FALSE;
  264.  
  265.     return TRUE;
  266.     }
  267.  
  268.  
  269.  
  270.  
  271. /*
  272.  * CFrame::OnCommand
  273.  *
  274.  * Purpose:
  275.  *  WM_COMMAND handler for the frame window so derivations can
  276.  *  process their messages and then pass the standard commands (like
  277.  *  file open and save) on to the base class.
  278.  *
  279.  * Parameters:
  280.  *  hWnd            HWND of the frame window.
  281.  *  wParam          WPARAM of the message.
  282.  *  lParam          LPARAM of the message.
  283.  *
  284.  * Return Value:
  285.  *  LRESULT         Return value for the message.
  286.  */
  287.  
  288. LRESULT CFrame::OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  289.     {
  290.     TCHAR           szFile[MAX_PATH];
  291.     BOOL            fOK;
  292.     PCHourglass     pHour;
  293.     WORD            wID=LOWORD(wParam);
  294.  
  295.     switch (wID)
  296.         {
  297.         case IDM_FILEOPEN:
  298.             /*
  299.              * This will be disabled if we already have an object.
  300.              * User must File/Close first to get back here. 
  301.              *
  302.              * Otherwise open the File/Open dialog
  303.              */
  304.             szFile[0]=0;
  305.             if (!OpenDialog(szFile, MAX_PATH))
  306.                 return 0L;
  307.                 
  308.             pHour=new CHourglass;            
  309.             fOK=CreateObject(szFile);
  310.             delete pHour;
  311.             return 0;
  312.  
  313.  
  314.         case IDM_FILECLOSE:
  315.             Close();
  316.             break;
  317.  
  318.  
  319.         case IDM_FILEEXIT:
  320.             PostMessage(hWnd, WM_CLOSE, 0, 0L);            
  321.             break;
  322.  
  323.  
  324.         case IDM_HELPABOUT:
  325.             DialogBox(m_hInst, MAKEINTRESOURCE(IDD_ABOUT)
  326.                 , m_hWnd, (DLGPROC)AboutProc);
  327.             break;
  328.  
  329.  
  330.         case IDM_ENTERCONTEXTHELP:
  331.         case IDM_ESCAPECONTEXTHELP:
  332.             //Notify the object on entry and exit.
  333.             ContextSensitiveHelp(IDM_ENTERCONTEXTHELP==wID);
  334.             break;
  335.  
  336.  
  337.         default:
  338.            return DefWindowProc(hWnd, WM_COMMAND, wParam, lParam);
  339.                
  340.         }
  341.  
  342.     return 0L;
  343.     }
  344.  
  345.  
  346.  
  347.  
  348.  
  349. /*
  350.  * CFrame::OpenDialog
  351.  *
  352.  * Purpose:
  353.  *  Invokes the COMMDLG.DLL GetOpenFileName dialog and retrieves
  354.  *  a filename for saving or opening.
  355.  *
  356.  * Parameters:
  357.  *  pszFile         LPTSTR buffer to receive the entered filename.
  358.  *  cchFile         UINT length of pszFile 
  359.  *
  360.  * Return Value:
  361.  *  BOOL            TRUE if the function retrieved a filename,
  362.  *                  FALSE if the user pressed CANCEL.
  363.  */
  364.  
  365. BOOL CFrame::OpenDialog(LPTSTR pszFile, UINT cchFile)
  366.     {
  367.     OPENFILENAME        ofn;
  368.     static TCHAR        szFilter[80]=TEXT("All Files (*.*)\0*.*\0\0");
  369.     BOOL                fRet;
  370.    #ifdef DEBUG
  371.     DWORD               dwErr;
  372.    #endif
  373.  
  374.     if (NULL==pszFile)
  375.         return FALSE;
  376.  
  377.     memset(&ofn, 0, sizeof(OPENFILENAME));
  378.     ofn.lStructSize      =sizeof(OPENFILENAME);
  379.     ofn.hwndOwner        =m_hWnd;
  380.  
  381.     ofn.lpstrFilter      =szFilter;
  382.     ofn.nFilterIndex     =1L;
  383.  
  384.     ofn.lpstrTitle       =NULL;
  385.     ofn.lpstrFile        =pszFile;
  386.     ofn.nMaxFile         =cchFile;
  387.  
  388.     ofn.lpstrDefExt      =TEXT("*");
  389.     ofn.Flags            =OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  390.  
  391.     fRet=GetOpenFileName(&ofn);
  392.     
  393.    #ifdef DEBUG
  394.     dwErr=CommDlgExtendedError();
  395.    #endif
  396.     return fRet;
  397.     }
  398.  
  399.  
  400.  
  401. /*
  402.  * CFrame::CreateObject
  403.  *
  404.  * Purpose:
  405.  *  Creates a site and has it create an object based on a filename.
  406.  *
  407.  * Parameters:
  408.  *  pszFile         LPTSTR pointing to the filename from which to
  409.  *                  create the object.
  410.  *
  411.  * Return Value:
  412.  *  BOOL            TRUE if successful, FALSE otherwise.
  413.  */
  414.  
  415. BOOL CFrame::CreateObject(LPTSTR pszFile)
  416.     {    
  417.     m_pSite=new CSite(++m_dwIDCounter, m_hWndClient, this);
  418.  
  419.     if (NULL==m_pSite)
  420.         return FALSE;
  421.  
  422.     m_pSite->AddRef();  //So we can free with Release
  423.  
  424.     /*
  425.      * Now tell the site to create an object in it using the filename
  426.      * and the storage we opened.  The site will create a sub-storage
  427.      * for the doc object's use.
  428.      */
  429.     if (!m_pSite->Create(pszFile, m_pIStorage))
  430.         return FALSE;
  431.  
  432.     m_fHaveObject=TRUE;
  433.  
  434.     //We created the thing, now activate it with "Show"
  435.     m_pSite->Activate(OLEIVERB_SHOW);
  436.  
  437.     //Force repaint to show "have object" message
  438.     InvalidateRect(m_hWndClient, NULL, TRUE);
  439.     UpdateWindow(m_hWndClient);
  440.     return TRUE;        
  441.     }
  442.  
  443.  
  444.  
  445. /*
  446.  * CFrame::Close
  447.  *
  448.  * Purpose:
  449.  *  Handles File/Close by freeing the object and resetting the
  450.  *  application state.
  451.  *
  452.  * Parameters:
  453.  *  None
  454.  *
  455.  * Return Value:
  456.  *  None
  457.  */
  458.  
  459. void CFrame::Close(void)
  460.     {    
  461.     RECT    rc;
  462.  
  463.     if (NULL!=m_pSite)
  464.         {
  465.         CSite *pSite=m_pSite;        //Prevents reentry
  466.         m_pSite=NULL;
  467.  
  468.         pSite->Close(FALSE);         //Frees the object
  469.         pSite->Destroy(m_pIStorage); //Cleans up the storage
  470.         pSite->Release();            //Frees the site        
  471.         }
  472.     
  473.     m_fHaveObject=FALSE;    
  474.     SetRect(&m_bwIP, 0, 0, 0, 0);    
  475.  
  476.     GetClientRect(m_hWnd, &rc);    
  477.     ResizeClientWindow(rc.left, rc.top, rc.right-rc.left
  478.         , rc.bottom-rc.top);    
  479.  
  480.     //Force repaint to remove "have object" message
  481.     InvalidateRect(m_hWndClient, NULL, TRUE);
  482.     UpdateWindow(m_hWndClient);
  483.     
  484.     return;        
  485.     }
  486.  
  487.  
  488. /*
  489.  * CFrame::ResizeClientWindow
  490.  *
  491.  * Purpose:
  492.  *    Resizes the client-area window according to current toolbar sizes
  493.  *  and the frame window size.
  494.  *
  495.  * Parameters:
  496.  *    x,y,cx,cy        UINT origin and dimensions of the window
  497.  *
  498.  * Return Value:
  499.  *    None
  500.  */
  501.  
  502. void CFrame::ResizeClientWindow(UINT x, UINT y, UINT cx, UINT cy)
  503.     {
  504.     SetWindowPos(m_hWndClient, NULL, x, y, cx, cy        
  505.         , SWP_NOZORDER | SWP_NOACTIVATE);
  506.  
  507.     //Tell the site to tell the object.
  508.     if (NULL!=m_pSite)
  509.         m_pSite->UpdateObjectRects();
  510.  
  511.     return;
  512.     }
  513.  
  514.  
  515. /*
  516.  * CFrame::MessageLoop
  517.  *
  518.  * Purpose:
  519.  *  Spins in a standard message loop (with accelerators) until
  520.  *  WM_QUIT is found after which it returns.
  521.  *
  522.  * Return Value:
  523.  *  WPARAM          Contents of msg.wParam from WM_QUIT.
  524.  */
  525.  
  526. WPARAM CFrame::MessageLoop(void)
  527.     {
  528.     MSG     msg;
  529.  
  530.     while (GetMessage(&msg, NULL, 0,0 ))
  531.         {
  532.         //Always give the object first crack at translation.
  533.         if (NULL!=m_pIOleIPActiveObject)
  534.             {
  535.             HRESULT     hr;
  536.  
  537.             hr=m_pIOleIPActiveObject->TranslateAccelerator(&msg);
  538.  
  539.             //If the object translated the accelerator, we're done
  540.             if (NOERROR==hr)
  541.                 continue;
  542.             }
  543.  
  544.         if (!::TranslateAccelerator(m_hWnd, m_hAccel, &msg))
  545.             {
  546.             TranslateMessage(&msg);
  547.             DispatchMessage(&msg);
  548.             }
  549.         }
  550.  
  551.     return msg.wParam;
  552.     }
  553.  
  554.  
  555.  
  556. /*
  557.  * FrameWndProc
  558.  *
  559.  * Purpose:
  560.  *  Frame window class procedure that allows a derivation of these
  561.  *  classes to hook and process any messages desired.  Otherwise this
  562.  *  handles standard commands as well as the status line and menus.
  563.  */
  564.  
  565. LRESULT APIENTRY FrameWndProc(HWND hWnd, UINT iMsg
  566.     , WPARAM wParam, LPARAM lParam)
  567.     {
  568.     PCFrame         pFR;
  569.     RECT            rc;
  570.     HMENU           hMenu;
  571.  
  572.     pFR=(PCFrame)GetWindowLong(hWnd, FRAMEWL_STRUCTURE);
  573.  
  574.     switch (iMsg)
  575.         {
  576.         case WM_NCCREATE:
  577.             pFR=(PCFrame)((LPCREATESTRUCT)lParam)->lpCreateParams;
  578.  
  579.             SetWindowLong(hWnd, FRAMEWL_STRUCTURE, (LONG)pFR);
  580.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  581.  
  582.         case WM_DESTROY:
  583.             PostQuitMessage(0);
  584.             break;
  585.  
  586.         case WM_CLOSE:                        
  587.             pFR->Close();
  588.             DestroyWindow(hWnd);
  589.             break;
  590.  
  591.         case WM_ERASEBKGND:
  592.             //Client area window always manages painting
  593.             return FALSE;
  594.  
  595.         case WM_SIZE:
  596.             //Tell the in-place object about the new frame size
  597.             GetClientRect(hWnd, &rc);
  598.  
  599.             if (NULL!=pFR->m_pIOleIPActiveObject)
  600.                 pFR->m_pIOleIPActiveObject->ResizeBorder(&rc, pFR, TRUE);
  601.                     
  602.             /*
  603.              * Resize the client, which is done in all cases since this window
  604.              * is the parent of the DocObject, plus we need to tell the 
  605.              * DocObject of the new size through IOleDocumentView::SetRect.
  606.              */
  607.             rc.left  +=pFR->m_bwIP.left;
  608.             rc.right -=pFR->m_bwIP.right;
  609.             rc.top   +=pFR->m_bwIP.top;
  610.             rc.bottom-=pFR->m_bwIP.bottom;            
  611.  
  612.             pFR->ResizeClientWindow(rc.left, rc.top, rc.right-rc.left
  613.                 , rc.bottom-rc.top);
  614.             
  615.             break;
  616.  
  617.  
  618.         case WM_SETFOCUS:
  619.             if (NULL!=pFR->m_pIOleIPActiveObject)
  620.                 {
  621.                 HWND    hWndObj;
  622.  
  623.                 pFR->m_pIOleIPActiveObject->GetWindow(&hWndObj);
  624.                 SetFocus(hWndObj);
  625.                 }
  626.  
  627.             return TRUE;
  628.  
  629.  
  630.         case WM_INITMENU:
  631.             pFR->m_fInObjectHelp=FALSE;
  632.             break;
  633.  
  634.  
  635.         case WM_MENUSELECT:
  636.                 {
  637.                  UINT fuFlags=(UINT)HIWORD(wParam);
  638.                  UINT uItem=(UINT)LOWORD(wParam);
  639.  
  640.                 if (MF_POPUP & fuFlags)
  641.                     {
  642.                     /*
  643.                      * If we're inside our m_hMenuHelp, and uItem is
  644.                      * not zero (first item on the menu, which is ours),
  645.                      * then we must be in an object-supplied menu.
  646.                      *
  647.                      * Therefore we set our flag and forward the message
  648.                      * as well as others that occur later.  Otherwise we
  649.                      * clear the flag so we get messages again.
  650.                      */                
  651.                     if (NULL!=pFR->m_hMenuHelp
  652.                         && (HMENU)lParam==pFR->m_hMenuHelp)                    
  653.                         {
  654.                         pFR->m_fInObjectHelp=(0!=uItem);
  655.                 
  656.                         if (pFR->m_fInObjectHelp)
  657.                             SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  658.                         }                
  659.                     }
  660.                 else
  661.                     {
  662.                     //Forward the message on
  663.                     if (pFR->m_fInObjectHelp)
  664.                         {
  665.                         SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  666.                         break;
  667.                         }
  668.                     }        
  669.                 }
  670.             break;
  671.  
  672.         case WM_INITMENUPOPUP:
  673.             /*
  674.              * If we're in the object's Help menu, forward to
  675.              * the object received in IOleInPlaceFrame::SetActiveObject
  676.              */
  677.             if (pFR->m_fInObjectHelp && NULL!=pFR->m_hWndObj) 
  678.                 SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  679.  
  680.  
  681.             //Skip the system menu
  682.             if (TRUE==(BOOL)HIWORD(lParam))
  683.                 break;
  684.  
  685.             /*
  686.              * If we have an object, enable Close, otherwise
  687.              * enable Open.
  688.              */
  689.             hMenu=(HMENU)wParam;
  690.  
  691.             if (hMenu==pFR->m_phMenu[0])
  692.                 {
  693.                 UINT uTempE=MF_BYCOMMAND | MF_ENABLED;
  694.                 UINT uTempD=MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
  695.  
  696.                 EnableMenuItem(hMenu, IDM_FILEOPEN
  697.                     , pFR->m_fHaveObject ? uTempD : uTempE);
  698.                 EnableMenuItem(hMenu, IDM_FILECLOSE
  699.                     , pFR->m_fHaveObject ? uTempE : uTempD);
  700.                 }
  701.             
  702.             break;
  703.  
  704.         case WM_COMMAND:
  705.             if (pFR->m_fInObjectHelp)
  706.                 {
  707.                 SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  708.                 break;
  709.                 }
  710.             else
  711.                 return pFR->OnCommand(hWnd, wParam, lParam);
  712.  
  713.         case WM_ACTIVATEAPP:
  714.             if (NULL!=pFR->m_pIOleIPActiveObject)
  715.                 {
  716.                 HRESULT hr;
  717.                 hr=pFR->m_pIOleIPActiveObject->OnFrameWindowActivate((BOOL)wParam);
  718.                 }
  719.             break;
  720.  
  721.         default:
  722.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  723.         }
  724.  
  725.     return 0L;
  726.     }
  727.  
  728.  
  729.  
  730. /*
  731.  * ClientWndProc
  732.  *
  733.  * Purpose:
  734.  *  Client window class procedure that's only used to paint a
  735.  *  message when we have a non-DocObject open.  Otherwise this
  736.  *  is completely hidden.
  737.  */
  738.  
  739. LRESULT APIENTRY ClientWndProc(HWND hWnd, UINT iMsg
  740.     , WPARAM wParam, LPARAM lParam)
  741.     {
  742.     PCFrame         pFR;
  743.     PAINTSTRUCT        ps;
  744.  
  745.     pFR=(PCFrame)GetWindowLong(hWnd, CLIENTWL_STRUCTURE);
  746.  
  747.     switch (iMsg)
  748.         {
  749.         case WM_NCCREATE:
  750.             pFR=(PCFrame)((LPCREATESTRUCT)lParam)->lpCreateParams;
  751.  
  752.             SetWindowLong(hWnd, CLIENTWL_STRUCTURE, (LONG)pFR);
  753.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  754.  
  755.         case WM_PAINT:
  756.             BeginPaint(hWnd, &ps);
  757.  
  758.             if (pFR->m_fHaveObject)
  759.                 {
  760.                 static TCHAR szMsg[]={TEXT("A non-DocObject is open or loaded. Use File/Close to destroy it.")};
  761.  
  762.                 SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW));
  763.                 TextOut(ps.hdc, 0, 0, szMsg, lstrlen(szMsg));
  764.                 }
  765.  
  766.             EndPaint(hWnd, &ps);
  767.             break;
  768.  
  769.         default:
  770.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  771.         }
  772.  
  773.     return 0L;
  774.     }
  775.  
  776.  
  777.  
  778.  
  779.  
  780. /*
  781.  * AboutProc
  782.  *
  783.  * Purpose:
  784.  *  Dialog procedure for the omnipresent About box.
  785.  *
  786.  * Parameters:
  787.  *  The standard.
  788.  *
  789.  * Return Value:
  790.  *  The value to be returned through the DialogBox call that
  791.  *  created the dialog.
  792.  *
  793.  */
  794.  
  795. BOOL APIENTRY AboutProc(HWND hDlg, UINT iMsg
  796.     , WPARAM wParam, LPARAM lParam)
  797.     {
  798.     switch (iMsg)
  799.         {
  800.         case WM_INITDIALOG:
  801.             return TRUE;
  802.  
  803.         case WM_COMMAND:
  804.             switch (LOWORD(wParam))
  805.                 {
  806.                 case IDOK:
  807.                     EndDialog(hDlg, TRUE);
  808.                 }
  809.             break;
  810.         }
  811.     return FALSE;
  812.     }
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822. /*
  823.  * IUnknown implementation
  824.  */
  825.  
  826.  
  827. /*
  828.  * CFrame::QueryInterface
  829.  * CFrame::AddRef
  830.  * CFrame::Release
  831.  */
  832.  
  833. STDMETHODIMP CFrame::QueryInterface(REFIID riid, void **ppv)
  834.     {
  835.     /*
  836.      * We only know IOleInPlaceFrame and its base interfaces as well
  837.      * as a bogus IOleCommandTarget to make PowerPoint happy.
  838.      */
  839.     *ppv=NULL;
  840.  
  841.     if (IID_IUnknown==riid || IID_IOleInPlaceUIWindow==riid
  842.         || IID_IOleWindow==riid || IID_IOleInPlaceFrame==riid)
  843.         *ppv=(IOleInPlaceFrame *)this;
  844.  
  845.     if (IID_IOleCommandTarget==riid)
  846.         *ppv=(IOleCommandTarget *)this;
  847.  
  848.     if (NULL!=*ppv)
  849.         {
  850.         ((LPUNKNOWN)*ppv)->AddRef();
  851.         return NOERROR;
  852.         }
  853.  
  854.     return E_NOINTERFACE;
  855.     }
  856.  
  857.  
  858. STDMETHODIMP_(ULONG) CFrame::AddRef(void)
  859.     {
  860.     return ++m_cRef;
  861.     }
  862.  
  863. STDMETHODIMP_(ULONG) CFrame::Release(void)
  864.     {
  865.     //Nothing special happening here--frame's life if user-controlled.
  866.     return --m_cRef;
  867.     }
  868.  
  869.  
  870. /*
  871.  * IOleInPlaceFrame implementation
  872.  */
  873.  
  874.  
  875. /*
  876.  * CFrame::GetWindow
  877.  *
  878.  * Purpose:
  879.  *  Retrieves the handle of the window associated with the object
  880.  *  on which this interface is implemented.
  881.  *
  882.  * Parameters:
  883.  *  phWnd           HWND * in which to store the window handle.
  884.  *
  885.  * Return Value:
  886.  *  HRESULT         NOERROR if successful, E_FAIL if there is no
  887.  *                  window.
  888.  */
  889.  
  890. STDMETHODIMP CFrame::GetWindow(HWND *phWnd)
  891.     {
  892.     *phWnd=m_hWnd;
  893.     return NOERROR;
  894.     }
  895.  
  896.  
  897.  
  898.  
  899. /*
  900.  * CFrame::ContextSensitiveHelp
  901.  *
  902.  * Purpose:
  903.  *  Instructs the object on which this interface is implemented to
  904.  *  enter or leave a context-sensitive help mode.
  905.  *
  906.  * Parameters:
  907.  *  fEnterMode      BOOL TRUE to enter the mode, FALSE otherwise.
  908.  *
  909.  * Return Value:
  910.  *  HRESULT         NOERROR
  911.  */
  912.  
  913. STDMETHODIMP CFrame::ContextSensitiveHelp(BOOL fEnterMode)
  914.     {
  915.     /*
  916.      * Don't bother if there is no active object since we don't do
  917.      * context help on our own.
  918.      */
  919.     if (NULL==m_pIOleIPActiveObject)
  920.         return NOERROR;
  921.  
  922.     //If the state changes, notify the active object.
  923.     if (m_fInContextHelp!=fEnterMode)
  924.         {
  925.         m_fInContextHelp=fEnterMode;
  926.         m_pIOleIPActiveObject->ContextSensitiveHelp(fEnterMode);
  927.         }
  928.  
  929.     return NOERROR;
  930.     }
  931.  
  932.  
  933.  
  934.  
  935. /*
  936.  * CFrame::GetBorder
  937.  *
  938.  * Purpose:
  939.  *  Returns the rectangle in which the container is willing to
  940.  *  negotiate about an object's adornments.
  941.  *
  942.  * Parameters:
  943.  *  prcBorder       LPRECT in which to store the rectangle.
  944.  *
  945.  * Return Value:
  946.  *  HRESULT         NOERROR if all is well, INPLACE_E_NOTOOLSPACE
  947.  *                  if there is no negotiable space.
  948.  */
  949.  
  950. STDMETHODIMP CFrame::GetBorder(LPRECT prcBorder)
  951.     {
  952.     if (NULL==prcBorder)
  953.         return E_INVALIDARG;
  954.  
  955.     //We return all the client area space
  956.     GetClientRect(m_hWnd, prcBorder);
  957.     return NOERROR;
  958.     }
  959.  
  960.  
  961.  
  962.  
  963. /*
  964.  * CFrame::RequestBorderSpace
  965.  *
  966.  * Purpose:
  967.  *  Asks the container if it can surrender the amount of space
  968.  *  in pBW that the object would like for it's adornments.  The
  969.  *  container does nothing but validate the spaces on this call.
  970.  *
  971.  * Parameters:
  972.  *  pBW             LPCBORDERWIDTHS containing the requested space.
  973.  *                  The values are the amount of space requested
  974.  *                  from each side of the relevant window.
  975.  *
  976.  * Return Value:
  977.  *  HRESULT         NOERROR if we can give up space,
  978.  *                  INPLACE_E_NOTOOLSPACE otherwise.
  979.  */
  980.  
  981. STDMETHODIMP CFrame::RequestBorderSpace(LPCBORDERWIDTHS pBW)
  982.     {
  983.     //Framer has no border space restrictions
  984.     return NOERROR;
  985.     }
  986.  
  987.  
  988.  
  989.  
  990. /*
  991.  * CFrame::SetBorderSpace
  992.  *
  993.  * Purpose:
  994.  *  Called when the object now officially requests that the
  995.  *  container surrender border space it previously allowed
  996.  *  in RequestBorderSpace.  The container should resize windows
  997.  *  appropriately to surrender this space.
  998.  *
  999.  * Parameters:
  1000.  *  pBW             LPCBORDERWIDTHS containing the amount of space
  1001.  *                  from each side of the relevant window that the
  1002.  *                  object is now reserving.
  1003.  *
  1004.  * Return Value:
  1005.  *  HRESULT         NOERROR
  1006.  */
  1007.  
  1008. STDMETHODIMP CFrame::SetBorderSpace(LPCBORDERWIDTHS pBW)
  1009.     {
  1010.     RECT            rc;
  1011.  
  1012.     /*
  1013.      * Since we have no tools, we can accept anything the object sends
  1014.      * and must therefore adjust the client-area window accordingly.
  1015.      */
  1016.  
  1017.     /*
  1018.      * If pBW is NULL, the object is not interested in tools, so we
  1019.      * don't have to do anything.  In either case we need to save
  1020.      * the toolspace allocations in order to resize the client window
  1021.      * correctly.
  1022.      */
  1023.     if (NULL==pBW)
  1024.         {
  1025.         if (!m_fOurMenuShowing)
  1026.             SetMenu(NULL, NULL, NULL);
  1027.  
  1028.         SetRect(&m_bwIP, 0, 0, 0, 0);
  1029.         GetClientRect( m_hWnd, &rc );
  1030.         }
  1031.     else
  1032.         {
  1033.         GetClientRect(m_hWnd, &rc);
  1034.         rc.left  +=pBW->left;
  1035.         rc.right -=pBW->right;
  1036.         rc.top   +=pBW->top;
  1037.         rc.bottom-=pBW->bottom;
  1038.  
  1039.         m_bwIP=*pBW;
  1040.         }
  1041.  
  1042.     ResizeClientWindow(rc.left, rc.top, rc.right-rc.left
  1043.         , rc.bottom-rc.top);
  1044.     
  1045.     return NOERROR;
  1046.     }
  1047.  
  1048.  
  1049.  
  1050.  
  1051. /*
  1052.  * CFrame::SetActiveObject
  1053.  *
  1054.  * Purpose:
  1055.  *  Provides the container with the object's IOleInPlaceActiveObject
  1056.  *  pointer
  1057.  *
  1058.  * Parameters:
  1059.  *  pIIPActiveObj   LPOLEINPLACEACTIVEOBJECT of interest.
  1060.  *  pszObj          LPCOLESTR naming the object.  Not used.
  1061.  *
  1062.  * Return Value:
  1063.  *  HRESULT         NOERROR
  1064.  */
  1065.  
  1066. STDMETHODIMP CFrame::SetActiveObject
  1067.     (LPOLEINPLACEACTIVEOBJECT pIIPActiveObj, LPCOLESTR pszObj)
  1068.     {
  1069.     if (NULL!=m_pIOleIPActiveObject)
  1070.         m_pIOleIPActiveObject->Release();
  1071.  
  1072.     //NULLs m_pIOleIPActiveObject if pIIPActiveObj is NULL
  1073.     m_pIOleIPActiveObject=pIIPActiveObj;
  1074.  
  1075.     if (NULL!=m_pIOleIPActiveObject)
  1076.         m_pIOleIPActiveObject->AddRef();
  1077.  
  1078.     m_pIOleIPActiveObject->GetWindow(&m_hWndObj);
  1079.     return NOERROR;
  1080.     }
  1081.  
  1082.  
  1083.  
  1084.  
  1085. /*
  1086.  * CFrame::InsertMenus
  1087.  *
  1088.  * Purpose:
  1089.  *  Instructs the container to place its in-place menu items where
  1090.  *  necessary in the given menu and to fill in elements 0, 2, and 4
  1091.  *  of the OLEMENUGROUPWIDTHS array to indicate how many top-level
  1092.  *  items are in each group.
  1093.  *
  1094.  * Parameters:
  1095.  *  hMenu           HMENU in which to add popups.
  1096.  *  pMGW            LPOLEMENUGROUPWIDTHS in which to store the
  1097.  *                  width of each container menu group.
  1098.  *
  1099.  * Return Value:
  1100.  *  HRESULT         NOERROR
  1101.  */
  1102.  
  1103. STDMETHODIMP CFrame::InsertMenus(HMENU hMenu
  1104.     , LPOLEMENUGROUPWIDTHS pMGW)
  1105.     {    
  1106.     //Copy our File menu into the shared menu.    
  1107.     InsertMenu(hMenu, 0, MF_BYPOSITION | MF_POPUP, (UINT)m_phMenu[0]
  1108.         , TEXT("&File"));
  1109.  
  1110.     pMGW->width[0]=1;
  1111.     pMGW->width[2]=0;
  1112.     pMGW->width[4]=0;
  1113.  
  1114.     /*
  1115.      * Add the special help menu which is the first item in
  1116.      * the m_hMenuHelp popup that's sitting around.
  1117.      */
  1118.     InsertMenu(hMenu, 1, MF_BYPOSITION | MF_POPUP
  1119.         , (UINT)m_hMenuHelp, TEXT("&Help"));
  1120.  
  1121.     //Tell the object we added our Help menu
  1122.     pMGW->width[5]=1;    
  1123.     return NOERROR;
  1124.     }
  1125.  
  1126.  
  1127.  
  1128.  
  1129. /*
  1130.  * CFrame::SetMenu
  1131.  *
  1132.  * Purpose:
  1133.  *  Instructs the container to replace whatever menu it's currently
  1134.  *  using with the given menu and to call OleSetMenuDescritor so OLE
  1135.  *  knows to whom to dispatch messages.
  1136.  *
  1137.  * Parameters:
  1138.  *  hMenu           HMENU to show.
  1139.  *  hOLEMenu        HOLEMENU to the menu descriptor.
  1140.  *  hWndObj         HWND of the active object to which messages are
  1141.  *                  dispatched.
  1142.  *
  1143.  * Return Value:
  1144.  *  HRESULT         NOERROR
  1145.  */
  1146.  
  1147. STDMETHODIMP CFrame::SetMenu(HMENU hMenu, HOLEMENU hOLEMenu
  1148.     , HWND hWndObj)
  1149.     {
  1150.     HRESULT         hr;
  1151.  
  1152.     /*
  1153.      * Our responsibilities here are to put the menu on the frame
  1154.      * window and call OleSetMenuDescriptor.
  1155.      */
  1156.  
  1157.     if (NULL==hMenu)
  1158.         {
  1159.         //Prevent redundant calls, or debug warnings on startup.
  1160.         if (NULL==m_hMenuTop)
  1161.             return NOERROR;
  1162.  
  1163.         hMenu=m_hMenuTop;
  1164.         m_hMenuTop=NULL;
  1165.         m_fOurMenuShowing=TRUE;
  1166.         }
  1167.     else
  1168.         {
  1169.         m_hMenuTop=m_hMenuOrg;
  1170.         m_fOurMenuShowing=FALSE;
  1171.  
  1172.         /*
  1173.          * Check if our Help menu has anything added to it.  If so, then
  1174.          * remember to forward menu messages.  If not, remove the Help
  1175.          * menu altogether (destroying it after removing our normal Help
  1176.          * popup, as we also do in RemoveMenus.
  1177.          */
  1178.         if (CHELPITEMS!=GetMenuItemCount(m_hMenuHelp))
  1179.             m_fUsingOurHelp=TRUE;
  1180.         else
  1181.             {            
  1182.             UINT    i, cItems;
  1183.                 
  1184.             cItems=GetMenuItemCount(hMenu);            
  1185.  
  1186.             //Find m_hMenuHelp in the menu and remove it.
  1187.             for (i=0; i < cItems; i++)
  1188.                 {
  1189.                 if (GetSubMenu(hMenu, i)==m_hMenuHelp)
  1190.                     {
  1191.                     RemoveMenu(hMenu, i, MF_BYPOSITION);
  1192.                     break;
  1193.                     }
  1194.                 }                            
  1195.             }            
  1196.         }
  1197.  
  1198.     if (NULL!=hMenu)
  1199.         ::SetMenu(m_hWnd, hMenu);
  1200.  
  1201.     DrawMenuBar(m_hWnd);
  1202.  
  1203.     hr=OleSetMenuDescriptor(hOLEMenu, m_hWnd, hWndObj, NULL, NULL);
  1204.     return hr;
  1205.     }
  1206.  
  1207.  
  1208.  
  1209.  
  1210. /*
  1211.  * CFrame::RemoveMenus
  1212.  *
  1213.  * Purpose:
  1214.  *  Asks the container to remove any menus it put into hMenu in
  1215.  *  InsertMenus.
  1216.  *
  1217.  * Parameters:
  1218.  *  hMenu           HMENU from which to remove the container's
  1219.  *                  items.
  1220.  *
  1221.  * Return Value:
  1222.  *  HRESULT         NOERROR
  1223.  */
  1224.  
  1225. STDMETHODIMP CFrame::RemoveMenus(HMENU hMenu)
  1226.     {
  1227.     int         cItems, i, j;
  1228.     HMENU       hMenuT;
  1229.  
  1230.     /*
  1231.      * To be defensive, loop through this menu removing anything
  1232.      * we recognize (that is, anything in m_phMenu) just in case
  1233.      * the server didn't clean it up right.  At least we can
  1234.      * give ourselves the prophylactic benefit.
  1235.      */
  1236.  
  1237.     if (NULL==hMenu)
  1238.         return NOERROR;
  1239.  
  1240.     cItems=GetMenuItemCount(hMenu);
  1241.  
  1242.     /*
  1243.      * Walk backwards down the menu.  For each popup, see if it
  1244.      * matches any other popup we know about, and if so, remove
  1245.      * it from the shared menu.
  1246.      */
  1247.     for (i=cItems; i >=0; i--)
  1248.         {
  1249.         hMenuT=GetSubMenu(hMenu, i);
  1250.  
  1251.         for (j=0; j <= CMENUS; j++)
  1252.             {
  1253.             //Remove any owned popup, or our special help menu
  1254.             if (hMenuT==m_phMenu[j]
  1255.                 || (hMenuT==m_hMenuHelp && m_hMenuHelp!=NULL))
  1256.                 RemoveMenu(hMenu, i, MF_BYPOSITION);
  1257.             }
  1258.         }
  1259.     
  1260.     m_fUsingOurHelp=FALSE;
  1261.  
  1262.     //The menu should now be empty.
  1263.     return NOERROR;
  1264.     }
  1265.  
  1266.  
  1267.  
  1268.  
  1269. /*
  1270.  * CFrame::SetStatusText
  1271.  *
  1272.  * Purpose:
  1273.  *  Asks the container to place some text in a status line, if one
  1274.  *  exists.  If the container does not have a status line it
  1275.  *  should return E_FAIL here in which case the object could
  1276.  *  display its own.
  1277.  *
  1278.  * Parameters:
  1279.  *  pszText         LPCOLESTR to display.
  1280.  *
  1281.  * Return Value:
  1282.  *  HRESULT         NOERROR if successful, S_TRUNCATED if not all
  1283.  *                  of the text could be displayed, or E_FAIL if
  1284.  *                  the container has no status line.
  1285.  */
  1286.  
  1287. STDMETHODIMP CFrame::SetStatusText(LPCOLESTR pszText)
  1288.     {
  1289.     //We have no status line...
  1290.     return E_NOTIMPL;
  1291.     }
  1292.  
  1293.  
  1294.  
  1295. /*
  1296.  * CFrame::EnableModeless
  1297.  *
  1298.  * Purpose:
  1299.  *  Instructs the container to show or hide any modeless popup
  1300.  *  windows that it may be using.
  1301.  *
  1302.  * Parameters:
  1303.  *  fEnable         BOOL indicating to enable/show the windows
  1304.  *                  (TRUE) or to hide them (FALSE).
  1305.  *
  1306.  * Return Value:
  1307.  *  HRESULT         NOERROR
  1308.  */
  1309.  
  1310. STDMETHODIMP CFrame::EnableModeless(BOOL fEnable)
  1311.     {
  1312.     return NOERROR;
  1313.     }
  1314.  
  1315.  
  1316.  
  1317.  
  1318. /*
  1319.  * CFrame::TranslateAccelerator
  1320.  *
  1321.  * Purpose:
  1322.  *  When dealing with an in-place object from an EXE server, this
  1323.  *  is called to give the container a chance to process accelerators
  1324.  *  after the server has looked at the message.
  1325.  *
  1326.  * Parameters:
  1327.  *  pMSG            LPMSG for the container to examine.
  1328.  *  wID             WORD the identifier in the container's
  1329.  *                  accelerator table (from IOleInPlaceSite
  1330.  *                  ::GetWindowContext) for this message (OLE does
  1331.  *                  some translation before calling).
  1332.  *
  1333.  * Return Value:
  1334.  *  HRESULT         NOERROR if the keystroke was used,
  1335.  *                  S_FALSE otherwise.
  1336.  */
  1337.  
  1338. STDMETHODIMP CFrame::TranslateAccelerator(LPMSG pMSG, WORD wID)
  1339.     {
  1340.     /*
  1341.      * wID already has anything translated from m_hAccel for us,
  1342.      * so we can just check for the commands we want and process
  1343.      * them instead of calling TranslateAccelerator which would be
  1344.      * redundant and which also has a possibility of dispatching to
  1345.      * the wrong window.
  1346.      */
  1347.     if (IDM_ENTERCONTEXTHELP==wID || IDM_ESCAPECONTEXTHELP==wID)
  1348.         {
  1349.         //wID properly expands to 32-bits
  1350.         OnCommand(m_hWnd, (WPARAM)wID, 0L);
  1351.         return NOERROR;
  1352.         }
  1353.  
  1354.     return S_FALSE;
  1355.     }
  1356.  
  1357.  
  1358. /*
  1359.  * IOleCommandTarget methods, provided to make PowerPoint happy
  1360.  * with this frame.
  1361.  */
  1362.  
  1363. STDMETHODIMP CFrame::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds
  1364.     , OLECMD *prgCmds, OLECMDTEXT *pCmdText)
  1365.     {
  1366.     return OLECMDERR_E_UNKNOWNGROUP;
  1367.     }
  1368.         
  1369. STDMETHODIMP CFrame::Exec(const GUID *pguidCmdGroup, DWORD nCmdID
  1370.     , DWORD nCmdexecopt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  1371.     {
  1372.     return OLECMDERR_E_UNKNOWNGROUP;
  1373.     }
  1374.     
  1375.