Compound Documents v1.00 ~~~~~~~~~~~~~~~~~~~~~~~~ Robert R. Marsh, SJ rrm@sprynet.com http://home.sprynet.com/sprynet/rrm/ Compound Documents, or OLE Structured Storage, provide an ingenious and easy way to effectively create a full file-system within a file. A compound document functions as a 'directory' (or root storage in the lingo) which can contain 'sub-directories' (aka storages) and/or 'files' (aka streams). Compound documents also have the ability to automatically buffer any changes until they are committed or rolled back. Unfortunately, the association with OLE/ActiveX keeps many Delphi users away. But while the details can be messy there is no deep difficulty. Some Delphi encapsulations of compound files are already available but either cost big bucks or mirror the underlying API too closely with all its arcane flags many of which are mutually exclusive. The components presented here encapsulate the OLE structured storage API in a what is, I hope, a Delphi- friendly manner, free from all the OLE clutter. What's more they work in all three versions of Delphi (see below for a caveat). A TRootStorage object corresponds to a physical file on disk. Other TStorage objects correspond to sub-storages of a root storage. Apart from their mode of construction both objects have similar behavior. They have methods to manage the sub-storages and streams they contain (CopyElement, MoveElement, RenameElement, DeleteElement, CopyTo, ListStorages, ListStreams) and methods to handle transaction processing (Commit, Revert). TStorageStream objects always belong to a parent storage object. They are fully compatible with Delphi's other stream objects. Despite the impression given in many descriptions transaction processing does not work at the stream level but only for storages. Transaction processing operates by publishing any changes visible at one level in the storage hierarchy to the parent level. A storage has no knowledge of changes made at a deeper level until they percolate upwards through a series of Commit operations. When a root storage commits its changes they are written to the physical file. Both storages and streams can be created as temporary objects by providing no Name parameter. A unique name is generated by Windows and is available through the Name property. Such objects are self- deleting. The OLE documentation warns that compound files are optimized for common operations (like the reading and writing of streams) and that other operations (especially those involving the enumeration of storage elements) can be slow. Although I have provided some enumeration methods (ListStorages, ListStreams) you will get better performance if you create a separate stream to store such information for yourself. In general, I have found read/write operations to be about 2 to 3 times slower than equivalent operations on 'ordinary' file streams. Not bad considering the extra functionality. You can find out more about Compound Documents / OLE Structured Storage from the excellent book "Inside OLE" (2nd ed.) by Kraig Brockschmidt (Microsoft Press) or from the Microsoft Developers Network library (via http://microsoft.com/msdn/). Good luck! One of the benefits of these components is that someone has read the small print for you and made many illegal operations impossible. I realize, however, that I have probably misread in some cases. So if you find problems with this code please let me know at the address above so that I can learn from my mistakes. I referred above to a caveat regarding the use of these components with Delphi 1. There are two issues. First, as I understand it, OLE2 came on the scene after Windows 3.1 so that plain vanilla installations don't include the necessary OLE dlls. Nevertheless, it would be rare to find a machine that hasn't had the OLE2 files added by one application or another. The second issue has more to do with Borland. The OLE2 DCU and PAS files they supplied with D1 seem to be contain errors (even on the D2 and D3 CDs). I have taken the liberty of correcting the problems which pertain to Compound Documents and also changed some of the flag declaration to bring them more into line with D2 and D3. The result is a file called OLE2_16 which must be used with CompDoc.DCU under Delphi 1. Other versions of Delphi can ignore this file. If you like these components and find yourself using them please consider making a donation to your favorite charity. I would also be pleased if you would make acknowledgement in any projects that make use of them. These components are supplied as is. The author disclaims all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The author assumes no liability for damages, direct or consequential, which may result from their use. Copyright (c) 1998 Robert R. Marsh, S.J. & the British Province of the Society of Jesus Robert R. Marsh, S.J. January 6, 1998