FIGURE.CPP
/* 
 * FIGURE.CPP 
 * Cosmo Chapter 23 
 * 
 * Implementation of the CFigure object for Cosmo. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#include "cosmo.h" 
 
 
/* 
 * CFigure::CFigure 
 * CFigure::~CFigure 
 * 
 * Parameters (Constructor): 
 *  pfnDestroy      PFNDESTROYED to call when object is destroyed. 
 *  pDoc            PCCosmoDoc we're associated with. 
 */ 
 
CFigure::CFigure(PFNDESTROYED pfnDestroy, PCCosmoDoc pDoc) 
    { 
    m_cRef=0; 
    m_pfnDestroy=pfnDestroy; 
 
    m_pFR=NULL;     //We get this later through FrameSet. 
    m_pDoc=pDoc; 
    m_pPL=pDoc->m_pPL; 
 
    m_fEmbedded=FALSE; 
 
    //NULL any contained interfaces initially. 
    m_pImpIPersistStorage=NULL; 
    m_pIStorage=NULL; 
    m_pIStream=NULL; 
    m_pImpIDataObject=NULL; 
    m_pIDataAdviseHolder=NULL; 
    m_pImpIOleObject=NULL; 
    m_pIOleAdviseHolder=NULL; 
    m_pIOleClientSite=NULL; 
 
    m_clsID=CLSID_CosmoFigure; 
    m_cf=pDoc->m_cf; 
 
    //These are for IDataObject::QueryGetData 
    m_cfeGet=CFORMATETCGET; 
 
    SETDefFormatEtc(m_rgfeGet[0], pDoc->m_cf, TYMED_HGLOBAL); 
    SETDefFormatEtc(m_rgfeGet[1], pDoc->m_cfEmbedSource 
        , TYMED_ISTORAGE); 
    SETDefFormatEtc(m_rgfeGet[2], pDoc->m_cfObjectDescriptor 
        , TYMED_HGLOBAL); 
    SETDefFormatEtc(m_rgfeGet[3], CF_METAFILEPICT, TYMED_MFPICT); 
    SETDefFormatEtc(m_rgfeGet[4], CF_BITMAP, TYMED_GDI); 
 
    m_pST=NULL; 
 
    m_pImpIPersistFile=NULL; 
 
    //We live in the document's lifetime, so no need to AddRef here. 
    m_pMoniker=m_pDoc->m_pMoniker; 
    m_dwRegROT=0L; 
 
    //CHAPTER23MOD 
    m_pIOleIPSite=NULL; 
    m_pIOleIPFrame=NULL; 
    m_pIOleIPUIWindow=NULL; 
    m_pImpIOleIPObject=NULL; 
    m_pImpIOleIPActiveObject=NULL; 
    m_hMenuShared=NULL; 
    m_hOLEMenu=NULL; 
    m_hAccel=NULL; 
    m_pHW=NULL; 
    m_pTB=NULL; 
    m_cyBar=0; 
    m_fUndoDeactivates=FALSE; 
    m_fAllowInPlace=TRUE; 
    m_fForceSave=FALSE; 
    //End CHAPTER23MOD 
 
    return; 
    } 
 
 
CFigure::~CFigure(void) 
    { 
    ReleaseInterface(m_pIOleClientSite); 
    ReleaseInterface(m_pIDataAdviseHolder); 
    ReleaseInterface(m_pIOleAdviseHolder); 
 
    //CHAPTER23MOD 
    if (NULL!=m_pHW) 
        delete m_pHW; 
 
    if (NULL!=m_pST) 
        delete m_pST; 
 
    /* 
     * Free contained interfaces. 
     * Container in-place interfaces released during deactivation. 
     */ 
 
    if (NULL!=m_pTB)    //Safety-net 
        delete m_pTB; 
 
    DeleteInterfaceImp(m_pImpIOleIPObject); 
    DeleteInterfaceImp(m_pImpIOleIPActiveObject); 
    //End CHAPTER23MOD 
 
    //Make sure no one thinks we're still running 
    if (0L!=m_dwRegROT) 
        INOLE_RevokeAsRunning(&m_dwRegROT); 
 
    ReleaseInterface(m_pIStorage) 
    ReleaseInterface(m_pIStream) 
 
    DeleteInterfaceImp(m_pImpIPersistFile); 
    DeleteInterfaceImp(m_pImpIOleObject) 
    DeleteInterfaceImp(m_pImpIDataObject) 
    DeleteInterfaceImp(m_pImpIPersistStorage); 
 
    //Free strings. 
    if (NULL!=m_pST) 
        delete m_pST; 
 
    return; 
    } 
 
 
 
 
 
/* 
 * CFigure::QueryInterface 
 * CFigure::AddRef 
 * CFigure::Release 
 * 
 * Purpose: 
 *  IUnknown members for CFigure object. 
 */ 
 
STDMETHODIMP CFigure::QueryInterface(REFIID riid, PPVOID ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid) 
        *ppv=this; 
 
    if (IID_IPersist==riid || IID_IPersistStorage==riid) 
        *ppv=m_pImpIPersistStorage; 
 
    if (IID_IDataObject==riid) 
        *ppv=m_pImpIDataObject; 
 
    if (IID_IOleObject==riid) 
        *ppv=m_pImpIOleObject; 
 
    if (IID_IPersistFile==riid) 
        *ppv=m_pImpIPersistFile; 
 
    //CHAPTER23MOD 
    if (IID_IOleWindow==riid || IID_IOleInPlaceObject==riid) 
        *ppv=m_pImpIOleIPObject; 
    //End CHAPTER23MOD 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CFigure::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
 
STDMETHODIMP_(ULONG) CFigure::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    if (NULL!=m_pfnDestroy) 
        (*m_pfnDestroy)(); 
 
    //Document deletes us 
    return 0; 
    } 
 
 
 
 
 
 
/* 
 * CFigure::Init 
 * 
 * Purpose: 
 *  Performs any initialization of a CFigure that's prone to failure 
 *  that we also use internally before exposing the object outside. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if the function is successful, 
 *                  FALSE otherwise. 
 */ 
 
BOOL CFigure::Init(void) 
    { 
    m_pST=new CStringTable(m_pDoc->m_hInst); 
 
    if (NULL==m_pST) 
        return FALSE; 
 
    if (!m_pST->Init(IDS_FIGUREMIN, IDS_FIGUREMAX)) 
        return FALSE; 
 
    //Allocate contained interfaces. 
    m_pImpIPersistStorage=new CImpIPersistStorage(this, this); 
 
    if (NULL==m_pImpIPersistStorage) 
        return FALSE; 
 
    m_pImpIDataObject=new CImpIDataObject(this, this); 
 
    if (NULL==m_pImpIDataObject) 
        return FALSE; 
 
    m_pImpIOleObject=new CImpIOleObject(this, this); 
 
    if (NULL==m_pImpIOleObject) 
        return FALSE; 
 
    m_pImpIPersistFile=new CImpIPersistFile(this, this); 
 
    if (NULL==m_pImpIPersistFile) 
        return FALSE; 
 
    //CHAPTER23MOD 
    m_pImpIOleIPObject=new CImpIOleInPlaceObject(this, this); 
 
    if (NULL==m_pImpIOleIPObject) 
        return FALSE; 
 
    m_pImpIOleIPActiveObject=new CImpIOleInPlaceActiveObject(this 
        , this); 
 
    if (NULL==m_pImpIOleIPActiveObject) 
        return FALSE; 
 
    m_pHW=new CHatchWin(m_pDoc->m_hInst); 
 
    if (NULL==m_pHW) 
        return FALSE; 
 
    //We don't have m_pFR yet from which to get the frame window. 
    if (!m_pHW->Init(m_pDoc->Window(), ID_HATCHWINDOW, NULL)) 
        return FALSE; 
    //End CHAPTER23MOD 
 
    return TRUE; 
    } 
 
 
 
/* 
 * CFigure::FrameSet 
 * 
 * Purpose: 
 *  Provides the compound document object with access to the frame 
 *  of this application for UI purposes. 
 * 
 * Parameters: 
 *  pFR             PCCosmoFrame of the frame window. 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CFigure::FrameSet(PCCosmoFrame pFR) 
    { 
    m_pFR=pFR; 
 
    //CHAPTER23MOD 
    //We need this in IOleInPlaceActiveObject::ResizeBorder 
    m_cyBar=m_pFR->m_cyBar; 
 
    //We need this in IOleInPlaceActiveObject::TranslateAccelerator 
    m_hAccel=m_pFR->m_hAccel; 
    //End CHAPTER23MOD 
    return; 
    } 
 
 
 
 
/* 
 * CFigure::FIsDirty 
 * 
 * Purpose: 
 *  Checks if the document is dirty.  This can be called from 
 *  IPersistStorage::IsDirty which doesn't have access to CCosmoDoc. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if dirty, FALSE if clean. 
 */ 
 
BOOL CFigure::FIsDirty(void) 
    { 
    //CHAPTER23MOD 
    //Force a save if we opened after being in-place. 
    return m_pDoc->m_fDirty || m_fForceSave; 
    //End CHAPTER23MOD 
    } 
 
 
 
 
/* 
 * CFigure::FIsEmbedded 
 * 
 * Purpose: 
 *  Answers if the object is embedded or not. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if the object is embedded, FALSE otherwise. 
 */ 
 
BOOL CFigure::FIsEmbedded(void) 
    { 
    return m_fEmbedded; 
    } 
 
 
 
 
/* 
 * CFigure::SendAdvise 
 * 
 * Purpose: 
 *  Calls the appropriate IOleClientSite or IAdviseSink member 
 *  function for various events such as closure, saving, etc. 
 * 
 * Parameters: 
 *  uCode           UINT OBJECTCODE_* identifying the notification. 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CFigure::SendAdvise(UINT uCode) 
    { 
    switch (uCode) 
        { 
        case OBJECTCODE_SAVED: 
            if (NULL!=m_pIOleAdviseHolder) 
                m_pIOleAdviseHolder->SendOnSave(); 
 
break; 
 
        case OBJECTCODE_CLOSED: 
            if (NULL!=m_pIOleAdviseHolder) 
                m_pIOleAdviseHolder->SendOnClose(); 
 
break; 
 
        case OBJECTCODE_RENAMED: 
            m_pMoniker=m_pDoc->m_pMoniker;  //For IOleObject::GetMoniker 
            m_dwRegROT=m_pDoc->m_dwRegROT; 
 
            if (NULL!=m_pIOleAdviseHolder) 
                m_pIOleAdviseHolder->SendOnRename(m_pMoniker); 
 
            break; 
 
        case OBJECTCODE_SAVEOBJECT: 
            if (FIsDirty() && NULL!=m_pIOleClientSite) 
                m_pIOleClientSite->SaveObject(); 
 
            break; 
 
        case OBJECTCODE_DATACHANGED: 
            //No flags are necessary here. 
            if (NULL!=m_pIDataAdviseHolder) 
                { 
                m_pIDataAdviseHolder->SendOnDataChange 
                    (m_pImpIDataObject, 0, 0); 
                } 
 
            //Tell the running object table of the change 
            if (0!=m_dwRegROT) 
                INOLE_NoteChangeTime(m_dwRegROT, NULL, NULL); 
 
            //CHAPTER23MOD 
            /* 
             * If this is the first change after activation, tell the 
             * container to free any undo information it's holding. 
             */ 
            if (NULL!=m_pIOleIPSite && m_fUndoDeactivates) 
                m_pIOleIPSite->DiscardUndoState(); 
 
            m_fUndoDeactivates=FALSE; 
            //End CHAPTER23MOD 
 
            break; 
 
        case OBJECTCODE_SHOWWINDOW: 
            if (NULL!=m_pIOleClientSite) 
                m_pIOleClientSite->OnShowWindow(TRUE); 
 
            break; 
 
        case OBJECTCODE_HIDEWINDOW: 
            if (NULL!=m_pIOleClientSite) 
                m_pIOleClientSite->OnShowWindow(FALSE); 
 
            break; 
 
        case OBJECTCODE_SHOWOBJECT: 
            if (NULL!=m_pIOleClientSite) 
                m_pIOleClientSite->ShowObject(); 
 
            break; 
        } 
 
    return; 
    } 
 
 
 
 
//CHAPTER23MOD 
/* 
 * CFigure::InPlaceActivate 
 * 
 * Purpose: 
 *  Goes through all the steps of activating the Figure as an 
 *  in-place object. 
 * 
 * Parameters: 
 *  pActiveSite     LPOLECLIENTSITE of the active site we show in. 
 *  fIncludeUI      BOOL indicating if we should do UI as well. 
 * 
 * Return Value: 
 *  HRESULT         Whatever error code is appropriate. 
 */ 
 
HRESULT CFigure::InPlaceActivate(LPOLECLIENTSITE pActiveSite 
    , BOOL fIncludeUI) 
    { 
    HRESULT                 hr; 
    HWND                    hWnd, hWndHW; 
    RECT                    rcPos; 
    RECT                    rcClip; 
 
    if (NULL==pActiveSite) 
        return ResultFromScode(E_INVALIDARG); 
 
    //If we're already active, do the UI and we're done. 
    if (NULL!=m_pIOleIPSite) 
        { 
        if (fIncludeUI) 
            UIActivate(); 
 
        return NOERROR; 
        } 
 
    /* 
     * 1.  Initialization, obtaining interfaces, calling 
     *     OnInPlaceActivate. 
     */ 
    hr=pActiveSite->QueryInterface(IID_IOleInPlaceSite 
        , (PPVOID)&m_pIOleIPSite); 
 
    if (FAILED(hr)) 
        return hr; 
 
    hr=m_pIOleIPSite->CanInPlaceActivate(); 
 
    if (NOERROR!=hr) 
        { 
        m_pIOleIPSite->Release(); 
        m_pIOleIPSite=NULL; 
        return ResultFromScode(E_FAIL); 
        } 
 
    m_pIOleIPSite->OnInPlaceActivate(); 
    m_fUndoDeactivates=TRUE; 
 
    /* 
     * 2.  Get the window context and create a window or change the 
     *     parent and position of an existing window.  Servers are 
     *     required to full cb in the OLEINPLACEFRAMEINFO structure. 
     */ 
    m_pIOleIPSite->GetWindow(&hWnd); 
    m_pFR->m_frameInfo.cb=sizeof(OLEINPLACEFRAMEINFO); 
 
    m_pIOleIPSite->GetWindowContext(&m_pIOleIPFrame 
        , &m_pIOleIPUIWindow, &rcPos, &rcClip 
        , &m_pFR->m_frameInfo); 
 
    /* 
     * Copy container frame pointer to CCosmoFrame for accelerators. 
     * No AddRef because frame never messes with it.  Note also that 
     * we don't do anything special with our own accelerators here 
     * because we just use the same ones as always. 
     */ 
    m_pFR->m_pIOleIPFrame=m_pIOleIPFrame; 
 
    /* 
     * We'll use a hatch window as the child of the container and the 
     * editing window as a child of the hatch window.  We already 
     * created the hatch window, so now all we have to do is put it 
     * in the right place and stick the Polyline in it. 
     */ 
 
    m_pHW->HwndAssociateSet(m_pFR->Window()); 
 
    m_pHW->ChildSet(m_pPL->Window());   //Calls SetParent 
    m_pHW->RectsSet(&rcPos, &rcClip);   //Positions polyline 
 
    hWndHW=m_pHW->Window(); 
    SetParent(hWndHW, hWnd);            //Move the hatch window 
    ShowWindow(hWndHW, SW_SHOW);        //Make us visible. 
    SendAdvise(OBJECTCODE_SHOWOBJECT); 
 
    if (fIncludeUI) 
        return UIActivate(); 
 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFigure::InPlaceDeactivate 
 * 
 * Purpose: 
 *  Reverses all the activation steps from InPlaceActivate. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CFigure::InPlaceDeactivate(void) 
    { 
    RECT        rc; 
 
    UIDeactivate(); 
 
    /* 
     * When setting the parent back to the normal document, 
     * reposition the Polyline to be at (8,8) instead of at wherever 
     * it was in the container's window or our hatch window.  This 
     * is so if we are deactivating to open in our own window the 
     * Polyline appears in the proper place in the document window. 
     */ 
 
    SetParent(m_pPL->Window(), m_pDoc->m_hWnd); 
    m_pHW->ChildSet(NULL); 
 
    //Make sure the hatch window is invisible and owned by Cosmo 
    ShowWindow(m_pHW->Window(), SW_HIDE); 
    SetParent(m_pHW->Window(), m_pDoc->m_hWnd); 
 
    GetClientRect(m_pDoc->m_hWnd, &rc); 
    InflateRect(&rc, -8, -8); 
 
    SetWindowPos(m_pPL->Window(), NULL, rc.left, rc.top 
        , rc.right-rc.left, rc.bottom-rc.top 
        , SWP_NOZORDER | SWP_NOACTIVATE); 
 
    if (NULL!=m_pIOleIPSite) 
        m_pIOleIPSite->OnInPlaceDeactivate(); 
 
    m_pFR->m_pIOleIPFrame=NULL; 
    ReleaseInterface(m_pIOleIPFrame); 
    ReleaseInterface(m_pIOleIPUIWindow); 
    ReleaseInterface(m_pIOleIPSite); 
 
    return; 
    } 
 
 
 
/* 
 * CFigure::UIActivate 
 * 
 * Purpose: 
 *  Goes through all the steps of activating the user interface of 
 *  the Figure as an in-place object. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  HRESULT         NOERROR or error code. 
 */ 
 
HRESULT CFigure::UIActivate(void) 
    { 
    //1.  Call IOleInPlaceSite::UIActivate 
    if (NULL!=m_pIOleIPSite) 
        m_pIOleIPSite->OnUIActivate(); 
 
    //2.  Critical for accelerators to work initially. 
    SetFocus(m_pHW->Window()); 
 
    //3.  Set the active object 
 
   #ifdef WIN32ANSI 
    OLECHAR     szTemp[40]; 
 
    MultiByteToWideChar(CP_ACP, 0, PSZ(IDS_INPLACETITLE) 
        , -1, szTemp, 40); 
   #endif 
 
    if (NULL!=m_pIOleIPFrame) 
        { 
        m_pIOleIPFrame->SetActiveObject(m_pImpIOleIPActiveObject 
           #ifdef WIN32ANSI 
            , szTemp); 
           #else 
            , PSZ(IDS_INPLACETITLE)); 
           #endif 
        } 
 
    if (NULL!=m_pIOleIPUIWindow) 
        { 
        m_pIOleIPUIWindow->SetActiveObject(m_pImpIOleIPActiveObject 
           #ifdef WIN32ANSI 
            , szTemp); 
           #else 
            , PSZ(IDS_INPLACETITLE)); 
           #endif 
        } 
 
    //4.  Create frame tools 
    InPlaceToolsCreate(); 
 
    //5.  Create the shared menu. 
    InPlaceMenuCreate(); 
 
    return NOERROR; 
    } 
 
 
 
 
 
/* 
 * CFigure::UIDeactivate 
 * 
 * Purpose: 
 *  Reverses all the user interface activation steps from 
 *  UIActivate. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CFigure::UIDeactivate(void) 
    { 
    //1.  Remove the in-place tools 
    InPlaceToolsDestroy(); 
 
    //2.  Remove the shared menu. 
    InPlaceMenuDestroy(); 
 
    //3.  Set active obejcts to NULL 
    if (NULL!=m_pIOleIPFrame) 
        m_pIOleIPFrame->SetActiveObject(NULL, NULL); 
 
    if (NULL!=m_pIOleIPUIWindow) 
        m_pIOleIPUIWindow->SetActiveObject(NULL, NULL); 
 
    //3.  Call IOleInPlaceSite::OnUIDeactivate 
    if (NULL!=m_pIOleIPSite) 
        m_pIOleIPSite->OnUIDeactivate(FALSE); 
 
    return; 
    } 
 
 
 
/* 
 * CFigure::InPlaceMenuCreate 
 * 
 * Purpose: 
 *  Creates and sets a menu for an in-place embedded object. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if everything is well, FALSE on error. 
 */ 
 
BOOL CFigure::InPlaceMenuCreate(void) 
    { 
    HMENU               hMenu, hMenuT; 
    UINT                uTemp=MF_BYPOSITION | MF_POPUP; 
    UINT                i; 
    OLEMENUGROUPWIDTHS  mgw; 
 
    for (i=0; i<6; i++) 
        mgw.width[i]=0; 
 
    //We already have popup menu handles in m_pFR->m_phMenu[] 
 
    //Create the new shared menu and let container do its thing 
    hMenu=CreateMenu(); 
    m_pIOleIPFrame->InsertMenus(hMenu, &mgw); 
 
    /* 
     * Add our menus remembering that the container has added its 
     * already. 
     */ 
    InsertMenu(hMenu, (UINT)mgw.width[0] 
       , uTemp, (UINT)m_pFR->m_phMenu[1], PSZ(IDS_MENUEDIT)); 
 
    /* 
     * Add the Open item to the edit menu. 
     * NOTE:  If you are a multiple-use server, this sort of code 
     * will also modify the menu on the server window as well as 
     * this shared menu in which case you need a separate popup menu 
     * altogether. 
     */ 
    AppendMenu(m_pFR->m_phMenu[1], MF_SEPARATOR, 0, NULL); 
    AppendMenu(m_pFR->m_phMenu[1], MF_STRING, IDM_EDITOPEN 
        , PSZ(IDS_MENUOPEN)); 
 
    InsertMenu(hMenu, (UINT)mgw.width[0]+1+(UINT)mgw.width[2] 
       , uTemp, (UINT)m_pFR->m_phMenu[2], PSZ(IDS_MENUCOLOR)); 
 
    InsertMenu(hMenu, (UINT)mgw.width[0]+1+(UINT)mgw.width[2]+1 
       , uTemp, (UINT)m_pFR->m_phMenu[3], PSZ(IDS_MENULINE)); 
 
    //Window menu position changes between MDI and SDI 
   #ifdef MDI 
    hMenuT=m_pFR->m_phMenu[5]; 
   #else 
    hMenuT=m_pFR->m_phMenu[4]; 
   #endif 
 
    InsertMenu(hMenu, (UINT)mgw.width[0]+1+(UINT)mgw.width[2]+2 
        + (UINT)mgw.width[4], uTemp, (UINT)hMenuT 
        , PSZ(IDS_MENUHELP)); 
 
    //Tell OLE how many items in each group are ours. 
    mgw.width[1]=1; 
    mgw.width[3]=2; 
    mgw.width[5]=1; 
 
    m_hMenuShared=hMenu; 
    m_hOLEMenu=OleCreateMenuDescriptor(m_hMenuShared, &mgw); 
 
    m_pIOleIPFrame->SetMenu(m_hMenuShared, m_hOLEMenu 
        , m_pFR->Window()); 
    return TRUE; 
    } 
 
 
 
 
/* 
 * CFigure::InPlaceMenuDestroy 
 * 
 * Purpose: 
 *  Performs opposite actions from InPlaceMenuCreate 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if all is well, FALSE otherwise. 
 */ 
 
BOOL CFigure::InPlaceMenuDestroy(void) 
    { 
    int         cItems, i, j; 
    HMENU       hMenuT; 
 
    //If we don't have a shared menu, nothing to do. 
    if (NULL==m_hMenuShared) 
        return TRUE; 
 
    //Stop the container frame from using this menu. 
    m_pIOleIPFrame->SetMenu(NULL, NULL, NULL); 
 
    //Clean up what we got from OleCreateMenuDescriptor. 
    OleDestroyMenuDescriptor(m_hOLEMenu); 
    m_hOLEMenu=NULL; 
 
    cItems=GetMenuItemCount(m_hMenuShared); 
 
    /* 
     * Walk backwards down the menu.  For each popup, see if it 
     * matches any other popup we know about, and if so, remove 
     * it from the shared menu. 
     */ 
    for (i=cItems; i >=0; i--) 
        { 
        hMenuT=GetSubMenu(m_hMenuShared, i); 
 
        for (j=0; j <= CMENUS; j++) 
            { 
            /* 
             * If the submenu matches any we have, remove, don't 
             * delete. Since we're walking backwards this only 
             * affects the positions of those menus after us so the 
             * GetSubMenu call above is not affected. 
             */ 
            if (hMenuT==m_pFR->m_phMenu[j]) 
                RemoveMenu(m_hMenuShared, i, MF_BYPOSITION); 
            } 
        } 
 
    /* 
     * Remove the Open item and separator from the Edit menu. 
     * NOTE:  If you are a multiple-user server, this affects the 
     * menu on the server window as well as the shared menu in which 
     * case you need to use a separate popup menu altogether. 
     */ 
    RemoveMenu(m_pFR->m_phMenu[1], MPOS_OPEN, MF_BYPOSITION); 
    RemoveMenu(m_pFR->m_phMenu[1], MPOS_SEP,  MF_BYPOSITION); 
 
    if (NULL!=m_pIOleIPFrame) 
        m_pIOleIPFrame->RemoveMenus(m_hMenuShared); 
 
    DestroyMenu(m_hMenuShared); 
    m_hMenuShared=NULL; 
    return TRUE; 
    } 
 
 
 
 
 
 
/* 
 * CFigure::InPlaceToolsCreate 
 * 
 * Purpose: 
 *  Creates a toolbar for in-place activation and negotiates the 
 *  border space for the toolbar. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if we could allocate the space and create 
 *                  the tools.  FALSE if we fail, meaning that we 
 *                  just do in-place with menus only, since we can 
 *                  do without the tools.  We could fail and attempt 
 *                  to reverse what we might have done already, but 
 *                  since we don't really *need* the toolbar, we 
 *                  keep going. 
 */ 
 
BOOL CFigure::InPlaceToolsCreate(void) 
    { 
    BORDERWIDTHS    bw; 
    HWND            hWnd; 
    UINT            uState=GIZMO_NORMAL; 
    UINT            utCmd =GIZMOTYPE_BUTTONCOMMAND; 
    UINT            utEx  =GIZMOTYPE_BUTTONATTRIBUTEEX; 
    UINT            i; 
    HBITMAP         hBmp; 
    RECT            rc; 
    UINT            dxB, dyB; 
 
    //We don't need anything on the document, so send zeros. 
    SetRectEmpty((LPRECT)&bw); 
 
    if (NULL!=m_pIOleIPUIWindow) 
        m_pIOleIPUIWindow->SetBorderSpace(&bw); 
 
    if (NULL==m_pIOleIPFrame) 
        return FALSE; 
 
    /* 
     * 1.  Make sure we can reserve space for what we need.  If this 
     *     fails then we just do without because the menu has 
     *     everything we really need.  A more willing server could 
     *     put tools in popup windows as well. 
     */ 
 
    if (!InPlaceToolsRenegotiate()) 
        { 
        //If the container doesn't allow us any, don't ask for any. 
        m_pIOleIPFrame->SetBorderSpace(&bw); 
        return FALSE; 
        } 
 
    /* 
     * 2.  Create the toolbar window using the container window as 
     *     the parent.  In order to get messages from it, we use 
     *     it's AssociateSet ability directly after creation and 
     *     before we add any tools to the bar. 
     */ 
 
    m_pIOleIPFrame->GetWindow(&hWnd); 
 
    //If we already have a toolbar, just show it again. 
    if (NULL!=m_pTB) 
        { 
        ShowWindow(m_pTB->Window(), SW_SHOW); 
        return TRUE; 
        } 
 
    m_pTB=new CToolBar(m_pFR->m_hInst); 
 
    if (NULL==m_pTB) 
        { 
        SetRectEmpty((LPRECT)&bw); 
        m_pIOleIPFrame->SetBorderSpace(&bw); 
        return FALSE; 
        } 
 
    m_pTB->Init(hWnd, ID_GIZMOBAR, m_cyBar); 
    g_pInPlaceTB=m_pTB; 
 
    //Insure the tools are initially invisible 
    ShowWindow(m_pTB->Window(), SW_HIDE); 
 
    //Tell the toolbar who to send messages to. 
    m_pTB->HwndAssociateSet(m_pFR->m_hWnd); 
 
    /* 
     * Add tools to the bar, setting CFrame::fInit to avoid 
     * command processing 
     */ 
    m_pFR->m_fInit=TRUE; 
 
    hBmp=m_pFR->m_hBmp; 
    dxB=m_pFR->m_dxB; 
    dyB=m_pFR->m_dyB; 
 
    //Edit Undo, Cut, Copy, Paste 
    m_pTB->Add(utCmd, 1, IDM_EDITUNDO,  dxB, dyB, NULL, hBmp, 1, uState); 
    m_pTB->Add(utCmd, 2, IDM_EDITCUT,   dxB, dyB, NULL, NULL, 0, uState); 
    m_pTB->Add(utCmd, 3, IDM_EDITCOPY,  dxB, dyB, NULL, NULL, 1, uState); 
    m_pTB->Add(utCmd, 4, IDM_EDITPASTE, dxB, dyB, NULL, NULL, 2, uState); 
 
    //Separator 
    m_pTB->Add(GIZMOTYPE_SEPARATOR, 5, 0, 6, dyB, NULL, NULL, 0, uState); 
 
    //Color Background and Color Line 
    m_pTB->Add(utCmd, 6, IDM_COLORBACKGROUND, dxB, dyB, NULL, hBmp, 3 
               , GIZMO_NORMAL | PRESERVE_BLACK); 
 
    m_pTB->Add(utCmd, 7, IDM_COLORLINE, dxB, dyB, NULL, hBmp, 4, uState); 
 
    //Separator 
    m_pTB->Add(GIZMOTYPE_SEPARATOR, 8, 0, 6, dyB, NULL, NULL, 0, uState); 
 
    //Line styles. 
    m_pTB->Add(utEx, 19, IDM_LINESOLID, dxB, dyB, NULL, hBmp, 5, uState); 
    m_pTB->Add(utEx, 10, IDM_LINEDASH, dxB, dyB, NULL, hBmp, 6, uState); 
    m_pTB->Add(utEx, 11, IDM_LINEDOT, dxB, dyB, NULL, hBmp, 7, uState); 
    m_pTB->Add(utEx, 12, IDM_LINEDASHDOT, dxB, dyB, NULL, hBmp, 8 
        , uState); 
    m_pTB->Add(utEx, 13, IDM_LINEDASHDOTDOT, dxB, dyB, NULL, hBmp, 9 
        , uState); 
 
    //Check the current line style. 
    i=m_pPL->LineStyleGet()+IDM_LINEMIN; 
    m_pTB->Check(i, TRUE); 
 
    m_pFR->m_fInit=FALSE; 
 
    /* 
     * Before making the toolbar visible, resize it to the 
     * container's GetBorder rectangle.  By default the toolbar 
     * sizes itself to the client area of the parent, but we can't 
     * assume that's the same as GetBorder returns, so we do the 
     * extra work here. 
     */ 
 
    m_pIOleIPFrame->GetBorder(&rc); 
    SetWindowPos(m_pTB->Window(), NULL, rc.left, rc.top 
        , rc.right-rc.left, rc.top+m_cyBar, SWP_NOZORDER); 
 
 
    //3.  Make the tools visible. 
    ShowWindow(m_pTB->Window(), SW_SHOW); 
 
    return TRUE; 
    } 
 
 
 
 
 
 
/* 
 * CFigure::InPlaceToolsDestroy 
 * 
 * Purpose: 
 *  Reverses the process of InPlaceToolsCreate 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if successful, FALSE otherwise. 
 */ 
 
 
BOOL CFigure::InPlaceToolsDestroy(void) 
    { 
    //Nothing to do if we never created anything. 
    if (NULL==m_pTB) 
        return TRUE; 
 
    /* 
     * No reason to call SetBorderSpace with an empty rectangle 
     * since you call IOleInPlaceSite::OnUIDeactivate.  The 
     * container will restore its own tools appropriately. 
     */ 
 
    //Destroy the toolbar. 
    if (NULL!=m_pTB) 
        { 
        delete m_pTB; 
        m_pTB=NULL; 
        g_pInPlaceTB=NULL; 
        } 
 
    return TRUE; 
    } 
 
 
 
/* 
 * CFigure::InPlaceToolsRenegotiate 
 * 
 * Purpose: 
 *  Calls IOleInPlaceFrame::RequestBorderSpace and SetBorderSpace 
 *  to reserve space for our toolbar. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if all is well, FALSE otherwise. 
 */ 
 
BOOL CFigure::InPlaceToolsRenegotiate(void) 
    { 
    HRESULT         hr; 
    BORDERWIDTHS    bw; 
 
    SetRect((LPRECT)&bw, 0, m_pFR->m_cyBar, 0, 0); 
 
    hr=m_pIOleIPFrame->RequestBorderSpace(&bw); 
 
    if (NOERROR!=hr) 
        return FALSE; 
 
    //Safety net:  RequestBorderSpace may modify values in bw 
    SetRect((LPRECT)&bw, 0, m_pFR->m_cyBar, 0, 0); 
    m_pIOleIPFrame->SetBorderSpace(&bw); 
    return TRUE; 
    } 
 
 
 
/* 
 * CFigure::OpenIntoWindow 
 * 
 * Purpose: 
 *  If we're current open in-place, send ourselves the OPEN verb to 
 *  show into a full window. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CFigure::OpenIntoWindow(void) 
    { 
    if (NULL!=m_pIOleIPSite) 
        { 
        //Make sure we don't try to do this. 
        m_fUndoDeactivates=FALSE; 
 
        /* 
         * We can get away with passing a lot of NULLs since we know 
         * how we implemented DoVerb. 
         */ 
        m_pImpIOleObject->DoVerb(OLEIVERB_OPEN, NULL 
            , m_pIOleClientSite, -1, NULL, NULL); 
 
        //This makes sure we save ourselves when closing. 
        m_fForceSave=TRUE; 
 
        //Repaint the container immediately 
        SendAdvise(OBJECTCODE_DATACHANGED); 
        } 
 
    return; 
    } 
 
 
 
/* 
 * Undo 
 * 
 * Purpose: 
 *  If we have not done anything else in this object then call 
 *  IOleInPlaceSite::DeactivateAndUndo and return TRUE, otherwise 
 *  just return FALSE.  Note that the m_fUndoDeactivates is set 
 *  to FALSE in CFigure::SendAdvise for OBJECTCODE_DATACHANGED. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if we deactivated, FALSE otherwise. 
 */ 
 
BOOL CFigure::Undo(void) 
    { 
    if (!m_fUndoDeactivates) 
        return FALSE; 
 
    m_fUndoDeactivates=FALSE; 
    m_pIOleIPSite->DeactivateAndUndo(); 
    return TRUE; 
    } 
 
//End CHAPTER23MOD