350 lines
9.8 KiB
C++
350 lines
9.8 KiB
C++
|
|
||
|
#include <mvopsys.h>
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
static char s_aszModule[] = __FILE__; /* For error report */
|
||
|
#endif
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <_mvutil.h>
|
||
|
#include <orkin.h>
|
||
|
#include <ITverinfo.h>
|
||
|
#include "objmngr.h"
|
||
|
|
||
|
#ifdef IA64
|
||
|
#include <itdfguid.h>
|
||
|
#endif
|
||
|
|
||
|
CObjectInstHandler::CObjectInstHandler()
|
||
|
{
|
||
|
m_hMemory = NULL;
|
||
|
m_pObjects = NULL;
|
||
|
m_fInitNew = FALSE;
|
||
|
m_fIsDirty = FALSE;
|
||
|
m_iMaxItem = 0;
|
||
|
m_iCurItem = 0;
|
||
|
}
|
||
|
|
||
|
CObjectInstHandler::~CObjectInstHandler()
|
||
|
{
|
||
|
(void)Close();
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CObjectInstHandler::InitNew()
|
||
|
{
|
||
|
if(TRUE == m_fInitNew)
|
||
|
return SetErrReturn(E_UNEXPECTED);
|
||
|
|
||
|
m_fIsDirty = TRUE; // Set to false after breakers work
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
if(NULL == (m_hMemory = _GLOBALALLOC
|
||
|
(DLLGMEM_ZEROINIT, OBJINST_BASE * sizeof(OBJINSTMEMREC))))
|
||
|
SetErrCode (&hr, E_OUTOFMEMORY);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
m_pObjects = (POBJINSTMEMREC)_GLOBALLOCK(m_hMemory);
|
||
|
ITASSERT(m_pObjects);
|
||
|
|
||
|
m_iCurItem = 0;
|
||
|
m_iMaxItem = OBJINST_BASE;
|
||
|
}
|
||
|
return hr;
|
||
|
} /* InitNew */
|
||
|
|
||
|
|
||
|
STDMETHODIMP CObjectInstHandler::Close()
|
||
|
{
|
||
|
if(!m_hMemory)
|
||
|
return S_OK;
|
||
|
|
||
|
POBJINSTMEMREC pObjArray = m_pObjects;
|
||
|
for (DWORD loop = 0; loop < m_iCurItem; loop++, pObjArray++)
|
||
|
pObjArray->pUnknown->Release();
|
||
|
|
||
|
_GLOBALUNLOCK(m_hMemory);
|
||
|
_GLOBALFREE(m_hMemory);
|
||
|
|
||
|
m_iMaxItem = 0;
|
||
|
m_iCurItem = 0;
|
||
|
m_pObjects = NULL;
|
||
|
m_hMemory = NULL;
|
||
|
m_fInitNew = FALSE;
|
||
|
m_fIsDirty = FALSE;
|
||
|
|
||
|
return S_OK;
|
||
|
} /* Close */
|
||
|
|
||
|
STDMETHODIMP CObjectInstHandler::AddObject(REFCLSID clsid, DWORD *pdwObjInstance)
|
||
|
{
|
||
|
if (NULL == pdwObjInstance)
|
||
|
return SetErrReturn(E_INVALIDARG);
|
||
|
|
||
|
// Can we write the out param?
|
||
|
if (IsBadWritePtr(pdwObjInstance, sizeof(DWORD)))
|
||
|
{
|
||
|
ITASSERT(0);
|
||
|
return SetErrReturn(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
IUnknown *pUnknown;
|
||
|
HRESULT hr = CoCreateInstance
|
||
|
(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnknown);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
IPersistStreamInit *pPersist;
|
||
|
if (SUCCEEDED(hr = pUnknown->QueryInterface
|
||
|
(IID_IPersistStreamInit, (void **)&pPersist)))
|
||
|
{
|
||
|
(void)pPersist->InitNew();
|
||
|
pPersist->Release();
|
||
|
}
|
||
|
|
||
|
if (m_iCurItem == m_iMaxItem)
|
||
|
{
|
||
|
HANDLE hNewMem;
|
||
|
|
||
|
_GLOBALUNLOCK(m_hMemory);
|
||
|
hNewMem = _GLOBALREALLOC (m_hMemory,
|
||
|
(m_iMaxItem + OBJINST_INCREMENT) * sizeof(OBJINSTMEMREC), 0);
|
||
|
if (NULL == hNewMem)
|
||
|
{
|
||
|
*pdwObjInstance = 0;
|
||
|
return SetErrReturn(E_OUTOFMEMORY);
|
||
|
}
|
||
|
m_hMemory = hNewMem;
|
||
|
m_pObjects = (POBJINSTMEMREC)_GLOBALLOCK(m_hMemory);
|
||
|
m_iMaxItem += OBJINST_INCREMENT;
|
||
|
}
|
||
|
|
||
|
(m_pObjects + m_iCurItem)->pUnknown = pUnknown;
|
||
|
(m_pObjects + m_iCurItem)->clsid = clsid;
|
||
|
*pdwObjInstance = m_iCurItem++;
|
||
|
m_fIsDirty = TRUE;
|
||
|
|
||
|
return S_OK;
|
||
|
} /* CObjectInstHandler::AddObject */
|
||
|
|
||
|
|
||
|
STDMETHODIMP CObjectInstHandler::GetObject
|
||
|
(DWORD dwObjInstance, REFIID riid, void **ppv)
|
||
|
{
|
||
|
if (NULL == ppv)
|
||
|
return SetErrReturn(E_INVALIDARG);
|
||
|
|
||
|
// Can we write the out param?
|
||
|
if (IsBadWritePtr(ppv, sizeof(void *)))
|
||
|
{
|
||
|
ITASSERT(0);
|
||
|
return SetErrReturn(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
*ppv = NULL;
|
||
|
|
||
|
if (dwObjInstance >= m_iCurItem)
|
||
|
return SetErrReturn(E_NOTEXIST);
|
||
|
|
||
|
IUnknown *pUnknown = (m_pObjects + dwObjInstance)->pUnknown;
|
||
|
if (NULL == pUnknown)
|
||
|
return SetErrReturn(E_NOTEXIST);
|
||
|
|
||
|
return pUnknown->QueryInterface(riid, ppv);
|
||
|
} /* CObjectInstHandler::GetObject */
|
||
|
|
||
|
|
||
|
STDMETHODIMP CObjectInstHandler::Save(LPSTREAM pStream, BOOL fClearDirty)
|
||
|
{
|
||
|
if (NULL == pStream)
|
||
|
return SetErrReturn(E_INVALIDARG);
|
||
|
|
||
|
// Build up the header
|
||
|
OBJ_INSTANCE_CACHE ObjInstCache;
|
||
|
ObjInstCache.Header.dwVersion =
|
||
|
MAKELONG(MAKEWORD(0, rapFile), MAKEWORD(rmmFile, rmjFile));
|
||
|
ObjInstCache.Header.dwEntries = m_iCurItem;
|
||
|
if (NULL == (ObjInstCache.hRecords = _GLOBALALLOC
|
||
|
(GMEM_MOVEABLE, sizeof(OBJ_INSTANCE_RECORD) * m_iMaxItem)))
|
||
|
return SetErrReturn (E_OUTOFMEMORY);
|
||
|
ObjInstCache.pRecords =
|
||
|
(POBJ_INSTANCE_RECORD)_GLOBALLOCK(ObjInstCache.hRecords);
|
||
|
POBJ_INSTANCE_RECORD pRecord = ObjInstCache.pRecords;
|
||
|
|
||
|
// Save stream start pointer
|
||
|
LARGE_INTEGER liTemp = {0};
|
||
|
ULARGE_INTEGER liStart;
|
||
|
HRESULT hr;
|
||
|
if (FAILED(hr = pStream->Seek(liTemp, STREAM_SEEK_CUR, &liStart)))
|
||
|
{
|
||
|
exit0:
|
||
|
_GLOBALUNLOCK(ObjInstCache.hRecords);
|
||
|
_GLOBALFREE(ObjInstCache.hRecords);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Write dummy header to beginning of file
|
||
|
DWORD dwOffset =
|
||
|
sizeof(OBJ_INSTANCE_HEADER) + m_iCurItem * sizeof(OBJ_INSTANCE_RECORD);
|
||
|
DWORD dwHeaderSize = dwOffset;
|
||
|
if (FAILED(hr = pStream->Write(&ObjInstCache, dwHeaderSize, NULL)))
|
||
|
goto exit0;
|
||
|
|
||
|
POBJINSTMEMREC pObjArray = m_pObjects;
|
||
|
for (DWORD loop = 0; loop < m_iCurItem; loop++, pObjArray++, pRecord++)
|
||
|
{
|
||
|
pRecord->dwOffset = dwOffset;
|
||
|
|
||
|
// When we loaded this we coulnd't create this object. It is
|
||
|
// essentially dead. In this state we can not save. This is not
|
||
|
// an issue for IT40, since we never save the database at run-time
|
||
|
if (NULL == pObjArray->pUnknown)
|
||
|
{
|
||
|
ITASSERT(0);
|
||
|
SetErrCode(&hr, E_UNEXPECTED);
|
||
|
goto exit0;
|
||
|
}
|
||
|
|
||
|
// Save current stream pointer
|
||
|
ULARGE_INTEGER liStart; // Local scope - Don't confuse with
|
||
|
// function scoped variable of the same name
|
||
|
if (FAILED(hr = pStream->Seek(liTemp, STREAM_SEEK_CUR, &liStart)))
|
||
|
goto exit0;
|
||
|
|
||
|
// Write CLSID
|
||
|
if (FAILED(hr = pStream->Write(&pObjArray->clsid, sizeof(CLSID), NULL)))
|
||
|
goto exit0;
|
||
|
|
||
|
// Get IPersistStreamInit interface and save persistance data
|
||
|
IPersistStreamInit *pPersist;
|
||
|
if (SUCCEEDED(hr = pObjArray->pUnknown->QueryInterface
|
||
|
(IID_IPersistStreamInit, (void**)&pPersist)))
|
||
|
{
|
||
|
// Write persistance data
|
||
|
hr = pPersist->Save(pStream, fClearDirty);
|
||
|
pPersist->Release();
|
||
|
if (FAILED(hr))
|
||
|
goto exit0;
|
||
|
}
|
||
|
|
||
|
// Get current stream pointer
|
||
|
ULARGE_INTEGER liEnd;
|
||
|
if (FAILED(hr = pStream->Seek(liTemp, STREAM_SEEK_CUR, &liEnd)))
|
||
|
goto exit0;
|
||
|
|
||
|
pRecord->dwSize = (DWORD)(liEnd.QuadPart - liStart.QuadPart);
|
||
|
dwOffset += pRecord->dwSize;
|
||
|
}
|
||
|
|
||
|
// Write completed header
|
||
|
liTemp.QuadPart = liStart.QuadPart;
|
||
|
if (FAILED(hr = pStream->Seek(liTemp, STREAM_SEEK_SET, NULL)))
|
||
|
goto exit0;
|
||
|
if (FAILED(hr = pStream->Write
|
||
|
(&ObjInstCache.Header, sizeof (OBJ_INSTANCE_HEADER), NULL)))
|
||
|
goto exit0;
|
||
|
hr = pStream->Write(ObjInstCache.pRecords,
|
||
|
dwHeaderSize - sizeof (OBJ_INSTANCE_HEADER), NULL);
|
||
|
|
||
|
m_fIsDirty = FALSE;
|
||
|
goto exit0;
|
||
|
} /* CObjectInstHandler::Save */
|
||
|
|
||
|
|
||
|
STDMETHODIMP CObjectInstHandler::Load(LPSTREAM pStream)
|
||
|
{
|
||
|
if (TRUE == m_fInitNew)
|
||
|
return SetErrReturn(E_UNEXPECTED);
|
||
|
|
||
|
if (NULL == pStream || IsBadReadPtr(pStream, sizeof(void *)))
|
||
|
return SetErrReturn(E_INVALIDARG);
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Read header from stream
|
||
|
OBJ_INSTANCE_CACHE objCache;
|
||
|
hr = pStream->Read(&objCache, sizeof(OBJ_INSTANCE_HEADER), NULL);
|
||
|
if (FAILED(hr))
|
||
|
return SetErrReturn(hr);
|
||
|
|
||
|
if (objCache.Header.dwVersion != MAKELONG(MAKEWORD(0, rapFile), MAKEWORD(rmmFile, rmjFile)))
|
||
|
return SetErrReturn(E_BADVERSION);
|
||
|
m_iMaxItem = m_iCurItem = objCache.Header.dwEntries;
|
||
|
|
||
|
// Allocate memory for run-time table
|
||
|
if (NULL == (m_hMemory = _GLOBALALLOC
|
||
|
(DLLGMEM_ZEROINIT, m_iCurItem * sizeof(OBJINSTMEMREC))))
|
||
|
return SetErrReturn(E_OUTOFMEMORY);
|
||
|
m_pObjects = (POBJINSTMEMREC)_GLOBALLOCK(m_hMemory);
|
||
|
ITASSERT(m_pObjects);
|
||
|
|
||
|
// Allocate memory for the stream index table
|
||
|
if (NULL == (objCache.hRecords = _GLOBALALLOC
|
||
|
(DLLGMEM_ZEROINIT, m_iCurItem * sizeof(OBJ_INSTANCE_RECORD))))
|
||
|
{
|
||
|
hr = SetErrCode(&hr, E_OUTOFMEMORY);
|
||
|
exit0:
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
_GLOBALUNLOCK(m_hMemory);
|
||
|
_GLOBALFREE(m_hMemory);
|
||
|
m_hMemory = NULL;
|
||
|
m_pObjects = NULL;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
objCache.pRecords = (POBJ_INSTANCE_RECORD)_GLOBALLOCK(objCache.hRecords);
|
||
|
ITASSERT(objCache.pRecords);
|
||
|
|
||
|
// Read in the stream index table
|
||
|
if (FAILED(hr = pStream->Read(objCache.pRecords,
|
||
|
m_iCurItem * sizeof(OBJ_INSTANCE_RECORD), NULL)))
|
||
|
{
|
||
|
exit1:
|
||
|
_GLOBALUNLOCK(objCache.hRecords);
|
||
|
_GLOBALFREE(objCache.hRecords);
|
||
|
goto exit0;
|
||
|
}
|
||
|
|
||
|
// Proces each object in the table
|
||
|
POBJINSTMEMREC pObjArray = m_pObjects;
|
||
|
for (DWORD loop = 0; loop < m_iCurItem; loop++, pObjArray++)
|
||
|
{
|
||
|
LARGE_INTEGER liTemp;
|
||
|
liTemp.QuadPart = objCache.pRecords[loop].dwOffset;
|
||
|
if (FAILED(hr = pStream->Seek(liTemp, STREAM_SEEK_SET, NULL)))
|
||
|
goto exit1;
|
||
|
|
||
|
pStream->Read(&pObjArray->clsid, sizeof(CLSID), NULL);
|
||
|
|
||
|
// Create COM Object
|
||
|
hr = CoCreateInstance (pObjArray->clsid, NULL,
|
||
|
CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pObjArray->pUnknown);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Check for IPersistStreamInit interface
|
||
|
IPersistStreamInit *pPersist;
|
||
|
if (SUCCEEDED(hr = pObjArray->pUnknown->QueryInterface
|
||
|
(IID_IPersistStreamInit, (void**)&pPersist)))
|
||
|
{
|
||
|
// Read persistance data
|
||
|
if (FAILED(hr = pPersist->Load(pStream)))
|
||
|
{
|
||
|
pObjArray->pUnknown->Release();
|
||
|
pObjArray->pUnknown = NULL;
|
||
|
}
|
||
|
|
||
|
pPersist->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_fIsDirty = FALSE;
|
||
|
hr = S_OK;
|
||
|
goto exit1;
|
||
|
} /* CObjectInstHandler::Load */
|
||
|
|
||
|
|
||
|
inline STDMETHODIMP CObjectInstHandler::IsDirty(void)
|
||
|
{
|
||
|
return (m_fIsDirty ? S_OK : S_FALSE);
|
||
|
} /* IsDirty */
|