From: RB on
Well I have done a bit more study and experimenting and I have 3 questions.
Appreciate input from everyone as usual and hopefully Goran will also reply
since he has helped me the most on serialization and from going back and
rereading the context of his replies (after I studying and experimenting enough
to even understand them) I can tell the he has a firm grasp on what is going on
in MFC's serialization process. ,
My first question is, I can not help but wonder why MFC does not
generate the Doc class (derived from CDocument) with the Serial macros
as opposed to the Dyncreate. Like at first I was thinking of creating a whole
other class derived from CObject with implement serial just to hold members
I wanted a schema to, but then Goran gave an example of the mfc schema
with creating the DocClass with SERIAL and after he showed this to me I began
to wonder why MFC did not generate it that way ? Maybe because of ......
( Goran did not recommend it since this ties serialization with your document
class name, so you could have trouble changing it using of serializeClass or
operator<</>> and might be a problem if a major overhaul of serialization occurs)

2 other questions below, denoted with ************
one simple mfc comment queston and
another question on 2nd set of code at bottom.
-------Implementing DocClass Serial instead of Dyncreate------

class CFileHandlingDoc : public CDocument
{
// RB question what exactly does this MFC generated comment mean ?
// | | | ************
protected: // create from serialization only
CFileHandlingDoc();

// DECLARE_DYNCREATE(CFileHandlingDoc)
// RB doc creation with serial instead
DECLARE_SERIAL(CFileHandlingDoc)
..........
..........
}

// CFileHandlingDoc implementations

// IMPLEMENT_DYNCREATE(CFileHandlingDoc, CDocument)
// RB creating doc with serial instead

IMPLEMENT_SERIAL(CFileHandlingDoc, CDocument, 0)

// And in my DocClass serialize function
void CFileHandlingDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));
ar << VerData.Ver << VerData.CpyRt << VerData.Corp;
ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
ExpMap1.Serialize(ar);
}
else
{
ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));
ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
ExpMap1.Serialize(ar);
}
}
// The above compiles and works on writes and reads doc class
// CRuntime Data with no problems

++++++++appreciate comments on below +++++++++++++
So then I am later reading in MFC Under the Hood by
Laura Draxler on page 255 on the use of the SERIAL
macros for user classes derived from CObject, she says:
"It may seem inconsistent to you at first that document
class does not need the SERIAL macros, and it uses the
DYNCREATE macros instead, but the framework provides this
support automatically for the document class."
----
And I am thinking yes it does seem that document class
would use SERIAL. But I obviously have misunderstood
the the context of her saying the framework provides
serial for the doc class, since when I expanded the
dyncreate macro and inserted my schema of 0 (instead of
the default FFFF for dyncreate) the SerializeClass call
failed on a read in. So she must be referring to another
aspect of this. (see code expansion below)

///////////////////////////////////////////////////
// CFileHandlingDoc

// Seeing if framework provides serial under implement dyncreate ?
// IMPLEMENT_DYNCREATE(CFileHandlingDoc, CDocument)
// Expanded

CObject* __stdcall CFileHandlingDoc::CreateObject()
{
return new CFileHandlingDoc;
}

const CRuntimeClass CFileHandlingDoc::classCFileHandlingDoc =
{ "CFileHandlingDoc", sizeof(class CFileHandlingDoc),
0x0000, // !RB replaced the 0xFFFF,! ****************
CFileHandlingDoc::CreateObject,
((CRuntimeClass*)(&CDocument::classCDocument)), 0
};

CRuntimeClass* CFileHandlingDoc::GetRuntimeClass() const
{
return ((CRuntimeClass*)(&CFileHandlingDoc::classCFileHandlingDoc));
}
// End Implement_Dyncreate expansion
From: Goran on
On Jun 20, 4:51 pm, "RB" <NoMail(a)NoSpam> wrote:
> Well I have done a bit more study and experimenting and I have 3 questions.  

Ok, you are going ahead of you now. You are not supposed to know the
answer to all these questions so fast, you need 3 years MFC
serialization experience first, minimum! ;-)

> Appreciate input from everyone as usual and hopefully Goran will also reply
> since he has helped me the most on serialization and from going back and
> rereading the context of his replies (after I studying and experimenting enough
> to even understand them)  I can tell the he has a firm grasp on what is going on
> in MFC's serialization process. ,
>   My first question is, I can not help but wonder why MFC does not
> generate the Doc class (derived from CDocument) with the Serial macros
> as opposed to the Dyncreate.  

I guess simply because MFC does need _DYNCREATE (to create the
document at runtime, from a template), but does not need _SERIAL,
because MFC simply calls Serialize(ar); on the document class.
Clearly, to simply call Serialize on an object, you don't need any of
these macros.

Now, remember, _SERIAL gives serialization operators >> and <<, and
schema number. Since every serialization code I've seen so far has
"global" document version, and some "magic" file type marker (your own
does it), I proposed the use of DECLARE_SERIAL and SerializeClass
simply because that will give you both, without reaching out for a
custom solution. SerializeClass will store class name in the
serialization stream (that's your "magic" file type marker), and will
also store the version (that's... well, version).

In all honesty: I came up with this idea of my own and I don't know if
someone else does that. But I see no flaw in it. BTW, IIRC ;-)... If
there's an error in the file (e.g. it's really something else, not
your file), SerializeClass throws an exception with
CArchiveException::badClass. That gets nicely reported in document's
ReportStoreLoadException.

> Like at first I was thinking of creating a whole
> other class derived from CObject with implement serial just to hold members
> I wanted a schema to, but then Goran gave an example of the mfc schema
> with creating the DocClass with SERIAL and after he showed this to me I began
> to wonder why MFC did not generate it that way ? Maybe because of ......
>   ( Goran did not recommend it since this ties serialization with your document
>    class name, so you could have trouble changing it using of serializeClass or
>    operator<</>> and might be a problem if a major overhaul of serialization occurs)
>
> 2 other questions below,  denoted with ************
> one simple mfc comment queston and
> another question on 2nd set of code at bottom.
> -------Implementing DocClass Serial instead of Dyncreate------
>
> class CFileHandlingDoc : public CDocument
> {
>  // RB question what exactly does this MFC generated comment mean ?
>                        //              |     |      |     ************
> protected:        // create from serialization only
> CFileHandlingDoc();

Stupid and untrue wizard comments. ;-) I guess it wants to say: ctor
is protected because this will be created from serialization only. But
document will be created at runtime when creating a new document, too,
so it's untrue that it's from serialization only. Only when document
is open, "dynamic creation" AND seralization happen.

> // DECLARE_DYNCREATE(CFileHandlingDoc)
> // RB doc creation with serial instead
>    DECLARE_SERIAL(CFileHandlingDoc)
>  ..........
>  ..........
>
> }
>
> // CFileHandlingDoc implementations
>
> // IMPLEMENT_DYNCREATE(CFileHandlingDoc, CDocument)
> // RB creating doc with serial instead
>
>   IMPLEMENT_SERIAL(CFileHandlingDoc, CDocument, 0)

Wow, wow, not like that! You need SERIALIZABLE_SCHEMA in there. I
always start with SERIALIZABLE_SCHEMA|1, but I guess you can start
with 0 as well.

>
> // And in my DocClass serialize function
> void CFileHandlingDoc::Serialize(CArchive& ar)
> {
>  if (ar.IsStoring())      
>   {
>    ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));

No, that goes in front of the "if". Otherwise, you're calling it twice
for no reason. See below, you do it already.

>    ar << VerData.Ver << VerData.CpyRt << VerData.Corp;  
>    ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
>    ExpMap1.Serialize(ar);    
>   }                                        
>  else              
>   {
>    ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));
>    ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
>    ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
>    ExpMap1.Serialize(ar);
>   }    }                    
>
> // The above compiles and works on writes and reads doc class
> // CRuntime Data with no problems
>
> ++++++++appreciate comments on below +++++++++++++
> So then I am later reading in MFC Under the Hood by
> Laura Draxler on page 255 on the use of the SERIAL
> macros for user classes derived from CObject, she says:
> "It may seem inconsistent to you at first that document
> class does not need the SERIAL macros, and it uses the
> DYNCREATE macros instead, but the framework provides this
> support automatically for the document class."

I believe that this stems from a common misconception that you need
XXX_SERIAL if you want to use serialization. Not necessarily. If all
you want is to call Serialize, do it and forget XXX_SERIAL (in fact,
you can often forget _DYNAMIC and _DYNCREATE, too). But schema changes
get harder then ;-).

As I explained before, MFC calls Serialize on the instance of the
document class, but that's the end of it. It certainly does __not__
provide any additional support for document's serialization (logical,
how can it know about stuff I want to save?). So if it's not calling
SerializeClass, and it is not using << / >>, it does not need
XXX_SERIAL, so why do it?

I'd say that the explanation in the book is confusing at best.

Goran.
From: Joseph M. Newcomer on
See below...
On Sun, 20 Jun 2010 10:51:39 -0400, "RB" <NoMail(a)NoSpam> wrote:

>
>Well I have done a bit more study and experimenting and I have 3 questions.
>Appreciate input from everyone as usual and hopefully Goran will also reply
>since he has helped me the most on serialization and from going back and
>rereading the context of his replies (after I studying and experimenting enough
>to even understand them) I can tell the he has a firm grasp on what is going on
>in MFC's serialization process. ,
> My first question is, I can not help but wonder why MFC does not
>generate the Doc class (derived from CDocument) with the Serial macros
>as opposed to the Dyncreate.
****
It does seem odd, but it also means that they are not assuming you require serialzation.
I'd be in the other fix, having to constantly get rid of DECLARE/IMPLEMENT_SERIAL because
I don't ever want to use the MFC serialization mechanism.

It is often a coin-toss as to which choice is made.
*****
> Like at first I was thinking of creating a whole
>other class derived from CObject with implement serial just to hold members
>I wanted a schema to, but then Goran gave an example of the mfc schema
>with creating the DocClass with SERIAL and after he showed this to me I began
>to wonder why MFC did not generate it that way ? Maybe because of ......
> ( Goran did not recommend it since this ties serialization with your document
> class name, so you could have trouble changing it using of serializeClass or
> operator<</>> and might be a problem if a major overhaul of serialization occurs)
>
>2 other questions below, denoted with ************
>one simple mfc comment queston and
>another question on 2nd set of code at bottom.
>-------Implementing DocClass Serial instead of Dyncreate------
>
>class CFileHandlingDoc : public CDocument
>{
> // RB question what exactly does this MFC generated comment mean ?
> // | | | ************
>protected: // create from serialization only
> CFileHandlingDoc();
>
>// DECLARE_DYNCREATE(CFileHandlingDoc)
>// RB doc creation with serial instead
> DECLARE_SERIAL(CFileHandlingDoc)
> ..........
> ..........
>}
>
>// CFileHandlingDoc implementations
>
>// IMPLEMENT_DYNCREATE(CFileHandlingDoc, CDocument)
>// RB creating doc with serial instead
>
> IMPLEMENT_SERIAL(CFileHandlingDoc, CDocument, 0)
>
>// And in my DocClass serialize function
>void CFileHandlingDoc::Serialize(CArchive& ar)
>{
****
I have often felt this whole mechanism was designed by a totally clueless programmer.
Probably the same twit that decided that we only needed UpdateData with a BOOL to indicate
direction. I keep seeing this kind of horrid overloading of concepts in designs and
wonder how it is that the same mistake gets repeated so often.

In a sane worled, there would be SerializeIn(CArchive & ar) and SerializeOut(CArchive &
ar). And the stupid IsStoring method would not have to exist.

I think these are the same people who think that creating more files is evil.
****
> if (ar.IsStoring())
> {
> ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));
> ar << VerData.Ver << VerData.CpyRt << VerData.Corp;
> ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
> ExpMap1.Serialize(ar);
> }
> else
> {
> ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));
> ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
> ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
> ExpMap1.Serialize(ar);
> }
>}
>// The above compiles and works on writes and reads doc class
>// CRuntime Data with no problems
>
>++++++++appreciate comments on below +++++++++++++
>So then I am later reading in MFC Under the Hood by
>Laura Draxler on page 255 on the use of the SERIAL
>macros for user classes derived from CObject, she says:
>"It may seem inconsistent to you at first that document
>class does not need the SERIAL macros, and it uses the
>DYNCREATE macros instead, but the framework provides this
>support automatically for the document class."
>----
>And I am thinking yes it does seem that document class
>would use SERIAL. But I obviously have misunderstood
>the the context of her saying the framework provides
>serial for the doc class, since when I expanded the
>dyncreate macro and inserted my schema of 0 (instead of
>the default FFFF for dyncreate) the SerializeClass call
>failed on a read in. So she must be referring to another
>aspect of this. (see code expansion below)
****
I have no idea. Serialize is so badly done I cannot imagine why I would ever want to use
it. I knew about most of its problems in 1979, when we designed the LG system (think: XML
done right), and I was apalled to find MFC had reinvented all the problems we knew were
horrid problems decades before.

All data should be tagged, self-identifying data. XML is a good representation for this.
****
>
>///////////////////////////////////////////////////
>// CFileHandlingDoc
>
>// Seeing if framework provides serial under implement dyncreate ?
>// IMPLEMENT_DYNCREATE(CFileHandlingDoc, CDocument)
>// Expanded
>
>CObject* __stdcall CFileHandlingDoc::CreateObject()
> {
> return new CFileHandlingDoc;
> }
>
>const CRuntimeClass CFileHandlingDoc::classCFileHandlingDoc =
> { "CFileHandlingDoc", sizeof(class CFileHandlingDoc),
> 0x0000, // !RB replaced the 0xFFFF,! ****************
****
Why? Just curious.
****
> CFileHandlingDoc::CreateObject,
> ((CRuntimeClass*)(&CDocument::classCDocument)), 0
> };
>
>CRuntimeClass* CFileHandlingDoc::GetRuntimeClass() const
> {
> return ((CRuntimeClass*)(&CFileHandlingDoc::classCFileHandlingDoc));
> }
>// End Implement_Dyncreate expansion
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: RB on
> Goran wrote
> I guess simply because MFC does need _DYNCREATE (to create the
> document at runtime, from a template), but does not need _SERIAL,
> because MFC simply calls Serialize(ar); on the document class.
> Clearly, to simply call Serialize on an object, you don't need any of
> these macros.

RB replied
Hey guy, thanks for replying. Yes I understand that the document doesn't
necessarily "need" the Serial macro to write to file, but I couldn't understand
why MFC would want to short the full capability of the schema in the doc.
Or at least say why they did not. It just doesn't at first make sense from my
limited view point, although see below for more.

> Goran wrote
> Now, remember, _SERIAL gives serialization operators >> and <<, and
> schema number. Since every serialization code I've seen so far has
> "global" document version, and some "magic" file type marker (your own
> does it), I proposed the use of DECLARE_SERIAL and SerializeClass
> simply because that will give you both, without reaching out for a
> custom solution. SerializeClass will store class name in the
> serialization stream (that's your "magic" file type marker), and will
> also store the version (that's... well, version).

RB replied
Exactly and it seems to me that if all the help text points towards using
the full power of serial in a CObject derived class why would the
document derivative not be included since to me it is the base of the
whole serialization process. Like if I have CMapStringToString's
Runtime data and schema written to my file but I don't have my
doc derivative's runtime data in the file unless I learn it from you on a
news group, or my member data's schema unless I do what the help
text says and put them in another CObject derived class with the full
power of Serial macros. The whole thing just seems odd to me, unless
for they were not wanting to tie the whole thing to the doc derivative's
name as you previously pointed out, and if so why didn't they say so.
See more on this lower down.

> Goran wrote
> In all honesty: I came up with this idea of my own and I don't know if
> someone else does that. But I see no flaw in it. BTW, IIRC ;-)... If
> there's an error in the file (e.g. it's really something else, not
> your file), SerializeClass throws an exception with
> CArchiveException::badClass. That gets nicely reported in document's
> ReportStoreLoadException.

RB replied
Well actually about the same time you showed it to me I got out an old
book I had bought used quite a while ago "MFC Programming by Alan Feuer"
and I looked thru it and found the same idea (creating the doc derivative with
the Serial macros ). But other than you and this one book, I have not seen it
elsewhere searching on the net or other MFC books I have.

>> RB previously wrote
>> IMPLEMENT_SERIAL(CFileHandlingDoc, CDocument, 0)

> Goran wrote
>Wow, wow, not like that! You need SERIALIZABLE_SCHEMA in there.
> I always start with SERIALIZABLE_SCHEMA|1, but I guess you can start
> with 0 as well.

RB replied
Yes you showed me correct, I did the zero thing. Not much thought involved
just figured I would start with zero since CMapStringToString does. Actually
I have read about OR-ing the VERSIONABLE_SCHEMA define with the
file schema, but I haven't yet gotten underneath the rhyme and reason of it.

>> RB previously wrote
>> if (ar.IsStoring())
>> {
>> ar.SerializeClass(RUNTIME_CLASS(CFileHandlingDoc));

> Goran wrote
> No, that goes in front of the "if". Otherwise, you're calling it twice
> for no reason.

RB replied
Well yes you are correct. I did this because I had wanted to keep the
order of Class runtime writes in order before their pertinant data writes.
Of course obviously I could just skip this on the first object being written,
but on all the other's CmStS etc, I would have to put them in both if else
loops to keep the runtime data right with the actual object data (unless it
was heap item and I used the ptr operator methods which does the WriteClass
and the data write both together).

>> Goran previously wrote
>>Notes:
>>* this ties serialization with your document class name, so you will
>>have trouble changing it

RB replied, well if I understand correctly what you meant with that
statement, THIS would to me be a conceivable reason MFC designers
did not include the Serial macro on the doc derivative. Because if you
ever changed the name of you doc derivative in a future version you would
never be able to read an old file back (with serialize anyhow) into a new
version with a different doc class name. So maybe they thought it better
to aim the help texts at a separate CObject derivative for SERIAL creation.
That way if you changed the name of your app (slightly or otherwise) then
the AppWizard generations would not break the doc derivative class's
name tie to the older versions.


>> Goran previously wrote
>> (That might be a problem when/if a major overhaul of serialization
>> occurs).

RB replied
Not quite sure exactly what you meant by a major overhaul of serialization.
I am assuming you mean if I change my Doc derivatives name ?

I know all of this has helped me learn more about the whole MFC structure
so that is a plus. But at this point I kinda feel like "not" serializing the
schema and class runtime "name" data of my doc derivative. In fact I
think I would feel more comfortable going back with the MFC dyncreate creation
and just writing out my doc data members to file first before any CObject
derivatives that follow like CmStS or any others. That way I could just
use my own schema system that is not tied to the doc derivative's name.

As always I have learned a great deal from your replies. For a person
wanting to learn, the newsgroup setup and people like you, Joe, Giovanni
and all the other guys are a priceless help.
RB

From: RB on

Hey Joe thanks for replying

> It does seem odd, but it also means that they are not assuming you require serialzation.
> I'd be in the other fix, having to constantly get rid of DECLARE/IMPLEMENT_SERIAL
> because I don't ever want to use the MFC serialization mechanism.
> ****

Well actually that is a very conceivable reason for not creating serial, so that makes two
reasons so far. Since as Goran had pointed out to me serial ties the doc derivative class's
name to the serialize schema. So I surmise that in future apps that had a slightly different
name and doc derivative class name would break the Runtime class data match for a read
from a newer version. That makes sense as to why the help texts always seem to point to
making a separate CObject derivative for SERIAL creations.
The thing that got me is why they did not be more clear about it and say it ?

> In a sane worled, there would be SerializeIn(CArchive & ar) and SerializeOut(CArchive &
> ar). And the stupid IsStoring method would not have to exist.
> I think these are the same people who think that creating more files is evil.
> ****

Well as far as the mfc serialize scheme goes I can see that putting the storing and
loading loops together helps keep the same order of writes and reads in my face
so it might be visually less error prone. But I guess you could do that in your
method also so that doesn't hold much water.
But actually now I feel like I will use the dyncreate method and devise my own
schema method for doc derivative members that need stored and keep the mfc
serialize runtime class method for CmStS or any CObject derivatives I may need
to create Serial. At least for the time being. As I get more experience under my
belt I may forgo all of this ( like you) and just write my own persistence functions.

>>const CRuntimeClass CFileHandlingDoc::classCFileHandlingDoc =
>> { "CFileHandlingDoc", sizeof(class CFileHandlingDoc),
>> 0x0000, // !RB replaced the 0xFFFF,! ****************
> ****
> Why? Just curious.
> ****

Nothing except having read the Laura said the framework supported serialize in the
doc class without creating with Serial, I wanted to see if I could insert my schema of
zero into the expanded dyncreate macro and then write and read it back. And I found
that it did not work, so she must have been referring to some other aspect of
framework support. It did write ok, I could see it in the dump. But it failed to read it
back I presume since it did not have all of the serial macro capability to compare the
written Class runtime data.