📄 tenant.cpp
字号:
/*
* TENANT.CPP
* Patron Chapter 12
*
* Implementation of the CTentant class which holds information
* for a single object on a page. It maintains position, references
* to data, and a storage.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "patron.h"
/*
* CTenant::CTenant
* CTenant::~CTenant
*
* Constructor Parameters:
* dwID DWORD identifier for this page.
* hWnd HWND of the pages window.
* pPG PCPages to the parent structure.
*/
CTenant::CTenant(DWORD dwID, HWND hWnd, PCPages pPG)
{
m_hWnd=hWnd;
m_dwID=dwID;
m_fInitialized=0;
m_pIStorage=NULL;
m_cOpens=0;
m_pObj=NULL;
m_pPG =pPG;
m_clsID=CLSID_NULL;
m_fSetExtent=FALSE;
return;
}
CTenant::~CTenant(void)
{
if (NULL!=m_pObj)
{
//We know we only hold one reference from Create or Load
m_pObj->Release();
m_pObj=NULL;
}
return;
}
/*
* CTenant::GetID
*
* Return Value:
* DWORD dwID field in this tenant.
*/
DWORD CTenant::GetID(void)
{
return m_dwID;
}
/*
* CTenant::GetStorageName
*
* Parameters:
* pszName LPOLESTR to a buffer in which to store the storage
* name for this tenant.
*
* Return Value:
* UINT Number of characters stored.
*/
UINT CTenant::GetStorageName(LPOLESTR pszName)
{
#ifdef WIN32ANSI
char szTemp[32];
UINT cch;
cch=wsprintf(szTemp, "Tenant %lu", m_dwID);
MultiByteToWideChar(CP_ACP, 0, szTemp, -1, pszName, 32);
return cch;
#else
return wsprintf(pszName, TEXT("Tenant %lu"), m_dwID);
#endif
}
/*
* CTenant::Create
*
* Purpose:
* Creates a new tenant of the given CLSID, which can be either a
* static bitmap or metafile now (Chapter 12) and which may
* eventually be 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 CTenant::Create(TENANTTYPE tType, LPVOID pvType
, LPFORMATETC pFE, PPOINTL pptl, LPSIZEL pszl
, LPSTORAGE pIStorage, PPATRONOBJECT ppo, DWORD dwData)
{
HRESULT hr;
LPUNKNOWN pObj;
LPVIEWOBJECT2 pIViewObject2;
LPOLEOBJECT pIOleObject;
UINT uRet=CREATE_GRAPHICONLY;
if (NULL==pvType || NULL==pIStorage)
return CREATE_FAILED;
//Fail if this is called for an already living tenant.
if (m_fInitialized)
return CREATE_FAILED;
m_fInitialized=TRUE;
//Create a new storage for this tenant.
if (!Open(pIStorage))
return CREATE_FAILED;
/*
* Get the placement info if it's here. We either have a non-
* NULL PPATRONOBJECT in ppo or we have to use default
* placement and retrieve the size from the object itself.
*/
pszl->cx=0;
pszl->cy=0;
if (NULL!=ppo)
{
*pFE=ppo->fe;
*pptl=ppo->ptl;
*pszl=ppo->szl; //Could be 0,0 , so we ask object
uRet=CREATE_PLACEDOBJECT;
}
hr=ResultFromScode(E_FAIL);
//Now create an object based specifically for the type.
switch (tType)
{
case TENANTTYPE_NULL:
break;
case TENANTTYPE_STATIC:
/*
* We could use OleCreateStaticFromData here which does
* pretty much what we're doing below. However, it does
* not allow us to control whether we paste a bitmap or
* a metafile--it uses metafile first, bitmap second.
* For this reason we'll use code developed in Chapter
* 11's FreeLoader to affect the paste.
*/
hr=CreateStatic((LPDATAOBJECT)pvType, pFE, &pObj);
break;
default:
break;
}
//If creation didn't work, get rid of the element Open created.
if (FAILED(hr))
{
Destroy(pIStorage);
return CREATE_FAILED;
}
//Otherwise, store the object pointer and initialize the tenant
m_pObj=pObj;
m_fe=*pFE;
m_fe.ptd=NULL;
m_dwState=TENANTSTATE_DEFAULT;
//If we also saw PatronObjects on the clipboard, we have size
if (0==pszl->cx && 0==pszl->cy)
{
SIZEL szl;
//Try to get the real size of the object, default to 2"*2"
SETSIZEL((*pszl), 2*LOMETRIC_PER_INCH, 2*LOMETRIC_PER_INCH);
//Try IViewObject2 first, then IOleObject as a backup.
hr=pObj->QueryInterface(IID_IViewObject2
, (PPVOID)&pIViewObject2);
if (SUCCEEDED(hr))
{
pIViewObject2->GetExtent(m_fe.dwAspect, -1, NULL, &szl);
pIViewObject2->Release();
}
else
{
hr=pObj->QueryInterface(IID_IOleObject
, (PPVOID)&pIOleObject);
if (SUCCEEDED(hr))
{
pIOleObject->GetExtent(m_fe.dwAspect, &szl);
pIOleObject->Release();
}
}
if (SUCCEEDED(hr))
{
//Convert HIMETRIC to our LOMETRIC mapping
SETSIZEL((*pszl), szl.cx/10, szl.cy/10);
}
}
return uRet;
}
/*
* CTenant::Load
*
* Purpose:
* Recreates the object living in this tenant in place of calling
* FCreate. This is used in loading as opposed to new creation.
*
* Parameters:
* pIStorage LPSTORAGE of the page we live in.
* pti PTENTANTINFO containing persistent information.
* The ID value in this structure is ignored.
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CTenant::Load(LPSTORAGE pIStorage, PTENANTINFO pti)
{
HRESULT hr;
LPUNKNOWN pObj;
if (NULL==pIStorage || NULL==pti)
return FALSE;
//Fail if this is called for an already living tenant.
if (m_fInitialized)
return FALSE;
m_fInitialized=TRUE;
//Open the storage for this tenant.
if (!Open(pIStorage))
return FALSE;
hr=OleLoad(m_pIStorage, IID_IUnknown, NULL, (PPVOID)&pObj);
if (FAILED(hr))
{
Destroy(pIStorage);
return FALSE;
}
//Otherwise, store the object pointer and initialize the tenant
m_pObj=pObj;
m_fe=pti->fe;
m_fe.ptd=NULL;
m_fSetExtent=pti->fSetExtent;
m_dwState=TENANTSTATE_DEFAULT;
RectSet(&pti->rcl, FALSE);
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::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++;
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;
}
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);
if (FAILED(OleSave(pIPS, m_pIStorage, TRUE)))
{
//This is essentially what OleSave does.
WriteClassStg(m_pIStorage, m_clsID);
pIPS->Save(m_pIStorage, TRUE);
}
pIPS->SaveCompleted(NULL);
pIPS->Release();
m_pIStorage->Commit(STGC_ONLYIFCURRENT);
}
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.
* Nothing is committed when being destroyed.
*
* Parameters:
* pIStorage LPSTORAGE contianing this page on which to call
* DestroyElement
*
* Return Value:
* None
*/
void CTenant::Destroy(LPSTORAGE pIStorage)
{
OLECHAR szTemp[32];
if (NULL!=pIStorage)
{
if (NULL!=m_pIStorage)
{
//Remove all reference/open counts on this storage.
while (0!=m_cOpens)
{
m_pIStorage->Release();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -