Click here to Skip to main content
Click here to Skip to main content

Structured Storage Class for ATL & MFC

By , 20 Jul 2000
 
  • Download demo project - 12 Kb
  • Download source - 8 Kb
  • Structured storage is a useful tool in the software development. It allows us to open a single binary file and section it into several storages (which may be nested). Each storage may have one or more streams, which are used to write and retrieve the program specific information.

    All this functionality is built around COM objects that MS provides with the Windows OS. We access it via IStorage and IStream interfaces and a few API function calls. This, however, is a tedious job and I decided to write a thin wrapper around these interfaces and API calls.

    A Brief Example

    The following code snapshot shows the class in action ...
    StructuredStorage ss;
    //
    // Let's create a file. This also creates the root storage.
    //
    ss.CreateFile(L"SSTest.bin");
    //
    // Let's create a storage on the root one.
    //
    ss.CreateStorage(L"FirstLevel");
    //
    // Create a stream and write to it
    //
    CComPtr<IStream> spIStr;
    ss.CreateStream(&spIStr, L"A stream");
    CComBSTR bs(L"Some text to be written into the stream!");
    bs.WriteToStream(spIStr);
    //
    // ...
    

    Background Information

    At this point I must say that the structure of the class was inspired by the article and code of Andrew Peace. His solution suited me perfectly, but unfortunately, I find it useless (for my specific case, of course) due to following reasons:
    • Andrew's solution uses CString and CList and is therefore bound with MFC library. We need the structured storage functionality in a COM control and therefore the linkage to MFC is not desired.
    • A better look at his code shows that he uses several redundant variables, which complicate the code, unnecessarily.
    • Sometimes (though rarely) we need to know why an interface call or a function call failed.

    Although my solution eliminates the shortcomings above, it adds some new:

    • I am using a STL vector container. Some people try to avoid using STL containers in their COM objects.
    • If the solution is used inside a standard MFC project, a support for CComBSTR class is required (defined in "ATLBase.h"). Again, some people dislike this header in MFC code.
    • Advance features of structured storage management are still not provided.

    Implementation Information

    The class is build around a vector of IStorage objects. (IStorage object == storage, vector of storages == container) The first element of vector represents the root storage and subsequent elements represent sub storages. We can say that the vector of storages represents a path from the root storage to the last storage (the current one). Example:
    • [0] = root storage (level 0, not neceserally the root of the file).
    • [1] = storage inside the root (level 1).
    • [2] = storage inside the level 1 storage (level2)
    • [n] = current storage at level n (the last element of container).

    If the root storage is also the root of the structured file, say "C:\test\StructFile.bin", level 1 is "Level 1", level 2 is "Level 2", ... then the path to the current storage is:

    "C:\test\StructFile.bin|Level1|Level2|...|LevelN"

    Vertical char | is used to emphasize the borderline between the storages. Note, that the part of the path "Level1|Level2|...|LevelN" is hidden inside the "StructFile.bin" file.

    The front and the back of the vector are the most important storages. The former presents the root storage, while the later presents the current storage.

    Related Documentation

    Please refer to MSDN library and search for IStorage, IStream, StgCreateDocfile, StgOpenStorage, ... for more details.

    Final Remarks

    Those who look into the StructuredStorage.h file, will notice a lot of commented text and funny commands. They are required by the Doxygen documentation system. It is a free documentation utility that is able to generate HTML, HTML help, LaTeX, RTF, ... documents.

    I hope you will find the class useful!

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    About the Author

    Ales Krajnc
    Web Developer
    Slovenia Slovenia
    Member
    No Biography provided

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    GeneralAlternative way for .NETmemberJan Gex23 Aug '06 - 4:48 
    Using the same approach in .NET would be a problem because interop calls require unmanaged code access permissions. Alternative way is to use some of 3rd party components. For example GemBox.CompoundFile ( http://www.gemboxsoftware.com/CompoundFile.htm) is a native (written in C#) .NET component for accessing OLE 2 Compound Document files.

    QuestionHow to save HTMLs into single?memberAlick Xiong16 Jun '04 - 21:06 
    I have just read your article for I have been looking for some information to do my work. I have to save several HTMLs not only one into a single file without any source(jpg,gif,etc.)lost. I found Structured Storage on the web which I have never used before.How to use this for my work?First,I must save several HTMLs into a single file such as *.abc;Second,I can reload the *.abc,then I can read the htmls in a htmlview in my project. I was confused.
    Could you give me some ideas ? Or a example would be nice.Thank you very much!
     
    Alick
    GeneralFix for memory leakmemberPhil J Pearson26 Mar '04 - 5:57 
    The GetPath method leaks memory; see the documentation for STATSTG:
     
    "...
    pwcsName
    Pointer to a NULL-terminated Unicode string containing the name. Space for this string is allocated by the method called and freed by the caller (see CoTaskMemFree).
    ..."
     
    I modified the function by adding two lines as follows:
      bsPath += L"|";
      if (NULL != sg.pwcsName)       // added
        CoTaskMemFree(sg.pwcsName);  // added
      }
    
     
    Regards,
    Phil

     

    The opinions expressed in this communication do not necessarily represent those of the author (especially if you find them impolite, discourteous or inflammatory).

    GeneralRe: Fix for memory leakmemberPortatofe2 Oct '08 - 5:14 
    Thank you for taking the time to publish this information very useful!
     

    GeneralSTGM_SWMRmemberShashidhar Kamath26 Sep '03 - 6:58 
    The Flags mentioned in online MSDN STGM_SWMR works only with newest platform sdk. If you intend to use the file in single write multiple read mode without making a copy of the file(as in transacted mode, slow file opening for read mode if file sizes are big)you should use STGM_SWMR flag.See STGM help on MSDN online. But with VC++ 6.0 it does not work. As this flag is not supported .You have to download latest version of SDK and compile your code setting SDK include and SDK libraries on top of VC and MFC includes and libraries in project->tool->option->directory menu. And you should use WIN32_WINNT=0x0500 as the preprocessor defination in C++ tab in project setting.
     
    shashi
    GeneralSolutionmemberShashidhar Kamath18 Sep '03 - 7:23 
    If you want to open one file in write mode from one application and the same file in read mode from other application You have to open the file in transacted mode in both the places. Where you want to write, Open it in use STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_DENY_WRITE mode and you have to commit the changes after you write.
     
    While where you want to read it
     
    open it using the flag STGM_TRANSACTED|STGM_SHARE_DENY_NONE|STGM_READ
     

    I had a tough time getting this right, because some of the things mentioned in MSDN are not implemented yet and they are not functional.
     

    hope this helps!
     
    Shashi
    GeneralRe: Solutionmembermedhamp25 Sep '03 - 23:46 
    Thanks Shashi,
     
    It solved my problem.
    The only change I need was write mode flags are-
    STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE for non transactional type of file
     
    Regards,
    Medha
    GeneralRe: Solution + Multi-ThreadsmemberKayuchkin Alexander12 Nov '03 - 19:58 
    Hello. Very usefull class, thanx.
    Can you tell me about how to use one storage in different threads?
    For example there are two threads, one for reading structured storage and another to write (recieving information from server and saving it to storage in background mode).
    Is this correct to use the same method to access storage as in previous message of mr.Medhamp? )
    Thank you
    Generalstructured file storagememberShashidhar Kamath8 Apr '03 - 20:01 
    Cry | :(( Cry | :(( Cry | :(( Hi
     
    i read ur article on structured storage. Im having a problem creating a structure file that with
    STGM_READWRITE |STGM_DIRECT |STGM_SHARE_DENY_WRITE options.
    I tried stgcretedocfile and StgCreateStorageEx.
     
    I even tried IDirectWriterLock interface, nothing seems to work. Basically i want the file to be opened in read/write access at one place and let others use it only using read access. How do i achieve this without STGM_TRANSACTED flag.
    Any help is greately appreciated.
     
    thanks
    shashi
     

    GeneralRe: structured file storagememberMedhamp18 Sep '03 - 0:49 
    Hi,
     
    I am facing same problem. I a opening file in one application using above class and tries to open the same file via another application, it it giving Sharing violation error in other application.
     
    But good try to wrap difficult IStorage class
     

    GeneralCloseFile methodmemberSancho5 Jan '03 - 1:49 
    Class has a CreateFile & OpenFile methods but where is CloseFile?
    GeneralRe: CloseFile methodmemberAles Krajnc5 Jan '03 - 6:06 
    The CloseStorage() does this job. CreateFile and OpenFile methods have a bit misleading names, but what they actually do is to open/create a root storage - see the code.
     
    Ales
     
    Don't think there are no crocodiles because the water is calm.
    GeneralRe: CloseFile methodmemberAles Krajnc5 Jan '03 - 6:15 
    Correction!
     
    It is Clear(), what you need to use.
     
    Ales
     
    Don't think there are no crocodiles because the water is calm.
    QuestionIStream ?memberswinefeaster11 May '02 - 17:02 
    Hello!
     
    I'm trying to record a metafile under Gdi+ somehow into MEMORY, but all the constructors for Gdiplus::Metafile require a filename! WTF | :WTF:

    There is however one constructor which allows the metafile to be recorded into an IStream interface. I was thinking that perhaps such an object could be written that would stream the data into a memory buffer via an IStream interface.


    Metafile::Metafile(IStream* stream, HDC referenceHdc, Rect& frameRect, MetafileFrameUnit frameUnit, EmfType type, WCHAR* description)

    Creates a Metafile object for recording to an IStream interface.


    Any ideas on how this is possible? Perhaps some atl / com code? I need this for a Visual C++ 6.0 Mfc app. I thought perhaps you would know this because your example has to do with IStream and IStorage, or perhaps you could point me in the right direction...

    Thanx a bunch! I really appreciate your help Smile | :) .

    Cheers,

    swinefeaster

     
    Check out Aephid Photokeeper, the powerful digital
    photo album solution at www.aephid.com.

    AnswerRe: IStream ?sussHakan16 Aug '02 - 11:44 
    I think what you need is:
     

    HGLOBAL hGlb = GlobalAlloc(...);
    IStream *pI = CreateStreamOnHGlobal(...);
    if( pI )
    {
    MetaFile *mf = new MetaFile( pI, ...); // or so
    }

    HTH,
     
    Hakan
    Smile | :)
    GeneralRe: IStream ?memberSwinefeaster16 Aug '02 - 12:16 
    Ooooh oooh oooh! wonderful! Thanks buddy Wink | ;) . I'll try that out and let ya know... I had almost given up on that.
     
    Cheers,
     
    Swine
     
    Check out Aephid Photokeeper, the powerful digital
    photo album solution at www.aephid.com.

    GeneralUNC pathsmemberSerge Gommers22 Aug '01 - 9:59 
    Hi,
     
    is there a way to use UNC pathnames with the StgOpenStorage function?
     
    According to the documentation of StgOpenStorage and StgOpenStorageEx, the filename prefix \\?\ can't be used, so how to use StgOpenStorage with UNC paths?
     


    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web02 | 2.6.130516.1 | Last Updated 21 Jul 2000
    Article Copyright 2000 by Ales Krajnc
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid