448 lines
14 KiB
C++
448 lines
14 KiB
C++
#include "privcpp.h"
|
|
|
|
// Constructor
|
|
CPackage_IPersistStorage::CPackage_IPersistStorage(CPackage *pPackage) :
|
|
_pPackage(pPackage)
|
|
{
|
|
ASSERT(_cRef == 0);
|
|
ASSERT(_psState == PSSTATE_UNINIT);
|
|
}
|
|
|
|
CPackage_IPersistStorage::~CPackage_IPersistStorage()
|
|
{
|
|
DebugMsg(DM_TRACE,"CPackage_IPersistStorage destroyed with ref count %d",_cRef);
|
|
}
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IUnknown Methods...
|
|
//
|
|
HRESULT CPackage_IPersistStorage::QueryInterface(REFIID iid, void ** ppv)
|
|
{
|
|
return _pPackage->QueryInterface(iid,ppv); // delegate to CPackage
|
|
}
|
|
|
|
ULONG CPackage_IPersistStorage::AddRef(void)
|
|
{
|
|
_cRef++; // interface ref count for debug
|
|
return _pPackage->AddRef(); // delegate to CPackage
|
|
}
|
|
|
|
ULONG CPackage_IPersistStorage::Release(void)
|
|
{
|
|
_cRef--; // interface ref count for debug
|
|
return _pPackage->Release(); // delegate to CPackage
|
|
}
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IPersistStorage Methods...
|
|
//
|
|
HRESULT CPackage_IPersistStorage::GetClassID(LPCLSID pClassID)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack ps - GetClassID() called.");
|
|
|
|
if (_psState == PSSTATE_UNINIT)
|
|
return E_UNEXPECTED;
|
|
|
|
if (pClassID == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*pClassID = CLSID_CPackage;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CPackage_IPersistStorage::IsDirty(void)
|
|
{
|
|
DebugMsg(DM_TRACE,
|
|
"pack ps - IsDirty() called. _fIsDirty==%d",
|
|
(INT)_pPackage->_fIsDirty);
|
|
if (_psState == PSSTATE_UNINIT)
|
|
return E_UNEXPECTED;
|
|
|
|
return (_pPackage->_fIsDirty ? S_OK : S_FALSE);
|
|
}
|
|
|
|
HRESULT CPackage_IPersistStorage::InitNew(IStorage *pstg)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DebugMsg(DM_TRACE, "pack ps - InitNew() called.");
|
|
|
|
if (_psState != PSSTATE_UNINIT)
|
|
return E_UNEXPECTED;
|
|
|
|
if (!pstg)
|
|
return E_POINTER;
|
|
|
|
// Create a stream to save the package and cache the pointer. By doing
|
|
// this now we ensure being able to save in low memory conditions.
|
|
//
|
|
hr = pstg->CreateStream(SZCONTENTS,STGM_DIRECT | STGM_CREATE |
|
|
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,
|
|
&_pPackage->_pstm);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = WriteFmtUserTypeStg(pstg, (CLIPFORMAT)_pPackage->_cf,SZUSERTYPE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_pPackage->_fIsDirty = TRUE;
|
|
_psState = PSSTATE_SCRIBBLE;
|
|
|
|
_pPackage->_pIStorage = pstg; // cache the IStorage pointer
|
|
_pPackage->_pIStorage->AddRef(); // but don't forget to addref it!
|
|
|
|
DebugMsg(DM_TRACE, " leaving InitNew()");
|
|
}
|
|
else
|
|
{
|
|
_pPackage->_pstm->Release();
|
|
_pPackage->_pstm = NULL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CPackage_IPersistStorage::Load(IStorage *pstg)
|
|
{
|
|
HRESULT hr;
|
|
LPSTREAM pstm = NULL; // package contents
|
|
CLSID clsid;
|
|
|
|
DebugMsg(DM_TRACE, "pack ps - Load() called.");
|
|
|
|
if (_psState != PSSTATE_UNINIT) {
|
|
DebugMsg(DM_TRACE," wrong state!!");
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (!pstg) {
|
|
DebugMsg(DM_TRACE," bad pointer!!");
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
// check to make sure this is one of our storages
|
|
hr = ReadClassStg(pstg, &clsid);
|
|
if (SUCCEEDED(hr) &&
|
|
(clsid != CLSID_CPackage && clsid != CLSID_OldPackage) || FAILED(hr))
|
|
{
|
|
DebugMsg(DM_TRACE," bad storage type!!");
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
hr = pstg->OpenStream(SZCONTENTS,0, STGM_DIRECT | STGM_READWRITE |
|
|
STGM_SHARE_EXCLUSIVE, 0, &pstm);
|
|
if (FAILED(hr)) {
|
|
DebugMsg(DM_TRACE," couldn't open contents stream!!");
|
|
DebugMsg(DM_TRACE," hr==%Xh",hr);
|
|
goto ErrRet;
|
|
}
|
|
|
|
hr = _pPackage->PackageReadFromStream(pstm);
|
|
if (FAILED(hr))
|
|
goto ErrRet;
|
|
|
|
_pPackage->_pstm = pstm;
|
|
_pPackage->_pIStorage = pstg;
|
|
pstg->AddRef();
|
|
|
|
_psState = PSSTATE_SCRIBBLE;
|
|
_pPackage->_fIsDirty = FALSE;
|
|
_pPackage->_fLoaded = TRUE;
|
|
|
|
DebugMsg(DM_TRACE, " leaving Load()");
|
|
return S_OK;
|
|
|
|
ErrRet:
|
|
if (pstm)
|
|
pstm->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CPackage_IPersistStorage::Save(IStorage *pstg, BOOL fSameAsLoad)
|
|
{
|
|
HRESULT hr;
|
|
LPSTREAM pstm=NULL;
|
|
|
|
DebugMsg(DM_TRACE, "pack ps - Save() called.");
|
|
|
|
// must come here from scribble state
|
|
if ((_psState != PSSTATE_SCRIBBLE) && fSameAsLoad) {
|
|
DebugMsg(DM_TRACE," bad state!!");
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// must have an IStorage if not SameAsLoad
|
|
if (!pstg && !fSameAsLoad) {
|
|
DebugMsg(DM_TRACE," bad pointer!!");
|
|
return E_POINTER;
|
|
}
|
|
|
|
// hopefully, the container calls WriteClassStg with our CLSID before
|
|
// we get here, that way we can overwrite that and write out the old
|
|
// packager's CLSID so that the old packager can read new packages.
|
|
//
|
|
if (FAILED(WriteClassStg(pstg,CLSID_OldPackage))) {
|
|
DebugMsg(DM_TRACE,
|
|
" couldn't write CLSID to storage!!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// ok, we have four possible ways we could be calling Save:
|
|
// 1. we're creating a new package and saving to the same
|
|
// storage we received in InitNew
|
|
// 2. We're creating a new package and saving to a different
|
|
// storage than we received in InitNew
|
|
// 3. We were loaded by a container and we're saving to the
|
|
// same stream we received in Load
|
|
// 4. We were loaded by a container and we're saving to a
|
|
// different stream than we received in Load
|
|
//
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
//
|
|
// Same Storage as Load
|
|
//
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
if (fSameAsLoad) {
|
|
|
|
DebugMsg(DM_TRACE," Same as load.");
|
|
|
|
LARGE_INTEGER li = {0,0};
|
|
pstm = _pPackage->_pstm;
|
|
|
|
// If we're not dirty, so there's nothing new to save.
|
|
|
|
if (FALSE == _pPackage->_fIsDirty) {
|
|
DebugMsg(DM_TRACE, " not saving cause we're not dirty!!");
|
|
return S_OK;
|
|
}
|
|
|
|
// if we are dirty, set the seek pointer to the beginning and write
|
|
// the package information to the stream
|
|
hr = pstm->Seek(li, STREAM_SEEK_SET, NULL);
|
|
if (FAILED(hr)) {
|
|
DebugMsg(DM_TRACE, " couldn't set contents pointer!!");
|
|
return hr;
|
|
}
|
|
|
|
// case 1: new package
|
|
if (!_pPackage->_fLoaded) {
|
|
switch(_pPackage->_panetype) {
|
|
LPTSTR temp;
|
|
case PEMBED:
|
|
// if haven't created a temp file yet, then use the the
|
|
// file to be packaged to get our file contents from,
|
|
// otherwise we just use the temp file, because if we
|
|
// have a temp file, it contains the most recent info.
|
|
//
|
|
temp = _pPackage->_pEmbed->pszTempName;
|
|
|
|
if (!_pPackage->_pEmbed->pszTempName) {
|
|
DebugMsg(DM_TRACE, " case 1a:not loaded, using initFile.");
|
|
_pPackage->_pEmbed->pszTempName = _pPackage->_pEmbed->fd.cFileName;
|
|
}
|
|
else {
|
|
DebugMsg(DM_TRACE, " case 1b:not loaded, using tempfile.");
|
|
}
|
|
|
|
hr = _pPackage->PackageWriteToStream(pstm);
|
|
|
|
// reset our temp name back, since we might have changed it
|
|
// basically, this just sets it to NULL if it was before
|
|
_pPackage->_pEmbed->pszTempName = temp;
|
|
break;
|
|
|
|
case CMDLINK:
|
|
// nothing screwy to do here...just write out the info
|
|
// which we already have in memory.
|
|
hr = _pPackage->PackageWriteToStream(pstm);
|
|
break;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
// case 3: loaded package
|
|
else {
|
|
hr = _pPackage->PackageWriteToStream(pstm);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
//
|
|
// NEW Storage
|
|
//
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
else {
|
|
|
|
DebugMsg(DM_TRACE," NOT same as load.");
|
|
hr = pstg->CreateStream(SZCONTENTS,STGM_DIRECT | STGM_CREATE |
|
|
STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,
|
|
&pstm);
|
|
if (FAILED(hr)) {
|
|
DebugMsg(DM_TRACE, " couldn't create contents stream!!");
|
|
return hr;
|
|
}
|
|
WriteFmtUserTypeStg(pstg, (CLIPFORMAT)_pPackage->_cf,SZUSERTYPE);
|
|
|
|
// case 2:
|
|
if (!_pPackage->_fLoaded) {
|
|
switch(_pPackage->_panetype) {
|
|
LPTSTR temp;
|
|
case PEMBED:
|
|
temp = _pPackage->_pEmbed->pszTempName;
|
|
|
|
if (!_pPackage->_pEmbed->pszTempName) {
|
|
DebugMsg(DM_TRACE, " case 2a:not loaded, using initFile.");
|
|
_pPackage->_pEmbed->pszTempName = _pPackage->_pEmbed->fd.cFileName;
|
|
}
|
|
else {
|
|
DebugMsg(DM_TRACE, " case 2b:not loaded, using tempfile.");
|
|
}
|
|
|
|
hr = _pPackage->PackageWriteToStream(pstm);
|
|
|
|
// reset our temp name back, since we might have changed it
|
|
// basically, this just sets it to NULL if it was before
|
|
_pPackage->_pEmbed->pszTempName = temp;
|
|
break;
|
|
|
|
case CMDLINK:
|
|
// nothing interesting to do here, other than write out
|
|
// the package.
|
|
hr = _pPackage->PackageWriteToStream(pstm);
|
|
break;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
goto ErrRet;
|
|
|
|
}
|
|
|
|
// case 4:
|
|
else {
|
|
if (_pPackage->_panetype == PEMBED && _pPackage->_pEmbed->pszTempName ) {
|
|
DebugMsg(DM_TRACE," case 4a:loaded, using tempfile.");
|
|
hr = _pPackage->PackageWriteToStream(pstm);
|
|
if (FAILED(hr))
|
|
goto ErrRet;
|
|
}
|
|
else {
|
|
DebugMsg(DM_TRACE," case 4b:loaded, using stream.");
|
|
ULARGE_INTEGER uli = { 0xFFFFFFFF, 0xFFFFFFFF };
|
|
LARGE_INTEGER li = {0,0};
|
|
|
|
hr = _pPackage->_pstm->Seek(li,STREAM_SEEK_SET,NULL);
|
|
if (FAILED(hr))
|
|
goto ErrRet;
|
|
|
|
hr = _pPackage->_pstm->CopyTo(pstm,uli,NULL,NULL);
|
|
if (FAILED(hr))
|
|
goto ErrRet;
|
|
}
|
|
}
|
|
ErrRet:
|
|
UINT u = pstm->Release();
|
|
DebugMsg(DM_TRACE," new stream released. cRef==%d.",u);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
_psState = PSSTATE_ZOMBIE;
|
|
|
|
DebugMsg(DM_TRACE, " leaving Save()");
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CPackage_IPersistStorage::SaveCompleted(IStorage *pstg)
|
|
{
|
|
HRESULT hr;
|
|
LPSTREAM pstm;
|
|
|
|
DebugMsg(DM_TRACE, "pack ps - SaveCompleted() called.");
|
|
|
|
// must be called from no-scribble or hands-off state
|
|
if (!(_psState == PSSTATE_ZOMBIE || _psState == PSSTATE_HANDSOFF))
|
|
return E_UNEXPECTED;
|
|
|
|
// if we're hands-off, we'd better get a storage to re-init from
|
|
if (!pstg && _psState == PSSTATE_HANDSOFF)
|
|
return E_UNEXPECTED;
|
|
|
|
// if pstg is NULL then we have everything we need, otherwise we must
|
|
// release our held pointers and reinitialize.
|
|
//
|
|
if (pstg != NULL) {
|
|
DebugMsg(DM_TRACE, " getting new storage.");
|
|
hr = pstg->OpenStream(SZCONTENTS, 0, STGM_DIRECT | STGM_READWRITE |
|
|
STGM_SHARE_EXCLUSIVE, 0, &pstm);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (_pPackage->_pstm != NULL)
|
|
_pPackage->_pstm->Release();
|
|
|
|
// this will be reinitialized when it's needed
|
|
if (_pPackage->_pstmFileContents != NULL) {
|
|
_pPackage->_pstmFileContents->Release();
|
|
_pPackage->_pstmFileContents = NULL;
|
|
}
|
|
|
|
if (_pPackage->_pIStorage != NULL)
|
|
_pPackage->_pIStorage->Release();
|
|
|
|
_pPackage->_pstm = pstm;
|
|
_pPackage->_pIStorage = pstg;
|
|
_pPackage->_pIStorage->AddRef();
|
|
}
|
|
|
|
_psState = PSSTATE_SCRIBBLE;
|
|
_pPackage->_fIsDirty = FALSE;
|
|
DebugMsg(DM_TRACE, " leaving SaveCompleted()");
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CPackage_IPersistStorage::HandsOffStorage(void)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack ps - HandsOffStorage() called.");
|
|
|
|
// must come from scribble or no-scribble. a repeated call to
|
|
// HandsOffStorage is an unexpected error (bug in client).
|
|
//
|
|
if (_psState == PSSTATE_UNINIT || _psState == PSSTATE_HANDSOFF)
|
|
return E_UNEXPECTED;
|
|
|
|
// release our held pointers
|
|
//
|
|
if (_pPackage->_pstmFileContents != NULL) {
|
|
_pPackage->_pstmFileContents->Release();
|
|
_pPackage->_pstmFileContents = NULL;
|
|
}
|
|
|
|
if (_pPackage->_pstm != NULL) {
|
|
_pPackage->_pstm->Release();
|
|
_pPackage->_pstm = NULL;
|
|
}
|
|
|
|
if (_pPackage->_pIStorage != NULL) {
|
|
_pPackage->_pIStorage->Release();
|
|
_pPackage->_pIStorage = NULL;
|
|
}
|
|
|
|
_psState = PSSTATE_HANDSOFF;
|
|
DebugMsg(DM_TRACE, " leaving HandsOffStorage()");
|
|
return S_OK;
|
|
}
|