65.9K
CodeProject is changing. Read more.
Home

Embracing IStream as just a stream of bytes

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (6 votes)

Dec 23, 2010

CPOL
viewsIcon

20340

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.