Embracing IStream as just a stream of bytes
Shows how one can use IStream for in-memory operations
IStream
is nothing more than just a stream of bytes. Though it's usually related to other interfaces in OLE such as IStorage
, it will be fair enough to treat IStream
as a standalone medium. Let's see. Suppose there is a function that takes an IStream
pointer as a parameter: void readInImage(IStream *)
. This generally means the expected byte-content of the data (in this case an image) may come from anywhere, only it should be interfaced through IStream
. Now suppose your byte-content is in the following form: extern char *imgBytes
.
So how to put that char*
into IStream
? Here we go:
extern char *imgBytes; extern int cbImgBytes; HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, cbImgBytes); ASSERT( hMem != NULL ); PVOID pMem = GlobalLock(hMem); // get the actual pointer for the HGLOBAL RtlMoveMemory(pMem, imgBytes, cbImgBytes); IStream *pStream = 0; HRESULT hr = CreateStreamOnHGlobal(hMem, TRUE, &pStream); // TRUE means hMem will be automatically freed up when pStream->Release(). // check against FAILED(hr)Now we can simply use that
pStream
like so:
readInImage(pStream); pStream->Release();For a reverse operation, i.e. writing into
IStream
, no need to use those GlobalAlloc
/GlobalLock
functions. Suppose we have the following function writeOutImage(IStream *)
. In the following illustration, writeOutImage
puts its byte-content into IStream
:
IStream *pStream = 0; HRESULT hr = CreateStreamOnHGlobal(0, TRUE, &pStream); // check against FAILED(hr) writeOutImage(pStream); // Note: IStream will automatically grow up as necessary.And finally, the following code shows how one can get back byte-content form
IStream
itself:
// first let's learn the size of the content STATSTG statsg; HRESULT hr = pStream->Stat(&statsg, STATFLAG_NONAME); // check against FAILED(hr) // We need to seek to the first position as after writeOutImage it's at the end. LARGE_INTEGER seekPos; seekPos.QuadPart = 0; hr = pStream->Seek(seekPos, STREAM_SEEK_SET, NULL); // check against FAILED(hr) char *bytes = new char[statsg.cbSize.QuadPart]; ULONG cbRead; hr = pStream->Read(bytes, statsg.cbSize.QuadPart, &cbRead); // here cbRead should be equal to statsg.cbSize.QuadPart. // Alternatively, to be memory efficient, one can read in chunk by chunk (in a cycle.)That is it. The bottom line is that
IStream
is just a way of holding a stream of bytes.