One cool thing about RadVC / RFC is its power to let you look into all the detail stuff that actually goes on as you work on the form designer. Depending on your programming appetite to hack Windows, in VC ++ / RadVC environment, you can actually trace the origin of a cool control or a form down to the SDK level. If you ever programmed in Visual Basic, you know very well that this isnt the case. Like in RadVC, you may have designed a nice looking form with some cool controls in VB. But unfortunately there is no way to know how the form actually gets created or how it interacts with its child controls as your program runs. You find yourself trapped in closed box, where you can only "see" things up to a certain extent. In this article, we will be exploring the C++ source code that gets generated when you create a new project using RadVCs "New Project" option. The code is based on RFC (RAD Foundation Class) library, which is again based on Microsoft Foundation class (MFC). As we all know, MFC is a C++ class library that encapsulates Windows SDK functions and provides a lot of useful C++ classes that makes Windows programming a real joy. To start with, lets switch to RadVC environment and create a new project called "RadTest" using "New Project" menu item (use all default settings in "New Project" dialog). If you look into the folder "RadTest", you will see that RadVC creates a number of files for your project. Here is a summary of what you will find in each of the files that make up your RadTest application.
Out of all these files, there are only two files that will get modified often as you add controls to your form or add some event handlers to them. These are the files that implement the form: "form1.h" and "form1.cpp". What happens When you create a new control? When you drop a new control on your form, RadVC creates a member variable for the new control (in form1.h). For example, if you create a new command button then the following statement is inserted in the header of your form class CRButton m_Button1; Also RadVC inserts another statement in the forms source file form1.cpp (inside ::CreateRFCControls() function) m_Button1.Create(this, IDC_BUTTON1, IDS_PROP_BUTTON1); Here the button's "Create" function takes three parameters: the first one is the pointer to the parent window, which is the form in our case. The second parameter ( IDC_BUTTON1) is the button's command ID (a constant) and the third one is its property string ID. RadVC inserts the later two constants using #define statement for you in your project's 'resource.h" file. #define
IDC_BUTTON1
1000 It also inserts a string entry in the project's resource file(RadTest.rc). RadVC stores the properties of the forms and controls in comma-delimited string format in *.rc file ( a similar approach is used by MFC to implement dialog templates.). If you open RadTest.rc file in "text" format, you will find the following string entry for the button control's design time properties.
IDS_PROP_BUTTON1
"1,12632256,0,0,1,MS San Serif,0,0,8,0,0,98,0,0,63,0,0,0,0,1,Tag,ToolTipText,
63,1,0,98,Button1,0,0,0,0,0,0,0,0,0," In a similar fashion, the design time properties of the form are implemented through another property string, which can be found in the constructor of "CForm1" class. CForm1::CForm1() Like the button control described above, the property string for the form "IDS_PROP_FORM1" is defined in resource.h and RadTest.rc files. Things work in a bit different way, when you create a control or forms by choosing "3-way RAD" option. To examine this, let's first select "3-way RAD" menu option from RadVC toolbar. From now on, any control or form you create will be using "3-way RAD" feature. As you have probably seen in version 1.2 feature list, form / controls created using 3-way RAD option do not use any resource based property strings to implement their design-time properties. For example, if we create a second command button control, the create function will look like the following: m_Button2.Create(this, IDC_BUTTON2, CRect(203,28,280,119)); As you can see here, the third parameter in the "Create" statement does not take a property string ID; instead it takes a CRect parameter, which basically defines the location and size of the controls. The other properties of the control are implemented through function calls that can be found in a form function called ::SetProperties(). void CForm1::SetProperties()
What happens when you add an event handler for your form or control? To demonstrate this feature, let's first select the form and double click on its client area. From the "Event" combo box of the "RadVC Codebar", select the event item "Click". RadVC will generate and insert necessary code for you and then it will take you to the implementation code of the CForm1 class where you can start coding in response to the user's "click" event on the form. void CForm1::Form_Click() virtual void Form_Click(); The event handlers for other controls are implemented through a message map macros. For example, if we override a "Click" event of our command button1, then we will find the following piece of code in form1.cpp: BEGIN_MESSAGE_MAP(CForm1,
CRForm) The event handler function "Button1_Click" is declared in the parent form's class declaration (form1.h file). afx_msg void Button1_Click(); What happens when your application is run? When you start your CRadTest application, the framework constructs an instance of your application class CRadTestApp . To verify this, you can set a breakpoint in the constructor of the application class (CRadTestApp::CRadTestApp() function in radtestapp.cpp file) and then run the application. The framework then calls ::InitInstance function of RFC's CRWinApp application class (in ver 1.2 we will make RFC source code available to you). In this function, RFC creates an object of the start-up form class. RFC then creates the form's "window" and sets its properties. When form gets created, RFCs CRForm class calls your form's ::Created RFCControls function. In this function, RFC creates all the child controls you have inside your form. Each time a control gets created [using its own ::Create(..) statement, RFC sets its design time properties. In case of resource - based property implementation (i.e. without 3-way RAD option selected), RFC extracts the design time properties from their property resource string. In 3-way RAD, however, RFC first calls all the child controls (by calling ::CreateRFCControls()), and then it sets their properties properties by calling another method called :: SetProperties() [in form1.cpp file]. Well, in this article, we have only scratched the surface of the C++ code that you play with in VC++ / RadVC. Certainly there is a lot to understand underneath this layer, i.e. the layer of RFC / MFC library.We hope to deal with that in some future article(s). Did you find this article useful? If so, please let us know. Also we need your ideas on new articles / tech tips etc.
|
|||||||||||||||||
[ Home ][ Order Now ][Feedback][ Contact Us ][ About CapitolSoft ] | |
[ Features ][ Tutorial ][ Samples ][ F.A.Q.s ][ Download ][ CDK ] |