CapitolSoft Banner
What Happens Under the Hood              as You Play on the Form?

Designing a RadVC form in Visual C++ is fun. But wouldn't it be even nice to know things that actually go on in your project as you create a new form, drop a couple of controls on the form or add some event handlers for them? Sure, you do not need to know all these stuff for the VB - like RAD programming in VC++, but a good knowledge of the internal workings of your application will undoubtedly help you to debug your application better and also to do more advanced programming jobs much faster.

 

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 isn’t 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 RadVC’s "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, let’s 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.

 

RadTest.dsp This file (the project file) contains information at the project level and is used to build your RadVC generated project.
RadTest.h This is the main header file for the application. It can includes other project specific headers (including Resource.h) and declares the CRadTestApp application class. CRadTestApp class is derived from RFC’s CRWinApp class which is again derived from MFC’s CWinApp class.
RadTest.cpp This is the main application source file that contains the application class CRadTestApp.
RadTest.rc This is a listing of all of the Microsoft Windows resources that the program uses. It can include the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++.
Form1.h This is the header file for the start-up form class "CForm1".
Form1.cpp This is the implementation file for the CForm1 class.
StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named RadTest.pch and a precompiled types file named StdAfx.obj.
Resource.h This is the standard header file, which defines new resource IDs. Microsoft Visual C++ reads and updates this file.

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 form’s 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
#define    IDS_PROP_BUTTON1                 61447

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()
{
    //{{AFX_RADVC_FORM_DATA_START
    m_nPropStringID = IDS_PROP_FORM1;
    //}}AFX_RADVC_FORM_DATA_END
}

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()
{
    //{{AFX_SETPROPS_IMPL_START
    m_Button2.Caption = _T("Button2");
    //}}AFX_SETPROPS_IMPL_END
}

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()
{
    // <RadVC> TODO: Add your code here
   
}

Here "Form_Click" is a CRForm virtual function and is declared in form's class declaration (in form1.h file):

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)
    //{{AFX_MSG_MAP(CForm1)
    ON_WM_RFC_CLICK(IDC_BUTTON1, Button1_Click)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

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, RFC’s 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 ]