Link to home
Start Free TrialLog in
Avatar of mintcake
mintcake

asked on

URGENT problem with compound files

I have written an application which used compound file storage, and I was having some peculiar things happening with the size of the files created by the program. So after much head scratching I decided to write a program with the minimum functionality which might exhibit the same problem, and see if it was something I was doing or something with MFC. I found that this minimum functionality program exhibited the same problem. SO I am wondering if anybody can figure what I need to do to fix it.

To create the minimum functionality program , use AppWizard to create an MFC app, (MDI or SDI, it doesn't matter), ensure that you make the application a container and enable compound files.

Overide the serialize method as follows

void CMyTestDoc::Serialize(CArchive& ar)
{
        if (ar.IsStoring())
        {
                // TODO: add storing code here
                for (int i = 0; i < 100; i++)
                {
                        ar << 0xAAAAAAAA;
                }
        }
        else
        {
                // TODO: add loading code here
                for (int i = 0; i < 100; i++)
                {
                        DWORD temp;
                        ar >> temp;
                }
        }

        // Calling the base class COleDocument enables serialization
        //  of the container document's COleClientItem objects.
        COleDocument::Serialize(ar);
}

Run the application. Hit the save button on the toolbar. Save the file as XYZ.??? - or whatever you like. Quit the application. Check the size of the file you just saved. You will find that it is about 3.5k in size. You might want to make a copy of the file by cut and paste.

Now restart the application, load up the file you just saved, and then hit the save button again. Quit the application. If you now look at the file size - (you may need to press refresh if browsing the files using Explorer, becuase it doesn't seem to automatically refresh) - you will find that the file is 4.5k in size.

Examining the data file with the doc view shows that the new data is being appended to the file. When the file is read in the new data is being read, but the old data is still there, but not accesable.

Surely the data should have overwritten the old data, but it appears tht what it actually does is append it to the end of the file. Now when the file is so small this is not a problem. But I have files of 5mb or so, doubling up to 10mb.
Avatar of ShaunWilde
ShaunWilde

It looks as though you are saving your files in transacted mode and you need to change that to direct mode. If you look in the MFC source you will see that all the streams are created with STGM_TRANSACTED but you need STGM_DIRECT.
I suspect it is a case of roll your own classes :( unless of course somebody else has already done them.
You haven't shown how the CArchive is created.  It sounds like the document is being created in an append mode.

Serializing to a compound document is a reasonably complex process, and somewhere there may be an assumption lurking that you want to append a new stream to the document, rather than replace the document.  What I'd do is start tracing MFC code to see the way in which the file is opened.  It takes special effort to open a file for append, so this is not an accident; somewhere, there is a conscious decision in MFC to do this as an append operation.  Finding where that happens will tell you what you need to do to replace the document.  For example, there may be a CDocument state variable that controls append-vs-truncate.
Avatar of mintcake

ASKER

I posted this problem on CodeGuru, and got the following response.

-----------------------------------
This happens because you are using the compound file and the way
MFC opens/commits storage, and of course the storage implementation :
MFC opens storage(COleDocumnet::m_lpRootStg) in transacted mode,
and commits it with the flag STGC_ONLYIFCURRENT.
This is the most safest way : if something happeng during save operation, old
data won't be lost.
The price is an extra disk space.
This probably not a problem for many (may be most) applications : these days
several megabytes is like several bytes 10 years ago.
If you really want to sacrifice robustness in favor of disk space, try to use the STGC_OVERWRITE in IStorage::Commit call.
You may want to overwrite SaveToStorage in your docuemnt class ( this is protected virtual function of COleDocument ) : copy this function from MFC source and change STGC_ONLYIFCURRENT to STGC_OVERWRITE.
Or ( it's not clean but should work ) do it in Serialize function
yourdoc::Serialize
{
ColeDocument::Serialize(ar)
if ( ar.IsStoring )
{
//do your stuff
ar.Flush();
ar.GetFile()->Flush();
if ( m_lpRootStg )
m_lpRootStg->Commit(STGC_OVERWRITE);
// the second commit in ColeDocuemnt::SaveToStorage shouldn't do any harm
}
....
}
Hope this helps
---------------------------------------

Unfortunately this was posted anonymously, so I don't know who to thank, because after testing I found that this is the correct solution.
ASKER CERTIFIED SOLUTION
Avatar of ShaunWilde
ShaunWilde

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Not the correct answer but close.
aww shucks - you shouldn't have :)