FILEOBJ.CPP

/* 
* FILEOBJ.CPP
* File Object for Link Source, Chapter 9
*
* Implementation of a "file" object named with a file moniker,
* which implements IPersistFile, IOleItemContainer, and
* IDescription. The latter two interfaces are implemented
* generically in IOLECONT.CPP and IDESCRIP.CPP.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/


#include "linksrc.h"

#ifdef WIN32ANSI
/*
* This is to turn off the mapping to ANSI wrapper APIs because
* we're actually using wide char strings under Win32 all the time
* in parts of this code.
*/
#undef StgOpenStorage
#define StgOpenStorage StgOpenStorage

#undef CreateFileMoniker
#define CreateFileMoniker CreateFileMoniker
#endif


/*
* CFileObject::CFileObject
* CFileObject::~CFileObject
*
* Parameters (Constructor):
* pUnkOuter LPUNKNOWN of a controlling unknown.
* pfnDestroy PFNDESTROYED to call when an object
* is destroyed.
*/

CFileObject::CFileObject(LPUNKNOWN pUnkOuter
, PFNDESTROYED pfnDestroy)
{
m_cRef=0;
m_pUnkOuter=pUnkOuter;
m_pfnDestroy=pfnDestroy;

m_clsID=CLSID_LinkedFile;
m_szFile[0]=(OLECHAR)0;
m_pIStorage=NULL;
m_pmk=NULL;
m_dwRegROT=0;

m_pImpIPersistFile=NULL;
m_pImpIOleItemContainer=NULL;
m_pImpIDescription=NULL;

return;
}

CFileObject::~CFileObject(void)
{
//Remove us from the running object table
if (0!=m_dwRegROT)
{
IRunningObjectTable *pROT;

if (SUCCEEDED(GetRunningObjectTable(0, &pROT)))
{
pROT->Revoke(m_dwRegROT);
pROT->Release();
}
}

ReleaseInterface(m_pmk);
ReleaseInterface(m_pIStorage);
DeleteInterfaceImp(m_pImpIDescription);
DeleteInterfaceImp(m_pImpIOleItemContainer);
DeleteInterfaceImp(m_pImpIPersistFile);
return;
}



/*
* CFileObject::Init
*
* Purpose:
* Performs any intiailization of a CFileObject that's prone to
* failure that we also use internally before exposing the object
* outside.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if the function is successful,
* FALSE otherwise.
*/

BOOL CFileObject::Init(void)
{
IUnknown *pUnk=this;

if (NULL!=m_pUnkOuter)
pUnk=m_pUnkOuter;

m_pImpIPersistFile=new CImpIPersistFile(this, pUnk);

if (NULL==m_pImpIPersistFile)
return FALSE;

m_pImpIOleItemContainer=new CImpIOleItemContainer(this, pUnk
, TRUE);

if (NULL==m_pImpIOleItemContainer)
return FALSE;

m_pImpIDescription=new CImpIDescription(pUnk);

if (NULL==m_pImpIDescription)
return FALSE;

return TRUE;
}




/*
* CFileObject::QueryInterface
* CFileObject::AddRef
* CFileObject::Release
*
* Purpose:
* IUnknown members for CFileObject object.
*/

STDMETHODIMP CFileObject::QueryInterface(REFIID riid, PPVOID ppv)
{
*ppv=NULL;

if (IID_IUnknown==riid)
*ppv=this;

if (IID_IPersist==riid || IID_IPersistFile==riid)
*ppv=m_pImpIPersistFile;

if (IID_IParseDisplayName==riid || IID_IOleContainer==riid
|| IID_IOleItemContainer==riid)
*ppv=m_pImpIOleItemContainer;

if (IID_IDescription==riid)
*ppv=m_pImpIDescription;

if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}

return ResultFromScode(E_NOINTERFACE);
}


STDMETHODIMP_(ULONG) CFileObject::AddRef(void)
{
return ++m_cRef;
}


STDMETHODIMP_(ULONG) CFileObject::Release(void)
{
if (0L!=--m_cRef)
return m_cRef;

if (NULL!=m_pfnDestroy)
(*m_pfnDestroy)();

delete this;
return 0;
}




/**
** IPersistFile implementation
**/

/*
* CImpIPersistFile:CImpIPersistFile
* CImpIPersistFile::~CImpIPersistFile
* CImpIPersistFile::QueryInterface
* CImpIPersistFile::AddRef
* CImpIPersistFile::Release
*
* Basic object members.
*/

CImpIPersistFile::CImpIPersistFile(PCFileObject pObj
, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}

CImpIPersistFile::~CImpIPersistFile(void)
{
return;
}

STDMETHODIMP CImpIPersistFile::QueryInterface(REFIID riid
, LPVOID *ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}

STDMETHODIMP_(ULONG) CImpIPersistFile::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CImpIPersistFile::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}





/*
* CImpIPersistFile::GetClassID
* CImpIPersistFile::IsDirty
* CImpIPersistFile::Save
* CImpIPersistFile::SaveCompleted
*
* Trivial or unimplemented members.
*/

STDMETHODIMP CImpIPersistFile::GetClassID(LPCLSID pClsID)
{
*pClsID=m_pObj->m_clsID;
return NOERROR;
}

STDMETHODIMP CImpIPersistFile::IsDirty(void)
{
//We're never dirty
return ResultFromScode(S_FALSE);
}

STDMETHODIMP CImpIPersistFile::Save(LPCOLESTR pszFile, BOOL fRemember)
{
return ResultFromScode(E_NOTIMPL);
}

STDMETHODIMP CImpIPersistFile::SaveCompleted(LPCOLESTR pszFile)
{
return NOERROR;
}





/*
* CImpIPersistFile::Load
*
* Purpose:
* Asks the server to load the document for the given filename.
*
* Parameters:
* pszFile LPCOLESTR of the filename to load.
* grfMode DWORD flags to use when opening the file.
*/

STDMETHODIMP CImpIPersistFile::Load(LPCOLESTR pszFile, DWORD grfMode)
{
const int cch=512;
HRESULT hr;

//We should only be loaded once; having a moniker tells us
if (NULL!=m_pObj->m_pmk)
return ResultFromScode(E_UNEXPECTED);

/*
* Since the server is single-use, we can be assured that
* this Load will only happen once, so we can hold the
* IStorage until the object is released.
*/
hr=StgOpenStorage(pszFile, NULL
, STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0
, &m_pObj->m_pIStorage);

if (FAILED(hr))
return hr;

m_pObj->m_pImpIDescription->SetStorage(m_pObj->m_pIStorage);

/*
* We opened it successfully, and that's all we have to
* do, so we can simply save the filename.
*/
#ifdef WIN32ANSI
wcsncpy(m_pObj->m_szFile, pszFile, cch);
#else
lstrcpyn(m_pObj->m_szFile, pszFile, cch);
#endif

/*
* Create a moniker for this file object and register as
* running.
*/
if (SUCCEEDED(CreateFileMoniker(pszFile, &m_pObj->m_pmk)))
{
IRunningObjectTable *pROT;

if (SUCCEEDED(GetRunningObjectTable(0, &pROT)))
{
//Register as weak so clients can free us
pROT->Register(0, m_pObj, m_pObj->m_pmk
, &m_pObj->m_dwRegROT);
pROT->Release();
}
}

return NOERROR;
}



/*
* CImpIPersistFile::GetCurFile
*
* Purpose:
* Returns the current filename.
*
* Parameters:
* ppszFile LPOLESTR * into which we store a pointer to
* the filename that should be allocated with the
* shared IMalloc.
*/

STDMETHODIMP CImpIPersistFile::GetCurFile(LPOLESTR *ppszFile)
{
LPMALLOC pIMalloc;
const int cch=512;
LPOLESTR psz;

*ppszFile=NULL;

if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
return ResultFromScode(E_FAIL);

psz=(LPOLESTR)pIMalloc->Alloc(cch*sizeof(OLECHAR));
pIMalloc->Release();

if (NULL==psz)
return ResultFromScode(E_OUTOFMEMORY);

#ifdef WIN32ANSI
wcsncpy(psz, m_pObj->m_szFile, cch);
#else
lstrcpyn(psz, m_pObj->m_szFile, cch);
#endif
*ppszFile=psz;
return NOERROR;
}