?
Solved

use of wSchema in IMPLEMENT_SERIAL

Posted on 1999-01-19
1
Medium Priority
?
1,020 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
[X]
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
1 Comment
 

Accepted Solution

by:
ramrocket earned 400 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

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

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

In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
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.
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…
Suggested Courses
Course of the Month10 days, 20 hours left to enroll

770 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