// tOleHandler.cpp: implementation of the tOleHandler class.
//
//////////////////////////////////////////////////////////////////////

#include <ole2.h>
#include <assert.h>

#ifndef _OLE2_H_
#define _OLE2_H_
#endif

#include "tOleHandler.h"
#include "tDispatch.h"

/*
 * tOleHandler::tOleHandler
 * tOleHandler::~tOleHandler
 *
 */

tOleHandler::tOleHandler()
{
  natural_width  = 0;
  natural_height = 0;

  m_hWnd=NULL;
  m_pIStorage=NULL;

  m_fInitialized=0;
  m_cOpens=0;

  m_pObj=NULL;
  m_clsID=CLSID_NULL;
  m_fSetExtent=FALSE;

  m_cRef=0;
  m_pIOleObject=NULL;
  m_pIViewObject2=NULL;
  m_grfMisc=0;

  m_rcl.right = m_rcl.left = 0;
  m_rcl.top = m_rcl.bottom = 0;

  m_pImpIOleClientSite=NULL;

  m_fRepaintEnabled=TRUE;


  m_pImpIOleIPSite=NULL;
  m_pIOleIPObject=NULL;
  m_rcPos.left=-1;
  m_fInRectSet=FALSE;

  //CHAPTER24MOD
  m_pImpIOleControlSite=NULL;
  m_pImpIDispatch=NULL;

  m_pIOleControl=NULL;

  m_fHaveControlInfo=FALSE;
  m_cLockInPlace=0;
  m_fPendingDeactivate=FALSE;
  //End CHAPTER24MOD
}


tOleHandler::~tOleHandler(void)
    {

    //Object pointers cleaned up in Close.

    //CHAPTER24MOD

    DeleteInterfaceImp(m_pImpIOleControlSite);
    DeleteInterfaceImp(m_pImpIDispatch);

    //End CHAPTER24MOD

    DeleteInterfaceImp(m_pImpIOleIPSite);
    DeleteInterfaceImp(m_pImpIOleClientSite);
    return;
    }




/*
 * tOleHandler::QueryInterface
 * tOleHandler::AddRef
 * tOleHandler::Release
 *
 * Purpose:
 *  IUnknown members for tOleHandler object.
 */

STDMETHODIMP tOleHandler::QueryInterface(REFIID riid, LPVOID *ppv)
    {
    *ppv=NULL;

    if (IID_IUnknown==riid)
        *ppv=this;

    if (IID_IOleClientSite==riid)
        *ppv=m_pImpIOleClientSite;

    if (IID_IOleWindow==riid || IID_IOleInPlaceSite==riid)
        *ppv=m_pImpIOleIPSite;

    //CHAPTER24MOD
    if (IID_IOleControlSite==riid)
        *ppv=m_pImpIOleControlSite;

    //Queries for IDispatch return the ambient properties interface
    if (IID_IDispatch==riid)
        *ppv=m_pImpIDispatch;
    //End CHAPTER24MOD

    if (NULL!=*ppv)
        {
        ((LPUNKNOWN)*ppv)->AddRef();
        return NOERROR;
        }

    return ResultFromScode(E_NOINTERFACE);
    }


STDMETHODIMP_(ULONG) tOleHandler::AddRef(void)
    {
    return ++m_cRef;
    }

STDMETHODIMP_(ULONG) tOleHandler::Release(void)
    {
    if (0!=--m_cRef)
        return m_cRef;

    delete this;
    return 0;
    }






/*
 * tOleHandler::Create
 *
 * Purpose:
 *  Creates a new tenant of the given CLSID, which can be either a
 *  static bitmap or metafile or any compound document object.
 *
 * Parameters:
 *  tType           TENANTTYPE to create, either a static metafile,
 *                  bitmap, or some kind of compound document object
 *                  This determines which OleCreate* call we use.
 *  pvType          LPVOID providing the relevant pointer from which
 *                  to create the tenant, depending on iType.
 *  pFE             LPFORMATETC specifying the type of renderings
 *                  to use.
 *  pptl            PPOINTL in which we store offset coordinates.
 *  pszl            LPSIZEL where this object should store its
 *                  lometric extents.
 *  pIStorage       LPSTORAGE of the page we live in.  We have to
 *                  create another storage in this for the tenant.
 *  ppo             PPATRONOBJECT containing placement data.
 *  dwData          DWORD with extra data, sensitive to iType.
 *
 * Return Value:
 *  UINT            A CREATE_* value depending on what we
 *                  actually do.
 */

UINT tOleHandler::Create(LPVOID pvType)
    {
    HRESULT             hr;
    LPUNKNOWN           pObj;
    UINT                uRet=CREATE_GRAPHICONLY;
    DWORD       dwMode=STGM_READWRITE
                    | STGM_SHARE_EXCLUSIVE
                    | STGM_DELETEONRELEASE;


    IPersistStorage *persist_storage = NULL;

    StgCreateDocfile(NULL, dwMode, 0, &m_pIStorage);

    if(m_pIStorage == NULL)
      return CREATE_FAILED;

    if (NULL==pvType)
        return CREATE_FAILED;

    hr=ResultFromScode(E_FAIL);

    Open(NULL);

    //CHAPTER24MOD
    /*
     * The OLE Control specifications mention that a
     * a control might implement IPersistStream[Init]
     * instead of IPersistStorage.  In that case you
     * cannot use OleCreate on a control but must rather
     * use CoCreateInstance since OleCreate assumes
     * that IPersistStorage is available.  With a control,
     * you would have to create the object first, then
     * check if OLEMISC_SETCLIENTSITEFIRST is set, then
     * send it your IOleClientSite first.  Then you check
     * for IPersistStorage and failing that, try
     * IPersistStream[Init].
     *
     * For simplicity we'll assume storage-based
     * controls in this sample.
     */
    //End CHAPTER24MOD

    hr = CoCreateInstance(*((LPCLSID)pvType), NULL,
      CLSCTX_ALL, IID_IUnknown, (LPVOID *)&pObj);

    if(FAILED(hr))
      return CREATE_FAILED;

    if(pObj->QueryInterface(IID_IPersistStorage, (void **) &persist_storage) != S_OK)
      return CREATE_FAILED;

    //We need an IOleObject most of the time, so get one here.
    m_pIOleObject=NULL;
    hr = pObj->QueryInterface(IID_IOleObject, (LPVOID*)&m_pIOleObject);

    if(FAILED(hr))
      return CREATE_FAILED;

    // seta o client site
    m_pIOleObject->SetClientSite(m_pImpIOleClientSite);

    // inicializa o objeto
    hr = persist_storage->InitNew(m_pIStorage);

    if(FAILED(hr))
      return CREATE_FAILED;


    //We don't get the size if PatronObject data was seen already.
    if (!ObjectInitialize(pObj))
        {
        return CREATE_FAILED;
        }

    SIZEL   szl;

    hr=ResultFromScode(E_FAIL);

    CalcNaturalSize();

    //CHAPTER24MOD
    //Make sure this happens
    /*if ((OLEMISC_ACTIVATEWHENVISIBLE & m_grfMisc))
        Activate(OLEIVERB_INPLACEACTIVATE, NULL);*/
    //End CHAPTER24MOD

    return uRet;
    }







/*
 * tOleHandler::ObjectInitialize
 * (Protected)
 *
 * Purpose:
 *  Performs operations necessary after creating an object or
 *  reloading one from storage.
 *
 * Parameters:
 *  pObj            LPUNKNOWN of the object in this tenant.
 *  pFE             LPFORMATETC describing the graphic here.
 *  dwData          DWORD extra data.  If pFE->dwAspect==
 *                  DVASPECT_ICON then this is the iconic metafile.
 *
 * Return Value:
 *  BOOL            TRUE if the function succeeded, FALSE otherwise.
 */

BOOL tOleHandler::ObjectInitialize(LPUNKNOWN pObj)
    {
    HRESULT         hr;
    FORMATETC fe;

    SETDefFormatEtc(fe, 0, TYMED_NULL);
    LPFORMATETC pFE = &fe;


    if (NULL==pObj || NULL==pFE)
        return FALSE;

    m_pObj=pObj;
    m_fe=*pFE;
    m_fe.ptd=NULL;
    m_dwState=TENANTSTATE_DEFAULT;

    m_pIViewObject2=NULL;
    hr=pObj->QueryInterface(IID_IViewObject2
        , (LPVOID*)&m_pIViewObject2);

    if (FAILED(hr))
        return FALSE;

    /*
     * Get the MiscStatus bits and check for OLEMISC_ONLYICONIC.
     * If set, force dwAspect in m_fe to DVASPECT_ICON so we
     * remember to draw it properly and do extents right.
     */
    m_pIOleObject->GetMiscStatus(m_fe.dwAspect, &m_grfMisc);


    //CHAPTER24MOD
    //Run the object if it says to do so
    if (OLEMISC_ALWAYSRUN & m_grfMisc)
        OleRun(pObj);
    //End CHAPTER24MOD



    //CHAPTER24MOD
    //Go try initializing control-related things.
    ControlInitialize();
    //End CHAPTER24MOD

    return TRUE;
    }




/*
 * tOleHandler::Open
 *
 * Purpose:
 *  Retrieves the IStorage associated with this tenant.  The
 *  IStorage is owned by the tenant and thus the tenant always
 *  holds a reference count.
 *
 *  If the storage is already open for this tenant, then this
 *  function will AddRef it; therefore the caller must always
 *  match an Open with a Close.
 *
 * Parameters:
 *  pIStorage       LPSTORAGE above this tenant (which has its
 *                  own storage).
 *
 * Return Value:
 *  BOOL            TRUE if opening succeeds, FALSE otherwise.
 */

BOOL tOleHandler::Open(LPSTORAGE pIStorage)
    {
    HRESULT     hr=NOERROR;
    DWORD       dwMode=STGM_TRANSACTED | STGM_READWRITE
                    | STGM_SHARE_EXCLUSIVE;


    //Create these if we don't have them already.
    if (NULL==m_pImpIOleClientSite)
        {
        m_pImpIOleClientSite=new tOleClientSite(this, this);
        m_pImpIOleIPSite=new tOleInPlaceSite(this, this);

        //CHAPTER24MOD
        m_pImpIOleControlSite=new tOleControlSite(this, this);
        m_pImpIDispatch=new tDispatch(this, this);

        if (NULL==m_pImpIOleClientSite 
            || NULL==m_pImpIOleIPSite || NULL==m_pImpIOleControlSite
            || NULL==m_pImpIDispatch)
            return FALSE;
        //End CHAPTER24MOD
        }

    return TRUE;
    }




/*
 * tOleHandler::Close
 *
 * Purpose:
 *  Possibly commits the storage, then releases it reversing the
 *  reference count from Open.  If the reference on the storage
 *  goes to zero, the storage is forgotten.  However, the object we
 *  contain is still held and as long as it's active the storage
 *  remains alive.
 *
 * Parameters:
 *  fCommit         BOOL indicating if we're to commit.
 *
 * Return Value:
 *  None
 */

void tOleHandler::Close(BOOL fCommit)
    {
        /*
         * We can't use a zero reference count to know when to NULL
         * this since other things might have AddRef'd the storage.
         */
            //OnInPlaceDeactivate releases this pointer.
            if (NULL!=m_pIOleIPObject)
                m_pIOleIPObject->InPlaceDeactivate();

            //Close the object saving if necessary
            if (NULL!=m_pIOleObject)
                {
                m_pIOleObject->Close(OLECLOSE_SAVEIFDIRTY);
                ReleaseInterface(m_pIOleObject);
                }

            //Release all other held pointers
            //CHAPTER24MOD
            ReleaseInterface(m_pIOleControl);

            //End CHAPTER24MOD

            //Release all other held pointers
            if (NULL!=m_pIViewObject2)
                {
                m_pIViewObject2->SetAdvise(m_fe.dwAspect, 0, NULL);
                ReleaseInterface(m_pIViewObject2);
                }

            //We know we only hold one ref from Create or Load
            ReleaseInterface(m_pObj);

            if (NULL != m_pIStorage)
              ReleaseInterface(m_pIStorage);

    return;
    }


/*
 * tOleHandler::Activate
 *
 * Purpose:
 *  Activates a verb on the object living in the tenant.  Does
 *  nothing for static objects.
 *
 * Parameters:
 *  iVerb           LONG of the verb to execute.
 *  pMSG            LPMSG to the message causing the invocation.
 *
 * Return Value:
 *  BOOL            TRUE if the object changed due to this verb
 *                  execution.
 */

BOOL tOleHandler::Activate(LONG iVerb, LPMSG pMSG)
    {
    RECT        rc, rcH;
    SIZEL       szl;

    //Can't activate statics.
/*    if (TENANTTYPE_STATIC==m_tType || NULL==m_pIOleObject)
        {
        MessageBeep(0);
        return FALSE;
        }*/

    RECTFROMRECTL(rc, m_rcl);
    RectConvertMappings(&rc, NULL, TRUE);
    XformRectInPixelsToHimetric(NULL, &rc, &rcH);

    //Get the server running first, then do a SetExtent, then show it
    OleRun(m_pIOleObject);

    if (m_fSetExtent)
        {
        SETSIZEL(szl, rcH.right-rcH.left, rcH.top-rcH.bottom);
        m_pIOleObject->SetExtent(m_fe.dwAspect, &szl);
        m_fSetExtent=FALSE;
        }

    //CHAPTER24MOD
    /*
     * If we have a pending deactivation, but we're activating
     * again, clear the pending flag.
     */
    if (OLEIVERB_UIACTIVATE==iVerb
        || OLEIVERB_INPLACEACTIVATE==iVerb)
        m_fPendingDeactivate=FALSE;
    //End CHAPTER24MOD

    m_pIOleObject->DoVerb(iVerb, pMSG, m_pImpIOleClientSite, 0
        , m_hWnd, &rcH);

    //If object changes, IAdviseSink::OnViewChange will see it.
    return FALSE;
    }






/*
 * tOleHandler::ObjectGet
 *
 * Purpose:
 *  Retrieves the LPUNKNOWN of the object in use by this tenant
 *
 * Parameters:
 *  ppUnk           LPUNKNOWN * in which to return the object
 *                  pointer.
 *
 * Return Value:
 *  None
 */

void tOleHandler::ObjectGet(LPUNKNOWN *ppUnk)
    {
    if (NULL!=ppUnk)
        {
        *ppUnk=m_pObj;
        m_pObj->AddRef();
        }

    return;
    }





/*
 * tOleHandler::SizeGet
 * tOleHandler::SizeSet
 * tOleHandler::RectGet
 * tOleHandler::RectSet
 *
 * Purpose:
 *  Returns or sets the size/position of the object contained here.
 *
 * Parameters:
 *  pszl/prcl       LPSIZEL (Size) or LPRECTL (Rect) with the
 *                  extents of interest.  In Get situations,
 *                  this will receive the extents; in Set it
 *                  contains the extents.
 *  fDevice         BOOL indicating that pszl/prcl is expressed
 *                  in device units.  Otherwise it's LOMETRIC.
 *  fInformObj      (Set Only) BOOL indicating if we need to inform
 *                  the object all.
 *
 * Return Value:
 *  None
 */

void tOleHandler::SizeGet(LPSIZEL pszl, BOOL fDevice)
    {
    if (!fDevice)
        {
        pszl->cx=m_rcl.right-m_rcl.left;
        pszl->cy=m_rcl.bottom-m_rcl.top;
        }
    else
        {
        RECT        rc;

        SetRect(&rc, (int)(m_rcl.right-m_rcl.left)
            , (int)(m_rcl.bottom-m_rcl.top), 0, 0);

        RectConvertMappings(&rc, NULL, TRUE);

        pszl->cx=(long)rc.left;
        pszl->cy=(long)rc.top;
        }

    return;
    }


void tOleHandler::SizeSet(LPSIZEL pszl, BOOL fDevice, BOOL fInformObj)
    {
    SIZEL           szl;

    if (!fDevice)
        {
        szl=*pszl;
        m_rcl.right =pszl->cx+m_rcl.left;
        m_rcl.bottom=pszl->cy+m_rcl.top;
        }
    else
        {
        RECT        rc;

        SetRect(&rc, (int)pszl->cx, (int)pszl->cy, 0, 0);
        RectConvertMappings(&rc, NULL, FALSE);

        m_rcl.right =(long)rc.left+m_rcl.left;
        m_rcl.bottom=(long)rc.top+m_rcl.top;

        SETSIZEL(szl, (long)rc.left, (long)rc.top);
        }

    //Tell OLE that this object was resized.
    if (NULL!=m_pIOleObject && fInformObj)
        {
        HRESULT     hr;
        BOOL        fRun=FALSE;

        //Convert our LOMETRIC into HIMETRIC by *=10
        szl.cx*=10;
        szl.cy*=-10;    //Our size is stored negative.

        /*
         * If the MiscStatus bit of OLEMISC_RECOMPOSEONRESIZE
         * is set, then we need to run the object before calling
         * SetExtent to make sure it has a real chance to
         * re-render the object.  We have to update and close
         * the object as well after this happens.
         */

        if (OLEMISC_RECOMPOSEONRESIZE & m_grfMisc)
            {
            if (!OleIsRunning(m_pIOleObject))
                {
                OleRun(m_pIOleObject);
                fRun=TRUE;
                }
            }

        hr=m_pIOleObject->SetExtent(m_fe.dwAspect, &szl);

        /*
         * If the object is not running and it does not have
         * RECOMPOSEONRESIZE, then SetExtent fails.  Make
         * sure that we call SetExtent again (by just calling
         * SizeSet here again) when we next run the object.
         */
        if (SUCCEEDED(hr))
            {
            m_fSetExtent=FALSE;

            if (fRun)
                {
                m_pIOleObject->Update();
                m_pIOleObject->Close(OLECLOSE_SAVEIFDIRTY);
                }
            }
        else
            {
            if (OLE_E_NOTRUNNING==GetScode(hr))
                m_fSetExtent=TRUE;
            }
        }

    return;
    }


void tOleHandler::RectGet(LPRECTL prcl, BOOL fDevice)
    {
    if (!fDevice)
        *prcl=m_rcl;
    else
        {
        RECT        rc;

        RECTFROMRECTL(rc, m_rcl);
        RectConvertMappings(&rc, NULL, TRUE);
        RECTLFROMRECT(*prcl, rc);
        }

    return;
    }


void tOleHandler::RectSet(LPRECTL prcl, BOOL fDevice, BOOL fInformObj)
    {
    SIZEL   szl;
    LONG    cx, cy;

    /*
     * Prevent reentrant calls that may come from calling
     * UpdateInPlaceObjectRects here and elsewhere.
     */
    if (m_fInRectSet)
        return;

    m_fInRectSet=TRUE;

    cx=m_rcl.right-m_rcl.left;
    cy=m_rcl.bottom-m_rcl.top;

    if (!fDevice)
        m_rcl=*prcl;
    else
        {
        RECT        rc;

        RECTFROMRECTL(rc, *prcl);
        RectConvertMappings(&rc, NULL, FALSE);
        RECTLFROMRECT(m_rcl, rc);
        }

    /*
     * Tell ourselves that the size changed, if it did.  SizeSet
     * will call IOleObject::SetExtent for us.
     */
    if ((m_rcl.right-m_rcl.left)!=cx || (m_rcl.bottom-m_rcl.top)!=cy)
        {
        SETSIZEL(szl, m_rcl.right-m_rcl.left, m_rcl.bottom-m_rcl.top);
        SizeSet(&szl, FALSE, fInformObj);
        }

    //Tell an in-place active object it moved too
    UpdateInPlaceObjectRects(NULL, TRUE);
    m_fInRectSet=FALSE;
    return;
    }








/*
 * tOleHandler::DeactivateInPlaceObject
 *
 * Purpose:
 *  Deactivates an in-place object if there is one in this tenant.
 *
 * Parameters:
 *  fFull           BOOL indicating full deactivation of UI
 *                  deactivate only.
 *
 * Return Value:
 *  None
 */

void tOleHandler::DeactivateInPlaceObject(BOOL fFull)
    {
    if (NULL!=m_pIOleIPObject)
        {
        /*
         * Activate-when-visible objects only UI deactivate
         * unless we're fully deactivating on purpose.
         */
        if ((OLEMISC_ACTIVATEWHENVISIBLE & m_grfMisc) && !fFull)
            m_pIOleIPObject->UIDeactivate();
        else
            {
            //CHAPTER24MOD
            /*
             * Only deactivate when there's no locks.  If there
             * is a lock, then remember that we need to deactivate
             * when all the locks go away.
             */
            if (0==m_cLockInPlace)
                m_pIOleIPObject->InPlaceDeactivate();
            else
                m_fPendingDeactivate=TRUE;
            //End CHAPTER24MOD
            }
        }

    return;
    }



/*
 * tOleHandler::UpdateInPlaceObjectRects
 *
 * Purpose:
 *  Generates a call to IOleInPlaceObject::SetObjectRects to allow
 *  it to show it's shading and its object adornments properly.
 *  This function deals in HIMETRIC units.
 *
 * Parameters:
 *  prcPos          LPCRECT to the size the object wants.  Ignored
 *                  if NULL in which case we use the size of the
 *                  tenant.  This rect is in client coordinates of
 *                  the pages window.
 *  fUseTenantRect  BOOL indicating if we need to use the tenant
 *                  rectangle offset for scrolling regardless.
 *
 * Return Value:
 *  None
 */

void tOleHandler::UpdateInPlaceObjectRects(LPCRECT prcPos
    , BOOL fUseTenantRect)
    {
    RECTL       rcl;
    RECT        rc;
    RECT        rcClip;
    BOOL        fResizeTenant=TRUE;

    //We don't clip special anywhere in our window.
    SetRect(&rcClip, 0, 0, 32767, 32767);

    /*
     * Note that if the object here is activate-when-visible
     * we'll always have this pointer.
     */
    if (NULL!=m_pIOleIPObject)
        {
        /*
         * This uses the last position rectangle from
         * IOleInPlaceSite::OnPosRectChange if it's been
         * initialized
         */
        if (NULL==prcPos && -1!=m_rcPos.left && !fUseTenantRect)
            prcPos=&m_rcPos;

        //This code is normally called from OnPosRectChange direct.
        if (NULL!=prcPos && !fUseTenantRect)
            {
            rc=*prcPos;

            //Calculate the boundaries of the full page
            //m_pPG->CalcBoundingRect(&rcClip, FALSE);

            //Make sure we limit object to page boundaries.
            IntersectRect(&rc, &rc, &rcClip);
            }
        else
            {
            /*
             * We have no rectangle of the object on which to
             * base the position, so just use the tenant rectangle.
             * This code is also used when scrolling objects.
             */
            RectGet(&rcl, TRUE);
            RECTFROMRECTL(rc, rcl);

            //Account for scrolling
//            OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
            fResizeTenant=FALSE;
            }


        /*
         * NOTE:  The rectangles to SetObjectRects is in client
         * coordinates of the pages window.
         */
        if (NULL!=m_pIOleIPObject)
            m_pIOleIPObject->SetObjectRects(&rc, &rcClip);

        if (fResizeTenant)
            {
            //Need to tell the tenant to change position too
            RECTLFROMRECT(rcl, rc);
            RectSet(&rcl, TRUE, FALSE);
            }
        }

    return;
    }


/*
 * tOleHandler::ObjectWindow
 *
 * Purpose:
 *  Returns the window handle of the in-place object.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HWND            Handle of the object window.
 */

HWND tOleHandler::ObjectWindow(void)
    {
    HWND    hWnd=NULL;

    if (NULL!=m_pIOleIPObject)
        m_pIOleIPObject->GetWindow(&hWnd);

    return hWnd;
    }




/*
 * tOleHandler::ControlInitialize
 *
 * Purpose:
 *  Initializes the control if that's the type of object we have
 *  in the site.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  BOOL            TRUE if initialization worked, FALSE otherwise.
 */

BOOL tOleHandler::ControlInitialize(void)
    {
    HRESULT         hr;
    BOOL            fEvents;

    if (NULL==m_pObj)
        return FALSE;

    hr=m_pObj->QueryInterface(IID_IOleControl
        , (PPVOID)&m_pIOleControl);

    //Failure means not a control.
    if (FAILED(hr))
        return FALSE;

    m_ambientProp.setControl(m_pIOleControl);

    m_dwState |= TENANTSTATE_CONTROL;

    if (OLEMISC_ACTSLIKEBUTTON & m_grfMisc)
        m_dwState |= TENANTSTATE_BUTTON;

    //We don't use this, but might as well store it.
    if (OLEMISC_ACTSLIKELABEL & m_grfMisc)
        m_dwState |= TENANTSTATE_LABEL;

    /*
     * Call IOleControl::GetControlInfo to retrieve the keyboard
     * information for this control.  We have to reload this
     * information in IOleControlSite::OnControlInfoChanged.
     */
    /*m_fHaveControlInfo=SUCCEEDED(m_pIOleControl
        ->GetControlInfo(&m_ctrlInfo));*/ //!!!


    /*
     * If you wanted to receive IPropertyNotifySink notifications
     * for a control, establish that advisory connection here
     * through the object's IConnectionPointContainer and
     * IConnectionPoint.
     */

    return TRUE;
    }



/*
 * tOleHandler::GetControlFlags
 *
 * Purpose:
 *  Requests flags describing the control inside this tenant
 *  if there is, in fact a control.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  DWORD           Flags describing the control from the
 *                  TENANT
 */

DWORD tOleHandler::GetControlFlags(void)
    {
    return m_dwState & STATEMASK_CONTROLS;
    }





/*
 * tOleHandler::TryMnemonic
 *
 * Purpose:
 *  Asks the tenant to check the given keyboard message against
 *  one that its control might want, passing it to
 *  IOleControl::OnMnemonic if there is a match.
 *
 * Parameters:
 *  pMsg            LPMSG containing the message to check.
 *
 * Return Value:
 *  BOOL            TRUE if the mnemonic was a match,
 *                  FALSE otherwise.
 */

BOOL tOleHandler::TryMnemonic(LPMSG pMsg)
    {
    UINT        i;
    BOOL        fRet=FALSE;
    LPACCEL     pACC;
    BYTE        fVirt=FVIRTKEY;

    if (!m_fHaveControlInfo)    //False for non-controls
        return FALSE;

    if (0==m_ctrlInfo.cAccel)
        return FALSE;

    pACC=(LPACCEL)GlobalLock(m_ctrlInfo.hAccel);

    if (NULL==pACC)
        return FALSE;

    /*
     * We'll come here on WM_KEYDOWN messages and WM_SYSKEYDOWN
     * messages.  The control's accelerator table will contain
     * entries that each have the desired key and the various
     * modifier flags.  We the create the current modifier flags
     * then look for entries that match those flags and the key
     * that is in the message itself.
     */

    fVirt |= (WM_SYSKEYDOWN==pMsg->message) ? FALT : 0;

    //GetKeyState works on the last message
    fVirt |= (0x8000 & GetKeyState(VK_CONTROL)) ? FCONTROL : 0;
    fVirt |= (0x8000 & GetKeyState(VK_SHIFT)) ? FSHIFT : 0;

    for (i=0; i < m_ctrlInfo.cAccel; i++)
        {
        if (pACC[i].key==pMsg->wParam && pACC[i].fVirt==fVirt)
            {
            m_pIOleControl->OnMnemonic(pMsg);
            fRet=TRUE;
            break;
            }
        }

    GlobalUnlock(m_ctrlInfo.hAccel);
    return fRet;
    }





/*
 * tOleHandler::AmbientChange
 *
 * Purpose:
 *  Notifes a control that an ambient property has changed in
 *  the control site.
 *
 * Parameters:
 *  dispID          DISPID of the property that changed.
 *
 * Return Value:
 *  None
 */

void tOleHandler::AmbientChange(DISPID dispID)
    {
    if (NULL!=m_pIOleControl)
        m_pIOleControl->OnAmbientPropertyChange(dispID);

    return;
    }

//End CHAPTER24MOD

void tOleHandler::OnShow()
{
  // Se objeto ja' tive sido ativado, ignora chamada
  // Alguns controles reagem mal quando ativados
  // mais de uma vez
  if(m_pIOleIPObject != NULL)
    return;

  if ((OLEMISC_ACTIVATEWHENVISIBLE & m_grfMisc))
    Activate(OLEIVERB_INPLACEACTIVATE, NULL);
}


void tOleHandler::GetNaturalSize(long *pWidth, long *pHeight)
{
  assert(pWidth && pHeight);
  if(!pWidth || !pHeight)
    return;

  *pWidth = natural_width;
  *pHeight = natural_height;
}

/*
 * CalcNaturalSize
 * Obtem o tamanho desejado pelo objeto
 */

void tOleHandler::CalcNaturalSize()
{
  HRESULT hr;
  SIZEL sizel;
  RECTL rcl;

  assert(m_pIViewObject2 != NULL);

  if(!m_pIViewObject2)
    return;

  hr = m_pIViewObject2->GetExtent(m_fe.dwAspect, -1, NULL, &sizel);

  if(FAILED(hr))
    return;

  SETRECTL(rcl, 0, 0, sizel.cx/10, -sizel.cy/10);
  RectSet(&rcl, FALSE, TRUE);

  // Obtem medidas ja' convertidas para pixels
  SizeGet(&sizel, TRUE);

  natural_width = sizel.cx;
  natural_height = sizel.cy;
}

