1 Introduction The Visual C 6.0 language development environment provides the serialization and data version control function of the input and output in the MFC as a CARCHIVE class. In general, with the upgrade of the software, the corresponding input and output will also change, how to ensure the affinity between multiple versions of software and multiple input and output data. For example, when the user uses the version of the software, the input provided is the output of version 2.0 software, what is the result? How does the same version 2.0 how to handle the 1.0 version of the data? Indeed, users can define a set of their own file formats to provide solutions for the above-mentioned troubles. Many software are doing so, but if you have a small size, function is single, the data format Unconsciously (of course, to ensure the correct output is correct), then it seems to be too cumbersome to specify its own data file format. Use Carchive to simplify the preparation of such software. 2 CARCHIVE Version Control Method When you use Declare_Serial and Implement_serail macro, you declare the static structural members of a CRUNTIMECLASS class in your class, which can record the version number you specify. Note Although M_Wschema seems to be a word in accordance with naming agreements, it is actually an UINT. When the serialization output, the class information (ie the low words of the class name and version number, the high character is the flag) is written to the data file, while serialization is input when carchive :: readclass () and carchive :: readObject () This information and the back object data rebuild objects, returns to the object pointer. All this happens in the statement similar to POBJECT << AR; If CruntimeClass detects the record number in the data file and the version number of the class (ie, the version number recorded in the CRUNTIMECLASS member) is inconsistent, depending on whether you set the version number, you specify the versionable_schema flag has different processing: if you do not set the flag CARCHIVE :: readclass () will throw an exception of a CARCHIVEXCEPTION type; if you set it, then carchive :: readclass () will successfully return the corresponding CRUntimeClass class object, while carchive :: readObject () will create a serial class object And returns the object and version number (in the CARCHIVE:: M_NObjectShema member, the member is a public type, you can directly access or call CARCHIVE:: GetObjectSchema () Return. If you call carchive :: getObjectSchema (), pay attention to this function can only Call once!). Although all this work is very good, the problem is not as simple as it looks, because your software will change in different versions. Because carchive :: readclass () is based on class names, CARCHIVE: ReadObject () is also based on CRUntimeClass class members objects returned according to CARCHIVE:: ReadClass () Create a serial class object (CRUNTIMECLASS member) It is a static member of a serial class). Therefore, if there is no corresponding serial class at all in the new software, then it must be fails! The three-class changes have the impact of version control. The upgrade needs to scale or change the interface of the class. From the serial class definition, there are various modes to extend new features: (1). Modify the original class definition, Change the name
At this time, the original class does not exist, then CARCHIVE cannot create a corresponding object according to the data file, so the new version is completely unable to compatibility, like two completely unrelated software. Not only the old software cannot identify and process data files for new software, the new software is also unable to identify and process data files for old software. You need to identify the conversion of the processing data file, and the MFC cannot identify the process. (2). Modify the original class definition, but the class name keeps this time, CARCHIVE can create an object according to the old data file, but in the new version of the serial class, CARCHIVE :: serailize () needs to do different input and output according to the version. deal with. Since the class definition has changed, the processing of the old data may differ from the same version processing method, and it is necessary to engage in it. The old version can identify a new version, but it is generally unable to process. (3). Support extended function from the original class
This approach takes full advantage of the characteristics of the C language, the new version can process different version data files according to the version number and still generate older versions of data files, which is very compatibility. But the old version cannot identify the new version of the data file, and it will not be processed. In comparison, the mode (1) is more rude, and the compatibility problem (2) and (3) are considered completely regardless of the compatibility problem, but the programming of the mode (2) is complex, the serial class is for the version. Number of process code, while the method (3) uses the characteristics of the C language to handle multi-version data issues, as long as the virtual function is available. But if the software upgrade is a lot, it will rise from 1.0 to 8.0, then it is obviously a bit uncomfortable. Another important insufficient is that the old version cannot recognize the new version of the data file, and only the data file format is wrong. 4 Examples The following example is the upgrade code, using mode (3) to handle different versions:
// Note: Although some MFC code is used, it is not used for simple use.
/ / The initialization code generated by the guide, so support for MFC is incomplete!
/ / Statement of the header file of the object
#ifndef __lcg_Object_h__
#define __lcg_Object_h__
#include
// Version 1.0 uses objects
Class COBject1: Public COBJECT
{
Declare_serial (CObject1)
PUBLIC:
COBJECT1 ();
Virtual Void Serialize (CARCHIVE & A);
Virtual Bool Isokver (Uint NVER);
CSTRING M_STR;
}
// version (2) Extended version 1.0 class
Class COBject2: Public COBJECT1
{
Declare_serial (COBJECT2)
PUBLIC:
COBJECT2 ();
Virtual Void Serialize (CARCHIVE & A);
Virtual Bool Isokver (Uint NVER);
CString M_STR2; // Version 2.0 Tips
}
#ENDIF
// object's .cpp file
#include "object.h"
Implement_serial (COBJECT1, COBJECT, (Versionable_Schema | 1))
COBJECT1 :: COBJECT1 ()
{
m_str = "COBJECT1 MSG / N";
}
// 1.0 version of the version check function, version check function is to be declared as virtual,
// This actual object may be checked, otherwise, even if the object is correct,
/ / However, since the call pointer is a pointer of the base class, the check result is incorrect! Bool COBject1 :: Isokver (uint NVER)
{
Return NVER == 1;
}
Void COBject1 :: Serialize (CARCHIVE & A)
{
IF (ar.isstoring ())
{
Ar << (int) m_str.getLength ();
ar.writeString (m_str);
}
Else
{
IF (! isokver (ar.m_nobjectschema))
{
AfxMessageBox ("COBJECT1 gets incorrect version!");
Return;
}
INT NLEN; AR >> NLEN;
Ar.read (M_Str.getBuffer (NLEN), NLEN;
}
}
// version 2.0 object
Implement_serial (COBJECT2, COBJECT1, (VersionAble_schema | 2)))
COBJECT2 :: COBJECT2 ()
{
m_Str2 = "COBJECT2 MSG / N";
}
Void COBject2 :: Serialize (CARCHIVE & A)
{
COBJECT1 :: Serialize (ar);
IF (ar.isstoring ())
{
Ar << (int) m_str2.getlength ();
ar.writeString (m_Str2);
}
Else
{
IF (! isokver (ar.m_nobjectschema))
{
AfxMessageBox ("COBJECT2 gets incorrect version!");
Return;
}
INT NLEN; AR >> NLEN;
Ar.read (M_Str2.getBuffer (NLEN), NLEN;
}
}
Bool COBject2 :: ISOKVER (UINT NVER)
{
Return NVER == 2;
}
// Main program, use different objects for different versions
#include
#include "object.h"
#pragma comment (Lib, "MSVCRT.LIB")
Int WinApi Winmain (Hinstance Hinst, Hinstance Hnull,
LPSTR LPCMDLINE, INT NCMDSHOW)
{
Afxwininit (Hinst, Hnull, LPCMDLINE, NCMDSHOW); // MFC initialization
Cfile File ("try1.txt", cfile :: moderad);
CARCHIVE AR (& File, Carchive :: Load);
COBJECT * PB = NULL;
COBJECT1 * PB1 = NULL;
COBJECT2 * PB2 = NULL;
Char szmsg [128];
Bool Berror = false;
// If the data file format is incorrect, it will trigger an exception!
Try {
AR >> PB;
}
Catch (CARCHIVEEXCEPTION, PE)
{
Berror = true; // error!
PE-> getErrorMessage (SZMSG, SIZEOF (SZMSG)); // Get prompt information
DELETE_EXCEPTION (PE);
AfxMessageBox (SZMSG);
END_CATCH
IF (Berror)
Return 0;
/ / Different classes according to different versions
Switch ((PB-> getRuntimeclass () -> m_wschema) & ~ (Versionable_Schema))
{
Case 1:
PB1 =
(COBJECT1 *) AFXDYNAMICDOWNCAST (runtime_class (cobject1), pb);
AfxMessageBox (PB1-> M_STR);
Break;
Case 2:
PB2 =
(COBJECT2 *) AFXDYNAMICDOWNCAST (runtime_class (cobject2), pb);
AfxMessageBox (PB2-> m_STR2);
Break;
DEFAULT:
AFXMessageBox ("Unkown Object!");
Break;
}
Delete PB;
Return 0;
}
5. Conclusion The above ideas and examples are a simple simulation of general software version control. In fact, there is more complex, and even need to generate private data for version control, but for small-scale software that requires rapid development, the above method can be used as One choice.
Reference 1 Visual C 6.0 MSDN 2 Visual C 6.0 MFC Source Code