windows-nt/Source/XPSP1/NT/shell/ext/pack/iperstor.cpp

448 lines
14 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
#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;
}