SITE.CPP
/* 
 * SITE.CPP 
 * Document Object Site Object 
 * 
 * Copyright (c)1995-1997 Microsoft Corporation, All Rights Reserved 
 */ 
 
 
#include "framer.h" 
 
 
/* 
 * CSite::CSite 
 * CSite::~CSite 
 * 
 * Constructor Parameters: 
 *  dwID            DWORD identifer for this site. 
 *  hWnd            HWND of the window associated with the site 
 *  pFR             PCFrame to the parent structure. 
 */ 
 
CSite::CSite(DWORD dwID, HWND hWnd, PCFrame pFR) 
    { 
    m_cRef=0; 
    m_dwID=dwID; 
    m_hWnd=hWnd; 
    m_pFR=pFR; 
 
    m_fInitialized=0; 
    m_pIStorage=NULL; 
 
    m_pObj=NULL; 
     
    m_pIOleObject=NULL; 
    m_pIOleIPObject=NULL; 
    m_pIOleDocView=NULL; 
 
    m_pImpIOleClientSite=NULL; 
    m_pImpIAdviseSink=NULL; 
    m_pImpIOleIPSite=NULL; 
    m_pImpIOleDocumentSite=NULL; 
 
    m_fDocObj=FALSE; 
    return; 
    } 
 
 
CSite::~CSite(void) 
    { 
    //Object pointers cleaned up in Close. 
 
    //We delete our own interfaces since we control them 
    DeleteInterfaceImp(m_pImpIOleDocumentSite); 
    DeleteInterfaceImp(m_pImpIOleIPSite); 
    DeleteInterfaceImp(m_pImpIAdviseSink); 
    DeleteInterfaceImp(m_pImpIOleClientSite); 
    return; 
    } 
 
 
 
 
/* 
 * CSite::QueryInterface 
 * CSite::AddRef 
 * CSite::Release 
 * 
 * Purpose: 
 *  IUnknown members for CSite object. 
 */ 
 
STDMETHODIMP CSite::QueryInterface(REFIID riid, void **ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid) 
        *ppv=this; 
 
    if (IID_IOleClientSite==riid) 
        *ppv=m_pImpIOleClientSite; 
 
    if (IID_IAdviseSink==riid) 
        *ppv=m_pImpIAdviseSink; 
 
    if (IID_IOleWindow==riid || IID_IOleInPlaceSite==riid) 
        *ppv=m_pImpIOleIPSite; 
 
    if (IID_IOleDocumentSite==riid) 
        *ppv=m_pImpIOleDocumentSite; 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CSite::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
STDMETHODIMP_(ULONG) CSite::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    delete this; 
    return 0; 
    } 
 
 
 
 
 
 
/* 
 * CSite::Create 
 * 
 * Purpose: 
 *  Asks the site to instantiate an object given a filename. 
 *  This goes through OleCreateFromFile and will either create 
 *  an embedded object or a package (embedded) object.  When 
 *  activated, this will either launch the app and activate 
 *  as a DocObject, launch the app and open the file, or fail 
 *  because no app can open the file. 
 * 
 * Parameters: 
 *  pszFile         LPTSTR of the file from which to create the object. 
 *  pIStorage       IStorage * of the parent storage in which we're 
 *                  to create an IStorage for the new object. 
 *  dwID            DWORD identifier for this site. 
 * 
 * Return Value: 
 *  BOOL            Result of the creation. 
 */ 
 
BOOL CSite::Create(LPTSTR pszFile, IStorage *pIStorage) 
    { 
    HRESULT             hr=E_FAIL; 
    LPUNKNOWN           pObj; 
 
    //Create a new storage for this object (sets m_pIStorage) 
    if (!CreateStorage(pIStorage)) 
        return FALSE; 
 
    //Now create an object from the file 
   #ifdef UNICODE     
    hr=OleCreateFromFile(CLSID_NULL, pszFile, IID_IUnknown 
        , OLERENDER_NONE, NULL, NULL, m_pIStorage, (void **)&pObj); 
   #else 
    OLECHAR     szFile[512];    //Assumption on string length 
 
    MultiByteToWideChar(CP_ACP, 0, pszFile, -1, szFile, 512);     
hr=OleCreateFromFile(CLSID_NULL, szFile, IID_IUnknown 
        , OLERENDER_NONE, NULL, NULL, m_pIStorage, (void **)&pObj); 
   #endif 
 
    //If creation didn't work, get rid of the element Open created. 
    if (FAILED(hr)) 
        { 
        Destroy(pIStorage); 
        return FALSE; 
        } 
 
    //We don't get the size if PatronObject data was seen already. 
    if (!ObjectInitialize(pObj)) 
        { 
        Destroy(pIStorage); 
        return FALSE; 
        } 
 
    m_fInitialized=TRUE; 
    return TRUE; 
    } 
 
 
 
 
 
 
/* 
 * CSite::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 CSite::ObjectInitialize(LPUNKNOWN pObj) 
    { 
    HRESULT         hr; 
    DWORD           dw; 
 
    if (NULL==pObj) 
        return FALSE; 
 
    m_pObj=pObj; 
 
    //We need an IOleObject most of the time, so get one here. 
    m_pIOleObject=NULL; 
    hr=pObj->QueryInterface(IID_IOleObject, (void **)&m_pIOleObject);          
 
    /* 
     * Follow up object creation with advises and so forth.  If 
     * we cannot get IOleObject here, then we know we can't do 
     * any IOleObject actions from here on--object is static. 
     */ 
    if (FAILED(hr)) 
        return TRUE; 
 
    //SetClientSite is critical for DocObjects 
    m_pIOleObject->SetClientSite(m_pImpIOleClientSite); 
    m_pIOleObject->Advise(m_pImpIAdviseSink, &dw); 
 
//This is to give PowerPoint a chance to initialize itself earlier 
OleRun(m_pIOleObject); 
    return TRUE; 
    } 
 
 
 
 
/* 
 * CSite::CreateStorage 
 * 
 * Purpose: 
 *  Creates an sub-storage within a given parent storage, 
 *  setting m_pIStorage. 
 * 
 * Parameters: 
 *  pIStorage       IStorage * of the parent storage 
 * 
 * Return Value: 
 *  BOOL            TRUE if creation succeeds, FALSE otherwise. 
 */ 
 
BOOL CSite::CreateStorage(IStorage *pIStorage) 
    { 
    HRESULT     hr; 
    DWORD       dwMode=STGM_TRANSACTED | STGM_READWRITE 
                    | STGM_SHARE_EXCLUSIVE; 
    TCHAR       szName[32]; 
 
    if (NULL==pIStorage) 
        return FALSE; 
 
    /* 
     * Attempt to open the storage under this ID.  If there is 
     * none, then create it.  In either case we end up with an 
     * IStorage that we either save in pPage or release. 
     */ 
    wsprintf(szName, TEXT("Site %lu"), m_dwID); 
 
   #ifdef UNICODE 
    hr=pIStorage->CreateStorage(szName, dwMode, 0, 0, &m_pIStorage); 
   #else 
    OLECHAR  szwName[32]; 
MultiByteToWideChar(CP_ACP, 0, szName, -1, szwName, 32);     
    hr=pIStorage->CreateStorage(szwName, dwMode, 0, 0, &m_pIStorage); 
   #endif 
 
    if (FAILED(hr)) 
        return FALSE; 
 
//Create stream for the object; name is irrelevant 
dwMode=STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE; 
   #ifdef UNICODE 
    hr=m_pIStorage->CreateStream(TEXT("\003DocObjInfo"), dwMode, 0, 0 
        , &m_pIStream); 
   #else     
MultiByteToWideChar(CP_ACP, 0, "\003DocObjInfo", -1, szwName, 32);     
    hr=m_pIStorage->CreateStream(szwName, dwMode, 0, 0, &m_pIStream); 
   #endif 
    
    //If we failed to create a stream in the file, do it in memory 
if (FAILED(hr)) 
{ 
if (FAILED(CreateStreamOnHGlobal(NULL, TRUE, &m_pIStream))) 
    return FALSE; 
} 
 
    //Create interface implementations 
    m_pImpIOleClientSite=new CImpIOleClientSite(this, this); 
    m_pImpIAdviseSink=new CImpIAdviseSink(this, this); 
    m_pImpIOleIPSite=new CImpIOleInPlaceSite(this, this); 
    m_pImpIOleDocumentSite=new CImpIOleDocumentSite(this, this); 
 
    if (NULL==m_pImpIOleClientSite || NULL==m_pImpIAdviseSink 
        || NULL==m_pImpIOleIPSite || NULL==m_pImpIOleDocumentSite) 
        return FALSE; 
 
    return TRUE; 
    } 
 
 
 
 
/* 
 * CSite::Close 
 * 
 * Purpose: 
 *  Possibly commits the storage, then releases it, afterwards 
 *  frees alls the object pointers. 
 * 
 * Parameters: 
 *  fCommit         BOOL indicating if we're to commit. 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CSite::Close(BOOL fCommit) 
    { 
    //OnInPlaceDeactivate releases this pointer. 
    if (NULL!=m_pIOleIPObject) 
        m_pIOleIPObject->InPlaceDeactivate(); 
 
    ReleaseInterface(m_pIOleDocView); 
 
    if (NULL!=m_pIOleObject) 
        { 
        m_pIOleObject->Close(fCommit 
            ? OLECLOSE_SAVEIFDIRTY : OLECLOSE_NOSAVE); 
        ReleaseInterface(m_pIOleObject); 
        } 
 
    ReleaseInterface(m_pObj); 
ReleaseInterface(m_pIStream); 
    ReleaseInterface(m_pIStorage); 
 
    return; 
    } 
 
 
 
 
/* 
 * CSite::Update 
 * 
 * Purpose: 
 *  Forces a commit on the object's storage 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CSite::Update(void) 
    { 
    LPPERSISTSTORAGE    pIPS; 
 
    if (NULL!=m_pIStorage) 
        return; 
 
    m_pObj->QueryInterface(IID_IPersistStorage, (void **)&pIPS); 
    OleSave(pIPS, m_pIStorage, TRUE); 
    pIPS->SaveCompleted(NULL); 
    pIPS->Release(); 
 
    m_pIStorage->Commit(STGC_DEFAULT); 
    return; 
    } 
 
 
 
 
 
/* 
 * CSite::Destroy 
 * 
 * Purpose: 
 *  Removes this storage from the parent storage.  The caller should 
 *  eventually delete this CSite object to free the object herein. 
 *  Nothing is committed when being destroyed. 
 * 
 * Parameters: 
 *  pIStorage       IStorage * of the parent 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CSite::Destroy(IStorage *pIStorage) 
    { 
    TCHAR     szName[32]; 
 
    if (NULL==pIStorage) 
        return; 
 
    if (NULL!=m_pObj) 
        Close(FALSE); 
     
wsprintf(szName, TEXT("Site %lu"), m_dwID); 
   #ifdef UNICODE 
    pIStorage->DestroyElement(szName); 
   #else 
    OLECHAR  szwName[32]; 
MultiByteToWideChar(CP_ACP, 0, szName, -1, szwName, 512);     
pIStorage->DestroyElement(szwName);     
   #endif 
    return; 
    } 
 
 
 
 
 
/* 
 * CSite::Activate 
 * 
 * Purpose: 
 *  Activates a verb on the object living in the site. 
 * 
 * Parameters: 
 *  iVerb           LONG of the verb to execute. 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CSite::Activate(LONG iVerb) 
    { 
    CHourglass *pHour; 
    RECT        rc; 
             
    pHour=new CHourglass; 
 
    GetClientRect(m_hWnd, &rc); 
    m_pIOleObject->DoVerb(iVerb, NULL, m_pImpIOleClientSite, 0 
        , m_hWnd, &rc); 
 
    delete pHour; 
    return; 
    } 
 
 
 
 
/* 
 * CSite::UpdateObjectRects 
 * 
 * Purpose: 
 *  Informs the site that the client area window was resized and 
 *  that the site needs to also tell the DocObject of the resize. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CSite::UpdateObjectRects(void) 
    { 
    RECT    rc; 
 
    if (NULL==m_pIOleDocView) 
        return; 
 
    GetClientRect(m_hWnd, &rc); 
    m_pIOleDocView->SetRect(&rc); 
    return; 
    }