I have two serialize operator overloads:
friend CArchive& operator<<(CArchive& rArchive, S_MEMORIAL_INFO const& rsMI)
{
return rArchive << rsMI.strHost
<< rsMI.strCohost
<< rsMI.strZoomAttendant
<< rsMI.strChairman
<< rsMI.strPrayerOpen
<< rsMI.strPrayerClose
<< rsMI.strSpeaker
<< rsMI.strImagePath
<< rsMI.strTextBeforeImage
<< rsMI.strTextAfterImage
<< rsMI.iImageWidthAsPercent
<< rsMI.iSongOpen
<< rsMI.iSongClose;
}
friend CArchive& operator>>(CArchive& rArchive, S_MEMORIAL_INFO& rsMI)
{
return rArchive >> rsMI.strHost
>> rsMI.strCohost
>> rsMI.strZoomAttendant
>> rsMI.strChairman
>> rsMI.strPrayerOpen
>> rsMI.strPrayerClose
>> rsMI.strSpeaker
>> rsMI.strImagePath
>> rsMI.strTextBeforeImage
>> rsMI.strTextAfterImage
>> rsMI.iImageWidthAsPercent
>> rsMI.iSongOpen
>> rsMI.iSongClose;
}
But I now wat to introduce version tracking so that I can cope with new fields without causing crashes in my software for users.
So now I would like:
friend CArchive& operator>>(CArchive& rArchive, S_MEMORIAL_INFO const& rsMI)
{
WORD wVersion{};
rArchive >> wVersion
>> rsMI.strHost
>> rsMI.strCohost
>> rsMI.strZoomAttendant
>> rsMI.strChairman
>> rsMI.strPrayerOpen
>> rsMI.strPrayerClose
>> rsMI.strSpeaker;
rsMI.strTheme.Empty();
if(wVersion >= 2)
rArchive >> rsMI.strTheme;
return rArchive >> rsMI.strImagePath
>> rsMI.strTextBeforeImage
>> rsMI.strTextAfterImage
>> rsMI.iImageWidthAsPercent
>> rsMI.iSongOpen
>> rsMI.iSongClose;
}
friend CArchive& operator<<(CArchive& rArchive, S_MEMORIAL_INFO& rsMI)
{
WORD wVersion = 2;
return rArchive << wVersion
<< rsMI.strHost
<< rsMI.strCohost
<< rsMI.strZoomAttendant
<< rsMI.strChairman
<< rsMI.strPrayerOpen
<< rsMI.strPrayerClose
<< rsMI.strSpeaker
<< rsMI.strTheme
<< rsMI.strImagePath
<< rsMI.strTextBeforeImage
<< rsMI.strTextAfterImage
<< rsMI.iImageWidthAsPercent
<< rsMI.iSongOpen
<< rsMI.iSongClose;
}
How can I now cope with the fact that for some users there is no WORD value there in the archive?
With hindsight I would have designed the serialization to write a version number right from the outset, but too late for that now.
As noted in the comments, the problem is that when reading
wVersionfrom the archive this removes two bytes from theCStringobject following.CArchiveperforms its own buffer management. The class definition contains several member variables for this, and it's quite easy to find out what they are doing. These members are protected though, so we need to define a derived class, containing a member which sets the current buffer pointer two bytes back:Then you can use this class in your code like this:
The
(CArchiveHlp*)cast is wrong in some way because the actual object is notCArchiveHlp(adynamic_castwould fail here), however the classes are almost identical, and theGoBack2()member is not virtual (so no v-table), therefore you can call it without any problem - it callsCArchiveHlpcode for aCArchiveclass instance, whose data in memory are identical.It's tested and works.