Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

use of wSchema in IMPLEMENT_SERIAL

Posted on 1999-01-19
1
981 Views
Last Modified: 2013-11-20
I'd like to know how to use the schema number in in IMPLEMENT_SERIAL. I'd like to use it to be able to read files of various versions, converting each version to the latest version, e.g., read (serialize) a CArchive object. If one of the objects is a prior version, read it the old way, then convert to the latest format, the store it using the latest format.

My documentation says only that a CArchiveException will be thrown when the framework encounters an object with a schema mismatch. I don't know how to recover and 'reread' the object (to convert its format) in the CATCH block.

Any ideas?
0
Comment
Question by:ALBEARD
1 Comment
 

Accepted Solution

by:
ramrocket earned 100 total points
ID: 1327986
Here is an article that will solve your problem from MS Developers Journal.  

Good Luck!
ramrocket

Mismatched schemas

If a file is loaded containing an original CChild object, with its old schema value 0x0099, MFC uses the extraction operator and detects that the old schema value is different from the current code and throws a CArchiveException.

It is a good idea to catch a CArchiveException in the object's Serialize() implementation. This locates the source of a version incompatibility immediately:

if (ar.IsLoading())
{
      try
      {
            ar >> pChild;
      }
      catch(CArchiveException* e)
      {
            if (CArchiveException::badSchema == e->m_cause)
            {
                  // Incompatible schema number!
                  TRACE("Bad schema at %s(%d)\n", __FILE__, __LINE__);
                  // handle accordingly...
            }
            else
            {
                  // hmm, another cause...
            }
      }
}
 


Versionable objects


The basic schema technique is adequate for objects that do not exist in multiple versions. There are two solutions to supporting backward-compatible objects: implement your own versioning scheme or use MFC's VERSIONABLE_SCHEMA mechanism:


MFC versionable objects are easily defined. Just override the VERSIONABLE_SCHEMA macro with your schema number in IMPLEMENT_SERIAL:

      IMPLEMENT_SERIAL(CChild, CObject, VERSIONABLE_SCHEMA | 0x009A)
 


This deceptively simple change makes your objects backward compatible. CChild::Serialize() can now be rewritten as follows:

void CChild::Serialize(CArchive& ar)
{
      CObject::Serialize(ar);            // remember to do this
      if (ar.IsStoring)
      {
            ar << m_dwData;
            ar << m_wId;
      }
      else      // IsLoading()
      {
            switch (ar.GetObjectSchema())
            {
                  case 0x0099:      // load old version
                        ar >> m_dwData;
                        break;
                  case 0x009A:      // load current version
                        ar >> m_dwData;
                        ar >> m_wId;
                        break;
                  default:            // Ouch! Corrupted file!
                        // handle error...
            }
      }
}
 


Note the addition of the CArchive::GetObjectSchema() call. This function returns the schema for the current object.

There is a caveat with GetObjectSchema(): you may call it only once during the serialization of an object; subsequent calls return -1. Therefore, you can't use VERSIONABLE_SCHEMA to make versionable class hierarchies. The following example illustrates this point.

class CBase : public CObject { ... };
class CChild : public CBase { ... };

// Note: base and child classes have different schema numbers
IMPLEMENT_SERIAL(CBase, CObject, VERSIONABLE_SCHEMA | 0x000A);
IMPLEMENT_SERIAL(CChild, CBase, VERSIONABLE_SCHEMA | 0x000B);

void CBase::Serialize(CArchive& ar)
{
      if ( ar.IsLoading() )
      {
            UINT nSchema = ar.GetObjectSchema();      // returns 0x000A
            // load versionable object...
      }
}

void CChild::Serialize(CArchive& ar)
{
      CBase::Serialize(ar);      // call base class Serialize()
      if ( ar.IsLoading() )
      {
            UINT nSchema = ar.GetObjectSchema();      // returns -1
            // second call to GetObjectSchema() FAILS
      }
}
 

The call to GetObjectSchema() in the child class's Serialize() fails because it was already called in the base class code.

Work around this caveat by implementing your own versioning. The following code shows one simple method:

class CBase : public CObject { enum { verBase = 0x0A }; ... };
class CChild : public CBase { enum { verChild = 0x0B }; ... };

void CBase::Serialize(CArchive& ar)
{
      CObject::Serialize(ar);
      if ( ar.IsStoring() )
      {
            ar << verBase;            // explicitly save version
            // ... then save everything else
      }
      else
      {
            UINT nMySchema;            // load version number
            ar >> nMySchema;
            switch ( nSchema )
            {
                  case verBase:      //load current version of object
                        // load CBase data...
                  // add cases for older versions
            }
      }
}

void CChild::Serialize(CArchive& ar)
{
      CBase::Serialize(ar);
      if ( ar.IsStoring() )
      {
            ar << verChild;            // explicitly save version
            // ... then save everything else
      }
      else
      {
            UINT nMySchema;            // load version number
            ar >> nMySchema;
            switch ( nSchema )
            {
                  case verChild:      //load current version of object
                        // load CChild data...
                  // add cases for older versions
            }
      }
}
 


Another GetObjectSchema() caveat: Calling GetObjectSchema() within a direct call to Serialize() will generate a CArchiveException during load. The archiving operators must be used for the MFC version control to work.

It is possible to handle different schema numbers within a class hierarchy without resorting to custom versioning. CArchive contains a method SerializeClass(), which can be used to serialize base class information inside a Serialize() function:

void CChild::Serialize(CArchive& ar)
{
      // serialize base class version and run-time class info
      ar.SerializeClass(RUNTIME_CLASS(CBase));
      // serialize base class data
      CBase::Serialize(ar);
      // etc.
}
 

0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Host to IP 7 80
difference between String.subString() and String.subSequence() 6 234
sumHeights2  challenge 7 114
Is there a simple front-end menu system. 9 103
Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question