IStream - Compound File Implementation

The IStream interface supports reading and writing data to stream objects. Stream objects contain the data in a structured storage object, where storages provide the structure. Simple data can be written directly to a stream, but most frequently, streams are elements nested within a storage object. They are similar to standard files.

The specification of IStream defines more functionality that the COM implementation supports. For example, the IStream interface defines streams up to 264 bytes in length requiring a 64-bit seek pointer. However, the COM implementation only supports streams up to 232 bytes in length (4 gigabytes) and read and write operations are always limited to 232 bytes at a time. The COM implementation also does not support stream transactioning or region locking.

When you want to create a simple stream based on global memory, you can get an IStream pointer by calling the API function CreateStreamOnHGlobal. To get an IStream pointer within a compound file object, call either StgCreateDocfile or StgOpenStorage. These functions retrieve an IStorage pointer, with which you can then call CreateStream/OpenStream for an IStream pointer. In either case, the same IStream implementation code is used.

Note  The compound file implementation of structured storage does not succeed on a QueryInterface for ISequentialStream but it includes the Read and Write methods through the IStream interface pointer. The same is true for the NTFS Native Structured Storage implementation.

When to Use

Call the methods of IStream to read and write data to a stream.

Since stream objects can be marshaled to other processes, applications can share the data in storage objects without having to use global memory. In the COM compound file implementation of stream objects, the custom marshaling facilities in COM create a remote version of the original object in the new process when the two processes have shared memory access. Thus, the remote version does not need to communicate with the original process to carry out its functions.

The remote version of the stream object shares the same seek pointer as the original stream. If you do not want to share the seek pointer, you should use the IStream::Clone method to provide a copy of the stream object for the remote process.

Note  If you are creating a stream object that is larger than the heap in your machine's memory and you are using an HGLOBAL, the stream object calls GlobalRealloc internally whenever it needs more memory. Because GlobalRealloc always copies data from the source to the destination, increasing a stream object from 20M to 25M, for example, consumes immense amounts of time. This is due to the size of the increments copied and is worsened if there is less than 45M of memory on the machine because of disk swapping.

The preferred solution is to implement an IStream that uses memory allocated by VirtualAlloc instead of GlobalAlloc. This can reserve a large chunk of virtual address space and then commit memory within that address space as required. No data copying occurs and memory is committed only as it is needed.

Another alternative is to call the IStream::SetSize method on the stream object to increase the memory allocation in advance. This is not, however, as efficient as using VirtualAlloc as described above.

Remarks

ISequentialStream::Read
Reads a specified number of bytes from the stream object into memory starting at the current seek pointer. This implementation returns S_OK if the end of the stream was reached during the read. (This is the same as the "end of file" behavior found in the MS-DOS FAT file system.
ISequentialStream::Write
Writes a specified number from bytes into the stream object starting at the current seek pointer. In this implementation, stream objects are not sparse. Any fill bytes are eventually allocated on the disk and assigned to the stream.
IStream::Seek
Changes the seek pointer to a new location relative to the beginning of the stream, to the end of the stream, or to the current seek pointer.
IStream::SetSize
Changes the size of the stream object. In this implementation, there is no guarantee that the space allocated will be contiguous
IStream::CopyTo
Copies a specified number of bytes from the current seek pointer in the stream to the current seek pointer in another stream.
IStream::Commit
The compound file implementation of IStream supports opening streams only in direct mode, not transacted mode. Therefore, the method has no effect when called other than to flush all memory buffers to the next storage level.

In this implementation, it does not matter if you commit changes to streams, you need only commit changes for storage objects.

IStream::Revert
This implementation does not support transacted streams, so a call to this method has no effect.
IStream::LockRegion
Range-locking is not supported by this implementation, so a call to this method has no effect.
IStream::UnlockRegion
Removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.
IStream::Stat
Retrieves the STATSTG structure for this stream
IStream::Clone
Creates a new stream object with its own seek pointer that references the same bytes as the original stream.

See Also

IStream, IStorage, CreateStreamOnHGlobal, StgCreateDocfile, StgOpenStorage