123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /////////////////////////////////////////////////////////////////////////////
- // TCNullStream.cpp | Implementation of the CTCNullStreamImpl class.<nl><nl>
- // This object provides an implementation of the IStream interface that does
- // nothing more that count the number of bytes being written to it. Since
- // ATL (currently 3.0) implements IPersistStreamInitImpl::GetSizeMax by
- // returning E_NOTIMPL, this object can be used in an override of that
- // method. This is accomplished by creating an instance of this null stream
- // and 'persisting' an object to it, thereby counting the number of bytes
- // needed to persist the object without allocating any memory.
- //
- /////////////////////////////////////////////////////////////////////////////
- // CTCNullStreamImpl
- #include "TCNullStreamImpl.h"
- /////////////////////////////////////////////////////////////////////////////
- // Construction
- CTCNullStreamImpl::CTCNullStreamImpl() :
- m_nPosition(0),
- m_nSize(0)
- {
- // Get the current FILETIME
- GetSystemTimeAsFileTime(&m_ftCreated);
- m_ftModified = m_ftAccessed = m_ftCreated;
- }
- /////////////////////////////////////////////////////////////////////////////
- // ISequentialStream Interface Methods
- STDMETHODIMP CTCNullStreamImpl::Read(void* pv, ULONG cb, ULONG* pcbRead)
- {
- HRESULT hr = S_OK;
- __try
- {
- // Lock the object
- Lock();
- // Compute the number of bytes that can be read
- ULONG nMax = m_nSize - m_nPosition;
- nMax = min(nMax, cb);
- // Clear the specified buffer for the maximum number of bytes
- ZeroMemory(pv, nMax);
- // Update the current position
- m_nPosition += nMax;
- // Get the current FILETIME
- GetSystemTimeAsFileTime(&m_ftAccessed);
- // Return the number of bytes read, if requested
- if (pcbRead)
- *pcbRead = nMax;
- }
- __except(1)
- {
- hr = STG_E_INVALIDPOINTER;
- }
- // Unlock the object
- Unlock();
- // Return the last result
- return hr;
- }
- STDMETHODIMP CTCNullStreamImpl::Write(const void* pv, ULONG cb,
- ULONG* pcbWritten)
- {
- UNUSED(pv);
- HRESULT hr = S_OK;
- __try
- {
- // Lock the object
- Lock();
- // Increment the current position
- m_nPosition += cb;
- // Compute the new size
- if (m_nPosition > m_nSize)
- m_nSize = m_nPosition;
- // Get the current FILETIME
- GetSystemTimeAsFileTime(&m_ftModified);
- // Return the number of bytes written, if requested
- if (pcbWritten)
- *pcbWritten = cb;
- }
- __except(1)
- {
- hr = STG_E_INVALIDPOINTER;
- }
- // Unlock the object
- Unlock();
- // Return the last result
- return hr;
- }
- /////////////////////////////////////////////////////////////////////////////
- // IStream Interface Methods
- STDMETHODIMP CTCNullStreamImpl::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
- ULARGE_INTEGER* plibNewPosition)
- {
- // Clear the specified [out] parameter, if not NULL
- if (plibNewPosition)
- TCZeroMemory(plibNewPosition);
- // Lock the object
- CLock lock(this);
- switch (dwOrigin)
- {
- case STREAM_SEEK_SET:
- {
- // Validate the position pointer as unsigned and in 32-bit range
- if (0 != dlibMove.HighPart)
- return STG_E_INVALIDFUNCTION;
- // Compute the new position
- m_nPosition = dlibMove.LowPart;
- break;
- }
- case STREAM_SEEK_CUR:
- {
- // Validate the position pointer as signed and in 32-bit range
- if (0 != dlibMove.HighPart && -1 != dlibMove.HighPart)
- return STG_E_INVALIDFUNCTION;
- // Compute the new position
- __int64 nPositionNew = __int64(m_nPosition) + LONG(dlibMove.LowPart);
- if (nPositionNew > ULONG_MAX)
- return STG_E_MEDIUMFULL;
- m_nPosition = ULONG(nPositionNew);
- break;
- }
- case STREAM_SEEK_END:
- {
- // Validate the position pointer as signed and in 32-bit range
- if (0 != dlibMove.HighPart && -1 != dlibMove.HighPart)
- return STG_E_INVALIDFUNCTION;
- // Compute the new position
- __int64 nPositionNew = __int64(m_nSize) + LONG(dlibMove.LowPart);
- if (nPositionNew > ULONG_MAX)
- return STG_E_MEDIUMFULL;
- m_nPosition = ULONG(nPositionNew);
- break;
- }
- default:
- return STG_E_INVALIDFUNCTION;
- }
- // Compute the new size, if position is beyond the end
- if (m_nPosition > m_nSize)
- m_nSize = m_nPosition;
- // Return the new position, if requested
- if (plibNewPosition)
- plibNewPosition->LowPart = m_nPosition;
- // Indicate success
- return S_OK;
- }
- STDMETHODIMP CTCNullStreamImpl::SetSize(ULARGE_INTEGER libNewSize)
- {
- // Validate the specified size as in 32-bit range
- if (0 == libNewSize.HighPart)
- return STG_E_INVALIDFUNCTION;
- // Lock the object
- CLock lock(this);
- // Set the new size of the stream
- m_nSize = libNewSize.LowPart;
- // Indicate success
- return S_OK;
- }
- STDMETHODIMP CTCNullStreamImpl::CopyTo(IStream* pstm, ULARGE_INTEGER cb,
- ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
- {
- // Initialize the [out] parameters
- if (pcbRead)
- TCZeroMemory(pcbRead);
- if (pcbWritten)
- TCZeroMemory(pcbWritten);
- // Ensure that the specified stream pointer is valid
- IStreamPtr spstm;
- RETURN_FAILED(TCSafeQI(pstm, &spstm));
- // Validate the specified size as in 32-bit range
- if (0 == cb.HighPart)
- return STG_E_INVALIDFUNCTION;
- // Initialize a chunk of memory to copy into the specified stream
- BYTE pBuf[2048];
- const int cbBuf = sizeof(pBuf);
- ZeroMemory(pBuf, cbBuf);
- // Lock the object
- CLock lock(this);
- // Compute the number of bytes that can be read
- ULONG nMax = m_nSize - m_nPosition;
- nMax = min(nMax, cb.LowPart);
- // Copy the NULL memory chunk for the specified number of bytes
- HRESULT hr;
- for (ULONG nRemaining = nMax; nRemaining > cbBuf; nRemaining -= cbBuf)
- if (FAILED(hr = spstm->Write(pBuf, cbBuf, NULL)))
- return hr;
- // Copy any remaining bytes
- if (nRemaining && FAILED(hr = spstm->Write(pBuf, nRemaining, NULL)))
- return hr;
- // Update the current position
- m_nPosition += nMax;
- // Get the current FILETIME
- GetSystemTimeAsFileTime(&m_ftAccessed);
- // Return the number of bytes read, if requested
- if (pcbRead)
- pcbRead->LowPart = nMax;
- // Return the number of bytes written, if requested
- if (pcbWritten)
- pcbWritten->LowPart = nMax;
- // Indicate success
- return S_OK;
- }
- STDMETHODIMP CTCNullStreamImpl::Commit(DWORD grfCommitFlags)
- {
- UNUSED(grfCommitFlags);
- return E_NOTIMPL;
- }
- STDMETHODIMP CTCNullStreamImpl::Revert(void)
- {
- return E_NOTIMPL;
- }
- STDMETHODIMP CTCNullStreamImpl::LockRegion(ULARGE_INTEGER libOffset,
- ULARGE_INTEGER cb, DWORD dwLockType)
- {
- UNUSED(libOffset);
- UNUSED(cb);
- UNUSED(dwLockType);
- return E_NOTIMPL;
- }
- STDMETHODIMP CTCNullStreamImpl::UnlockRegion(ULARGE_INTEGER libOffset,
- ULARGE_INTEGER cb, DWORD dwLockType)
- {
- UNUSED(libOffset);
- UNUSED(cb);
- UNUSED(dwLockType);
- return E_NOTIMPL;
- }
- STDMETHODIMP CTCNullStreamImpl::Stat(STATSTG* pstatstg, DWORD grfStatFlag)
- {
- UNUSED(grfStatFlag);
- // Initialize the specified structures
- TCZeroMemory(pstatstg);
- // Lock the object
- CLock lock(this);
- // Populate the fields of the specified structure
- pstatstg->pwcsName = NULL;
- pstatstg->type = STGTY_STREAM;
- pstatstg->cbSize.HighPart = 0;
- pstatstg->cbSize.LowPart = m_nSize;
- pstatstg->mtime = m_ftModified;
- pstatstg->ctime = m_ftCreated;
- pstatstg->atime = m_ftAccessed;
- pstatstg->grfMode = STGM_READWRITE | STGM_SHARE_DENY_NONE;
- pstatstg->grfLocksSupported = 0;
- pstatstg->clsid = CLSID_NULL;
- // Indicate success
- return S_OK;
- }
- STDMETHODIMP CTCNullStreamImpl::Clone(IStream** ppstm)
- {
- // Initialize the [out] parameter
- CLEAROUT(ppstm, (IStream*)NULL);
- // Create an new instance of ourself
- typedef CComObject<CTCNullStreamImpl> CNullStreamObject;
- CNullStreamObject* pObject = NULL;
- HRESULT hr = CNullStreamObject::CreateInstance(&pObject);
- RETURN_FAILED(hr);
- // The QueryInterface will put a refcount of 1 on the new object
- IStreamPtr pstm(pObject->GetUnknown());
- // Lock the object
- CLock lock(this);
- // Initialize the new stream with our seek pointer and size
- LARGE_INTEGER dlibMove = {0, m_nPosition};
- ULARGE_INTEGER libNewSize = {0, m_nSize};
- _SVERIFY(hr = pstm->Seek(dlibMove, STREAM_SEEK_SET, NULL));
- _SVERIFY(hr = pstm->SetSize(libNewSize));
- // Detach the new stream to the specified [out] parameter
- *ppstm = pstm;
- pstm.Detach();
- // Indicate success
- return S_OK;
- }
|