MFC technology insider series (III)-type identification and Dynamic Creation Technology insider during the implementation period of MFC

Source: Internet
Author: User

//////////////////////////////////////// //////////////////////////////////////// ////
/********* Article series: MFC technology insider series ***********/
/************** Inside the MFC Technology series (iii )***********/
/* Article Title: MFC implementation period type identification and dynamic creation technical insider */
/* Copyright (c) 2002 bigwhite */
/* All Rights Reserved */
/******* Keyword: type identification during the execution period, dynamic creation *******/
/* Time: 2002.7.23 */
/* Note: the source code of the program involved in this article is in Microsoft */
/Visual Studio. NET Enterprise effecect edition/
/* The Source Code provided by the Development Kit */

//////////////////////////////////////// //////////////////////////////////////// ////////////////
Introduction:
As we all know, Microsoft's MFC application framework is built on a series of advanced programming technologies. For example, message ing, Command Transmission, type identification and dynamic creation during execution, and document serialization. Among them, the type identification and dynamic creation technology during the execution period is one of the most important technologies. Microsoft has implemented this mechanism using some mysterious Macros in MFC, but it has become a major difficulty for beginners who are studying MFC programming, so in this article, I will explore the details in detail.

Body:
The type identification and Dynamic Creation Technology of the MFC execution period is based on the cruntimeclass structure and a series of mysterious macro implementations. The premise of dynamic creation technology is the establishment of the type recognition network during the execution period. Next let's take a look at how the type recognition network is established during the execution period?
//////////////////////////////////////// ///////////
/* 1. cruntimeclass structure overview */
//////////////////////////////////////// ///////////
Note: The cruntimeclass structure is defined in ../Visual Studio. NET/vc7/atlmfc/include/afx. h.
// Object type information
Struct cruntimeclass
{
// Attributes
Lpcstr m_lpszclassname;
Int m_nobjectsize;
Uint m_wschema; // schema Number of the loaded class
Cobject * (Pascal * m_pfncreateobject) (); // null => abstract class
# Ifdef _ afxdll
Cruntimeclass * (Pascal * m_pfngetbaseclass )();
# Else
Cruntimeclass * m_pbaseclass;
# Endif
// Operations
Cobject * Createobject ();
Bool isderivedfrom (const cruntimeclass * pbaseclass) const;

// Dynamic Name Lookup and Creation
Static cruntimeclass * Pascal fromname (lpcstr lpszclassname); // For ANSI
Static cruntimeclass * Pascal fromname (lpcwstr lpszclassname); // for Unicode
Static cobject * Pascal Createobject (lpcstr lpszclassname); For ANSI
Static cobject * Pascal Createobject (lpcwstr lpszclassname); // for Unicode
// Implementation
Void store (carchive & AR) const;
Static cruntimeclass * Pascal load (carchive & AR, uint * pwschemanum );

// Cruntimeclass objects linked together in simple list
Cruntimeclass * m_pnextclass; // Linked List of Registered classes
Const afx_classinit * m_pclassinit;
};

//////////////////////////////////////// /////////////////
/* I. 2. Components of the type recognition network during the execution period */
//////////////////////////////////////// //////////////////
In the cruntimeclass structure, the members related to the establishment of the type identification network during the execution period are as follows:
Struct cruntimeclass
{
...//
Lpcstr m_lpszclassname;
Cruntimeclass * m_pbaseclass;

}


//////////////////////////////////////// //////////////////
/* 1. 3. Establish a connection for the Type Recognition network during the execution period */
//////////////////////////////////////// //////////////////
MFC adds two macros to The. h and. cpp files of each class that has the ability to recognize the type of execution period. They are:
// In XX. h
Class class_name
{
Declare_dynamic (class_name)
...//
}
// In XX. cpp
Implement_dynamic (class_name, base_class_name)
...//
What will these two macros look like? Let's look at its source code!
Note: These two macros are defined in ../Visual Studio. NET/vc7/atlmfc/include/afx. h.

# Define declare_dynamic (class_name )/
Public :/
Static const cruntimeclass class # class_name ;/
Virtual cruntimeclass * getruntimeclass () const ;/

# Define implement_dynamic (class_name, base_class_name )/
Implement_runtimeclass (class_name, base_class_name, 0 xFFFF, null, null)


# Define implement_runtimeclass (class_name, base_class_name, wschema, pfnnew, class_init )/
Afx_comdat const cruntimeclass class_name: Class ## class_name = {/
# Class_name, sizeof (class class_name), wschema, pfnnew ,/
Runtime_class (base_class_name), null, class_init };/
Cruntimeclass * class_name: getruntimeclass () const/
{Return runtime_class (class_name );}/
Related macros are defined as follows:
# Define runtime_class (class_name) _ runtime_class (class_name)
# DEFINE _ runtime_class (class_name) (cruntimeclass *) (& class_name: Class ## class_name ))

See it! These two macros work together to insert something into each class. As for what kind of macros, let's take a look!

Next I will use a specific class to show how the type recognition network is established during the following execution period.
Take the cmainframe class of an MDI application as an example:
// In maimfrm. h
Class cmainframe: Public cmdiframewnd
{
Declare_dynamic (cmainframe)
...//
}

// In maimfrm. cpp
Implement_dynamic (cmainframe, cmdiframewnd)
...//

After expansion, you must:
// In maimfrm. h
Class cmainframe: Public cmdiframewnd
{
Public:
Static const cruntimeclass classcmainframe;
Virtual cruntimeclass * getruntimeclass () const;
...//
}

// In maimfrm. cpp
 
Afx_comdat const cruntimeclass cmainframe: classcmainframe = {cmainframe, sizeof (classcmainframe), 0 xFFFF, null, (cruntimeclass *) (& cmdiframewnd: callback), null, null };

Cruntimeclass * cmainframe: getruntimeclass () const
{Return & cmainframe: classcmainframe ;}
The code above shows that the implement_dynamic macro initializes and implements the cruntimeclass classcmainframe and cruntimeclass * getruntimeclass () const static functions added to the cmainframe.
The most important point is that the cruntimeclass * m_pbaseclass of the classcmainframe object of the cmainframe class is assigned an "indirect" value as & cmdiframewnd: classcmdiframewnd, which is the static cruntimeclass member of.
And so on:
The cruntimeclass * m_pbaseclass member of cmdiframewnd: classcmdiframewnd is assigned an "indirect" value
Its base class & cframewnd: classcframewnd;
....
....
Cruntimeclass * m_pbaseclass, a member of cve-target: classc1_target, is assigned "indirectly" as & cobject: classcobject;
Cobject does not have a base class. So what is the value assigned to the cruntimeclass * m_pbaseclass member of cobject: classcobject? What is the special runtime-class structure for cobject (no base class) in MFC framework?

Note: The sequence of the base class of the cmainframe class is cmdiframewnd --> cframewnd --> cwnd --> cframetarget --> cobject

// In afx. h
// Class cobject is the root of all compliant objects
Class afx_novtable cobject
{
Public:
Virtual cruntimeclass * getruntimeclass () const;
Static const cruntimeclass classcobject;
...//
}
 
// In objcore. cpp
// Special runtime-class structure for cobject (no base class)
Const struct cruntimeclass cobject: classcobject =
{"Cobject", sizeof (cobject), 0 xFFFF, null, null };

Cruntimeclass * cobject: getruntimeclass () const
{
Return _ runtime_class (cobject );
}
 
//////////////////////////////////////// ///////////////
/* 1. 4. Application of the network type recognition during the execution period */
//////////////////////////////////////// //////////////
The implementation phase of the type identification network has been established, it will play an important role in the MFC framework, here is an example of its application:
Cobject: The iskindof function is a function completed using the network. Let's take a look at its source code:
// In objcore. cpp
Bool cobject: iskindof (const cruntimeclass * Pclass) const
{
Assert (this! = NULL );
// It better be in valid memory, at least for cobject size
Assert (afxisvalidaddress (this, sizeof (cobject )));
// Simple Si case
Cruntimeclass * pclassthis = getruntimeclass ();
Return pclassthis-> isderivedfrom (Pclass );
}
Bool cruntimeclass: isderivedfrom (const cruntimeclass * pbaseclass) const
{
Assert (this! = NULL );
Assert (afxisvalidaddress (this, sizeof (cruntimeclass), false ));
Assert (pbaseclass! = NULL );
Assert (afxisvalidaddress (pbaseclass, sizeof (cruntimeclass), false ));

// Simple Si case
Const cruntimeclass * pclassthis = this;
# Ifdef _ afxdll
For (;;)
# Else
While (pclassthis! = NULL)
# Endif
{
If (pclassthis = pbaseclass)
Return true;
# Ifdef _ afxdll
If (pclassthis-> m_pfngetbaseclass = NULL)
Break;
Pclassthis = (* pclassthis-> m_pfngetbaseclass )();
# Else
Pclassthis = pclassthis-> m_pbaseclass;
# Endif
}
Return false; // encoded ed to the top, no match
}

//////////////////////////////////////// //////////
/* 2.1. dynamic creation technology during the execution period */
//////////////////////////////////////// //////////
After talking about the establishment of the type identification network during the implementation period, let's take a look at another important technology-the dynamic creation technology during the implementation period. This technology is widely used and is the main framework in your SDI, the view and its corresponding documents, as well as the Child Framework in the MDI, and its corresponding documents are all generated using dynamic creation technology.
During the execution period, the dynamic creation technology also utilizes the cruntimeclass structure and a pair of corresponding macros declare_dyncreate (class_name)
And implement_dyncreate (class_name, base_class_name );
Let's take a look at the definitions of these two macros:

# Define declare_dyncreate (class_name )/
Declare_dynamic (class_name )/
Static cobject * Pascal Createobject ();
# Define implement_dyncreate (class_name, base_class_name )/
Cobject * Pascal class_name: Createobject ()/
{Return New class_name ;}/
Implement_runtimeclass (class_name, base_class_name, 0 xFFFF ,/
Class_name: Createobject, null)
It should be seen that the type recognition network during the execution period is the basis for dynamic creation technology during the execution period.

//////////////////////////////////////// ///////////////////
/* II. 2 dynamic creation of technical components during the execution period */
//////////////////////////////////////// ///////////////////

The following lists the cruntimeclass structure members related to the dynamic creation technology during the execution period:
// Object type information
Struct cruntimeclass
{
Cobject * (Pascal * m_pfncreateobject) (); // null => abstract class
Cobject * Createobject ();
...//
};

////////////////////////////////////
/* 2.3. macro expansion */
////////////////////////////////////
This example uses the dynamic creation of cmainframe In the SDI Program as an example. Let's take a look at the above two Macros in the XX. h and XX. cpp files:
// In mainfrm. h
Class cmainframe
{
Public:
Static const cruntimeclass classcmainframe;
Virtual cruntimeclass * getruntimeclass () const;
Static cobject * Pascal Createobject ();
...//
};
// In mainfrm. cpp
Cobject * Pascal cmainframe: Createobject () {return New class_name ;}
Afx_comdat const cruntimeclass cmainframe: classcmainframe = {
Cmainframe, sizeof (classcmainframe), 0 xFFFF, cmainframe: Createobject, (cruntimeclass *) (& cmdiframewnd: classcmdiframewnd), null, null };

Cruntimeclass * cmainframe: getruntimeclass () const
{Return & cmainframe: classcmainframe ;}
We can see that the two macros are different from the two macros described above. declare_dyncreate adds a function static cobject * Pascal Createobject () to the header file (); the expansion of implement_dyncreate is also different. It will be detailed below.
 
 
//////////////////////////////////////// ////
/* 2.4. how to create a dynamic disk */
//////////////////////////////////////// ///
Let's take a look at the access control of the cmainframe constructor! Protected: Are you confused? Protected constructors cannot be instantiated. So how is cmainframe constructed? This is why Microsoft uses cruntimeclass for dynamic creation. Here is a simple example to illustrate the constructor:
// In A. H
Class
{
Protected: (){}
... // Something else
Public: static A * Createobject ();
};
// In A. cpp
A * A: Createobject ()
{Return new ();}
// In test. cpp
Int main (void)
{
A * pnewobj = A: Createobject (); // OK
Return 0;
}
After the explanation, let's take a look at how Microsoft Works. Let's look back at declare_dyncreate as cmainframe.
Add something. Static cobject * Pascal Createobject (); bright eyes! Yes, it is equivalent
Static A * Createobject (); who called it? Let's look back at what implement_dyncreate has done?

Afx_comdat const cruntimeclass cmainframe: classcmainframe = {
Cmainframe, sizeof (classcmainframe), 0 xFFFF, cmainframe: Createobject, (cruntimeclass *) (& cframewnd: classframewnd), null, null };
The macro assigned m_pfncreateobject to cmainframe: Createobject;
You may not be very clear about this. Let's look at the MFC code!
Csingledoctemplate * pdoctemplate;
Pdoctemplate = new csingledoctemplate (
Idr_mainframe,
Runtime_class (cmydoc ),
Runtime_class (cmainframe), // main SDI frame window
Runtime_class (cmyview ));
We have mentioned this in the MFC technology insider series (II)-"MFC Document view structure insider", so we will not detail it here,
Csingledoctemplate: opendocumentfile called createnewframe
Cframewnd * cdoctemplate: createnewframe (cdocument * pdoc, cframewnd * pother) // some source code
{
...//
Cframewnd * pframe = (cframewnd *) m_pframeclass-> Createobject ();
...//
}
M_pframeclass is the cruntimeclass * pointer. It points to cmainframe: classcmainframe; The createnewframe function is called.
(Cframewnd *) m_pframeclass-> Createobject (); The cobject * cruntimeclass: Createobject () code is as follows:

// In objcore. cpp
Cobject * cruntimeclass: Createobject ()
{
If (m_pfncreateobject = NULL)
{
Trace (traceappmsg, 0,
_ T ("error: Trying to create object which is not ")
_ T ("declare_dyncreate/nor declare_serial: % hs./N "),
M_lpszclassname );
Return NULL;
}

Cobject * pobject = NULL;
Try
{
Pobject = (* m_pfncreateobject )();
}
End_try

Return pobject;
}
It calls (* m_pfncreateobject) (); that is, cmainframe: Createobject (); and returns the pointer to the dynamically created cmainframe object. You should understand it.
/////////////////////////////////////////
/* 3. Coming soon */
/////////////////////////////////////////
MFC technology insider series (4) ----- MFC message ing and message transmission insider

 

 

 

 

 

 

 

 

 

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.