📄 tenant.cpp
字号:
* the running source via IOleLink::BindIfRunning. Since
* we do not pass m_pImpIOleClientSite here, we'll call
* BindIfRunning ourselves in ObjectInitialize.
*/
//CHAPTER24MOD
/*
* As with creation, OleLoad doesn't work with anything
* other than storage-based objects, and doesn't pay
* attention to OLEMISC_SETCLIENTSITEFIRST. For
* simplicity, this sample only works with storage-based
* controls.
*/
//End CHAPTER24MOD
hr=OleLoad(m_pIStorage, IID_IUnknown, NULL, (PPVOID)&pObj);
if (FAILED(hr))
{
Destroy(pIStorage);
return FALSE;
}
m_fSetExtent=pti->fSetExtent;
ObjectInitialize(pObj, &pti->fe, NULL);
//Restore the original state before reloading.
//CHAPTER24MOD
m_dwState=(m_dwState & STATEMASK_CONTROLS) | dwState;
//End CHAPTER24MOD
RectSet(&pti->rcl, FALSE, FALSE);
/*
* If the object is ActiveWhenVisible, send it the
* OLEIVERB_INPLACEACTIVATE verb now unless we're
* in design mode, then don't send at all.
*/
//CHAPTER24MOD
if ((OLEMISC_ACTIVATEWHENVISIBLE & m_grfMisc) && !m_fDesignMode)
Activate(OLEIVERB_INPLACEACTIVATE, NULL);
//End CHAPTER24MOD
return TRUE;
}
/*
* CTenant::GetInfo
*
* Purpose:
* Retrieved a TENANTINFO structure for this tenant.
*
* Parameters:
* pti PTENANTINFO structure to fill
*
* Return Value:
* None
*/
void CTenant::GetInfo(PTENANTINFO pti)
{
if (NULL!=pti)
{
pti->dwID=m_dwID;
pti->rcl=m_rcl;
pti->fe=m_fe;
pti->fSetExtent=m_fSetExtent;
}
return;
}
/*
* CTenant::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 CTenant::ObjectInitialize(LPUNKNOWN pObj, LPFORMATETC pFE
, DWORD dwData)
{
HRESULT hr;
LPPERSIST pIPersist=NULL;
DWORD dw;
PCDocument pDoc;
TCHAR szFile[CCHPATHMAX];
LPOLELINK pIOleLink=NULL;
if (NULL==pObj || NULL==pFE)
return FALSE;
m_pObj=pObj;
m_fe=*pFE;
m_fe.ptd=NULL;
m_dwState=TENANTSTATE_DEFAULT;
/*
* Determine the type: Static or Embedded. If Static,
* this will have CLSID_Picture_Metafile or CLSID_Picture_Dib.
* Otherwise it's embedded. Later we'll add a case for links.
*/
m_tType=TENANTTYPE_EMBEDDEDOBJECT;
if (SUCCEEDED(pObj->QueryInterface(IID_IPersist
, (PPVOID)&pIPersist)))
{
CLSID clsid=CLSID_NULL;
hr=pIPersist->GetClassID(&clsid);
//If we don't have a CLSID, default to static
if (FAILED(hr) || CLSID_Picture_Metafile==clsid
|| CLSID_Picture_Dib==clsid)
m_tType=TENANTTYPE_STATIC;
pIPersist->Release();
}
//Check if this is a linked object.
if (SUCCEEDED(pObj->QueryInterface(IID_IOleLink
, (PPVOID)&pIOleLink)))
{
LPMONIKER pmk;
hr=pIOleLink->GetSourceMoniker(&pmk);
if (FAILED(hr) || NULL==pmk)
m_tType=TENANTTYPE_STATIC;
else
{
m_tType=TENANTTYPE_LINKEDOBJECT;
pmk->Release();
//Connect to the object if the source is running.
pIOleLink->BindIfRunning();
}
pIOleLink->Release();
}
m_pIViewObject2=NULL;
hr=pObj->QueryInterface(IID_IViewObject2
, (PPVOID)&m_pIViewObject2);
if (FAILED(hr))
return FALSE;
m_pIViewObject2->SetAdvise(m_fe.dwAspect, 0, m_pImpIAdviseSink);
//We need an IOleObject most of the time, so get one here.
m_pIOleObject=NULL;
hr=pObj->QueryInterface(IID_IOleObject
, (PPVOID)&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;
/*
* 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
if (OLEMISC_ONLYICONIC & m_grfMisc)
m_fe.dwAspect=DVASPECT_ICON;
/*
* We could pass m_pImpIOleClientSite in an OleCreate* call, but
* since this function could be called after OleLoad, we still
* need to do this here, so it's always done here...
*/
m_pIOleObject->SetClientSite(m_pImpIOleClientSite);
m_pIOleObject->Advise(m_pImpIAdviseSink, &dw);
OleSetContainedObject(m_pIOleObject, TRUE);
/*
* For IOleObject::SetHostNames we need the application name
* and the document name (which is passed in the object
* parameter). The design of Patron doesn't give us nice
* structured access to the name of the document we're in, so
* I grab the parent of the Pages window (the document) and
* send it DOCM_PDOCUMENT which returns us the pointer.
* Roundabout, but it works.
*/
pDoc=(PCDocument)SendMessage(GetParent(m_hWnd), DOCM_PDOCUMENT
, 0, 0L);
if (NULL!=pDoc)
pDoc->FilenameGet(szFile, CCHPATHMAX);
else
szFile[0]=0;
NotifyOfRename(szFile, NULL, NULL);
/*
* If we're creating an iconic aspect object and we have
* an object from the Insert Object dialog, then we need to
* store that iconic presentation in the cache, handled
* with the utility function INOLE_SwitchDisplayAspect. In
* this case dwData is a handle to the metafile containing
* the icon. If dwData is NULL then we depend on the
* server to provide the aspect, in which case we need
* a view advise.
*/
if (DVASPECT_ICON & m_fe.dwAspect)
{
DWORD dw=DVASPECT_CONTENT;
IAdviseSink *pSink;
pSink=(NULL==dwData) ? NULL : m_pImpIAdviseSink;
INOLE_SwitchDisplayAspect(m_pIOleObject, &dw
, DVASPECT_ICON, (HGLOBAL)(UINT)dwData, FALSE
, (NULL!=dwData), pSink, NULL);
}
//CHAPTER24MOD
//Go try initializing control-related things.
ControlInitialize();
//End CHAPTER24MOD
return TRUE;
}
/*
* CTenant::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 CTenant::Open(LPSTORAGE pIStorage)
{
HRESULT hr=NOERROR;
DWORD dwMode=STGM_TRANSACTED | STGM_READWRITE
| STGM_SHARE_EXCLUSIVE;
OLECHAR szTemp[32];
if (NULL==m_pIStorage)
{
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.
*/
GetStorageName(szTemp);
hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0
, &m_pIStorage);
if (FAILED(hr))
{
hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0
, &m_pIStorage);
}
}
else
m_pIStorage->AddRef();
if (FAILED(hr))
return FALSE;
m_cOpens++;
//Create these if we don't have them already.
if (NULL==m_pImpIOleClientSite && NULL==m_pImpIAdviseSink)
{
m_pImpIOleClientSite=new CImpIOleClientSite(this, this);
m_pImpIAdviseSink=new CImpIAdviseSink(this, this);
m_pImpIOleIPSite=new CImpIOleInPlaceSite(this, this);
//CHAPTER24MOD
m_pImpIOleControlSite=new CImpIOleControlSite(this, this);
m_pImpIDispatch=new CImpIDispatch(this, this);
if (NULL==m_pImpIOleClientSite || NULL==m_pImpIAdviseSink
|| NULL==m_pImpIOleIPSite || NULL==m_pImpIOleControlSite
|| NULL==m_pImpIDispatch)
return FALSE;
//End CHAPTER24MOD
}
return TRUE;
}
/*
* CTenant::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 CTenant::Close(BOOL fCommit)
{
if (fCommit)
Update();
if (NULL!=m_pIStorage)
{
m_pIStorage->Release();
/*
* We can't use a zero reference count to know when to NULL
* this since other things might have AddRef'd the storage.
*/
if (0==--m_cOpens)
{
m_pIStorage=NULL;
//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);
ReleaseInterface(m_pIDispatchControl);
if (0!=m_dwConnEvents)
{
InterfaceDisconnect(m_pObj, m_iidEvents
, &m_dwConnEvents);
}
//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);
}
}
return;
}
/*
* CTenant::Update
*
* Purpose:
* Forces a common on the page if it's open.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if the object is open, FALSE otherwise.
*/
BOOL CTenant::Update(void)
{
LPPERSISTSTORAGE pIPS;
if (NULL!=m_pIStorage)
{
/*
* We need to OleSave again because we might have changed
* the size or position of this tenant. We also need to
* save the rectangle on the page, since that's not known
* to OLE.
*/
m_pObj->QueryInterface(IID_IPersistStorage, (PPVOID)&pIPS);
//CHAPTER24MOD
/*
* Some controls may not implement IPersistStorage, using
* IPersistStream[Init] instead. In that case, the
* QueryInterface above will fail, and we then have to
* create a stream ourselves in m_pIStorage in which to
* serialize the object through IPersistStream. This
* sample doesn't support stream-only objects at this time.
*/
//End CHAPTER24MOD
//This fails for static objects...so we improvise if so
if (FAILED(OleSave(pIPS, m_pIStorage, TRUE)))
{
//This is essentially what OleSave does.
WriteClassStg(m_pIStorage, m_clsID);
pIPS->Save(m_pIStorage, TRUE);
}
//CHAPTER24MOD
/*
* If this is a control, then we also need to serialize
* our events list. We do this into a stream called
* "\x03Events Mapping" the presence of which is used in
* ControlInitialize to initialize the events map. Note
* that since we're writing a container stream into the
* object's IStorage then we have to use the ASCII 3 prefix.
*/
if (TENANTSTATE_EVENTS & m_dwState)
{
LPSTREAM pIStream;
HRESULT hr;
hr=m_pIStorage->CreateStream(SZEVENTSSTREAM
, STGM_CREATE | STGM_DIRECT | STGM_READWRITE
| STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream);
if (SUCCEEDED(hr));
{
m_pEventMap->Serialize(pIStream);
pIStream->Release();
}
}
//End CHAPTER24MOD
pIPS->SaveCompleted(NULL);
pIPS->Release();
m_pIStorage->Commit(STGC_DEFAULT);
}
return FALSE;
}
/*
* CTenant::Destroy
*
* Purpose:
* Removes this page from the given storage. The caller should
* eventually delete this CTenant object to free the object herein.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -