January 28th, 2010

Hidden Data

If the CArchive::ReadObject function in MFC would temporarily cache the CRuntimeClass pointer for the object that's being read in a visible member variable so that the object's Serialize function could see it, I could make a miracle occur.

Unfortunately, it doesn't and I can't, so I'm going to have to do this the hard way.

A little geekish background: It turns out that you can initialize the CRuntimeClass structure so that the CRuntimeClass structure belonging to class A can be used to create a different class B. This is useful when you've serialized class A in your archive, but you want to rearrange the class structure so that you create class B -- say, for instance, that you've renamed the class or you're converting an existing class to a virtual base class and adding various derived classes down below. In this case, class A is now a virtual base class and class B is the new class derived from it. (Presumably, there will be more classes derived from class A in the long run, but the first class that's derived is usually the direct inheritor, so this trick works.)

Say, though, that you've got virtual base class A with classes B, C, and D descended from it and you want to get rid of B, C, and D and collapse back to a single non-virtual class A. If B, C, and D each contain unique additional data items that you've decided to just stuff into A and ignore when they don't apply, you can't get the serialization to work (unless the schema numbers for B, C, and D are completely disjoint, which isn't likely).

You can cause the CRuntimeClass structure for the now-obsolete classes B, C, and D to create class A during serialization, but you've got no way to tell in A::Serialize which of classes B, C, and D you're reading the old data for. You could figure that out if you could see the CRuntimeClass structure that CArchive::ReadObject just pulled off of the archive, but you can't. It's just kept in a local variable inside of ReadObject.

*sigh* So at this point, I've determined that the only way to do this is going to be the hard way. I have to read the obsolete classes and then convert them -- and all references to them -- to the base class.

On the other hand, it means I can go back to bed and stop worrying about it.