Windows Fundamentals

 

Introduction to the Win32 Library

A library is a set of published documents. It could consist of a piece of paper, a book, or a group of books used as a (written) reference for a specific purpose. The programs that are on a Microsoft Windows operating system follow a set of rules and suggestions defined in a library called Win32 (Windows 32-bits). Win32 is a group of functions, objects, variables, and constants that govern how the Microsoft Windows (95 and above) operating systems function. As a reference, it allows individuals and companies to know what is necessary in order to create or develop applications for this specific platform.

In order to write programs or good and effective applications for a Microsoft Windows operating system, you do not have to use a compiler or development environment published by Microsoft or a company affiliated with Microsoft. Many people fall into that assumption or misconception. I read in a book once stating that Microsoft Visual C++ was the best environment to create Windows applications BECAUSE MSVC was published by Microsoft. The author supported the idea that since MSVC is written by people from inside the company, they are closer to the (Win32) source code and their MFC library enjoys a better collaboration with the operating system. This is extremely false. First of all there is absolutely nothing you can do in MSVC that you cannot do using another compiler. For example, although Delphi is written in Pascal while Win32 is written in C, Delphi understand Win32 100% and there is no function of the Win32 library that Delphi does not understand or cannot access. Secondly, in the world of Rapid Application Environment (RAD), MSVC is one of the poorest development environments around, at least as compared to Borland compilers (C++ Builder and Delphi). All you have to do is open both MSVC and C++ Builder and compare.

At the time of this writing (November 2002), the new Microsoft Visual C++ .NET has been around for a year or so but everything you need to do in MSVC .NET using the new .NET technology has to be done manually: you cannot create a single control by click-n-drop (I know this might not be a big deal; after all, it enables programmers to have a job). Thirdly, the Win32 library is available to every company that wants to develop for Windows, and Win32 is fairly (not highly) documented.

Over all, it is not strictly necessary to know Win32 thoroughly to write programs; but it is highly valuable to know some or most of the intricacies of its implementations. Since Win32 “tells” Microsoft Windows what to do, it is important to know how Windows functions.

In order to create a Win32 application in Borland C++ Builder, you would call the New Items dialog box. From the General property page, click the Console Application icon and click OK. From the Console Wizard dialog box, click the C++ radio button and make sure the Console Application check box is unchecked. When writing a Win32 application, Borland C++ Builder displays a syntax of the WinMain() function.

Practical Learning: Starting a Win32 Application

  1. If you did not do so already, start Borland C++ Builder. From the main menu, click File -> New -> Other (or File -> New)
     
  2. From the New Items dialog box, click the Console Wizard icon and click OK.
  3. In the Console Wizard dialog, make sure the C++ radio button is selected. On the right side, leave all check boxes empty (or unchecked):
     
  4. Click OK

The WinMain() Function Definition

Just like every C++ application starts from a function called main(), every Win23 application starts with a function called WinMain(). The syntax of the WinMain() function is:

int WINAPI WinMain(HINSTANCE hInstance,
		   HINSTANCE hPrevInstance,
  		   LPSTR lpCmdLine,
  		   int nCmdShow);

The first argument, hInstance, represents the current instance of the running application.

The second argument, hPrevInstance, represents a previous instance of the application. In our applications, this parameter will always be ignored or set to NULL.

The third argument, lpCmdLine, is a 32-bit long pointer to a null-terminated string that represents the attribute(s) of the command line when running the application.

The last argument, nCmdShow, is an integer that directs how the window should appear. It is a constant integer that can have one of the following values:

Value Description
SW_HIDE Used to hide the window. If another window was running when this one got hidden, that one becomes active. If there were many windows running, the operating system follows a coordinate system that allows it to choose the window that was immediately behind the one that has been hidden.
SW_MAXIMIZE Used to maximize the window. Consequently, the window fills the whole screen. If other windows were running, they become hidden.
SW_MINIMIZE Used to minimize the window. If another window was running, that one becomes active. If there were many windows running, the operating system follows a coordinate system that allows it to choose the window that was immediately behind the one that was just minimized.
SW_RESTORE Restores the window. If the window was maximized, which means it was covering the whole screen, it uses a dimension and position that it had prior to this action.
SW_SHOW Activates the window and displays it in its current size and position.
SW_SHOWMAXIMIZED Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE Displays the window as a minimized window.
This value is similar to SW_SHOWMINIMIZED, except the window is not activated.
SW_SHOWNA Displays the window in its current size and position.
This value is similar to SW_SHOW, except the window is not activated.
SW_SHOWNOACTIVATE Displays a window in its most recent size and position.
This value is similar to SW_SHOWNORMAL, except the window is not activated.
SW_SHOWNORMAL Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.

 

Filling a Window

The first thing you do when creating a Win32 application is to create a window. A window, or the main window, is created using the WNDCLASS or the WNDCLASSEX structures. Although still available and used, the WNDCLASS structure was mainly used with previous versions of Microsoft Windows. Since everything in WNDCLASS is also available in WNDCLASSEX and more, we will use the latter for our application.

The WNDCLASS and the WNDCLASSEX structures are defined as follows:

struct WNDCLASS
{
struct WNDCLASSEX
{
UINT cbSize;
UINT style; UINT style;
WNDPROC lpfnWndProc; WNDPROC lpfnWndProc;
int cbClsExtra; int cbClsExtra;
int cbWndExtra; int cbWndExtra;
HINSTANCE hInstance; HINSTANCE hInstance;
HICON hIcon; HICON hIcon;
HCURSOR hCursor; HCURSOR hCursor;
HBRUSH hbrBackground; HBRUSH hbrBackground;
LPCTSTR lpszMenuName; LPCTSTR lpszMenuName;
LPCTSTR lpszClassName; LPCTSTR lpszClassName;
HICON hIconSm;
}; };

In order to use one of these structures, you must first declare it. The name of the variable could be any you like but you should make it easy for the name to reflect the structure you are using. This could be done as follows:

WNDCLASS WndClass;

or

WNDCLASSEX WndClsEx;

The cbSize (Class-Byte Size) member variable of the WNDCLASSEX structure represents the byte size of the object. To find its value, you will use the sizeof operator like this:

WndClsEx.cbSize = sizeof(WndClsEx);

Both structures use a set of constant integers that specify the attributes of the window style. The attributes are defined as follows:

#define CS_VREDRAW 0x0001
#define CS_HREDRAW 0x0002
#define CS_DBLCLKS 0x0008
#define CS_OWNDC 0x0020
#define CS_CLASSDC 0x0040
#define CS_PARENTDC 0x0080
#define CS_NOCLOSE 0x0200
#define CS_SAVEBITS 0x0800
#define CS_BYTEALIGNCLIENT 0x1000
#define CS_BYTEALIGNWINDOW 0x2000
#define CS_GLOBALCLASS 0x4000

When using these attributes, one of them may be enough for your application. You can use one attribute as follows:

WndClass.style = CS_VREDERAW;

If you would like to use more than one attribute, you can combine them using the bitwise OR (|) operator. Here is example:

WndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;

The lpfnWndProc (Long-Pointer-To-A-Function-Window-Procedure) member defines the window procedure. It is provided from an external function that we will review later.

The cbClsExtra (Class-Byte-Class-Extra) and the cbWndExtra (Class-Byte-Window-Extra) members specify the number of extra bytes to provide to the object. Both members receive a value of 0 for regular programs.

The hInstance (Handle-Instance) represents the instance of the current window.

The hIcon (Handle-Icon) variable represents an icon for the current application. If you do not have an icon or you do not want to specify an icon, set this value to NULL. In that case the application would use the default icon. Otherwise, you can use the LoadIcon() function to include an icon.

The hCursor (Handle-Cursor) member is used to specify a cursor for the application. You mostly use the LoadCursor() function to specify a cursor for the application.

The hbrBackground (Handle-Brush-Background) member is used to set a color for the background of the window.

If you decide to display a menu, you can set its identifier using the lpszMenuName (Long-Pointer-To-A-String-As-The-Menu's-Name). If you do not have a menu, set this variable to NULL.

Every window must have a name in your application. This allows you and the application to refer to that window. The name of the window is a null-terminated string set with the lpszClassName (Long-Pointer-To-A-String-As-The-Class'-Name) member.

The WNDCLASSEX structure allows you to specify a small icon for the application. This icon is used when the application is displaying in Windows Explorer using the list, details, or small icons views. This is handled by the hIconSm (Handle-Icon-Small) member variable.

Practical Learning: Filling Out a Window

  • To fill out a window structure, change the content of the file as follows:
     
    //---------------------------------------------------------------------------
    #include <windows.h>
    #pragma hdrstop
    //---------------------------------------------------------------------------
    #pragma argsused
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
    {
        // The variable that will define the window
        WNDCLASSEX  WndClsEx;
        // The window's name
        static char szAppName[] = "FirstClass";
    
        // Filling out the structure that builds the window
        WndClsEx.cbSize = sizeof(WndClsEx);
        WndClsEx.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
        WndClsEx.lpfnWndProc = WindowProc;
        WndClsEx.cbClsExtra = 0;
        WndClsEx.cbWndExtra = 0;
        WndClsEx.hInstance = hInstance;
        WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
        WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        WndClsEx.lpszMenuName = NULL;
        WndClsEx.lpszClassName = szAppName;
        WndClsEx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
    
        return 0;
    }
    //---------------------------------------------------------------------------

Window Registration 

After building a window, you must let the operating system know that you have built a window and intend to use it. Letting the operating system be aware of the window is referred to as registering it. To register a window, you can use either the RegisterClass() or the RegisterClassEx() functions. Their respective syntaxes are:

ATOM RegisterClass(CONST WNDCLASS *lpWndClass );

and

ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx );

This function takes one argument which is the name of the window you had just built using either WNDCLASS or WNDCLASSEX structures. The argument is passed as a pointer.

Practical Learning: Registering a Window

  • Register the previous object as follows:
     
    //---------------------------------------------------------------------------
    #include <windows.h>
    #pragma hdrstop
    //---------------------------------------------------------------------------
    #pragma argsused
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
    {
        // The variable that will define the window
        WNDCLASSEX  WndClsEx;
        // The window's name
        static char szAppName[] = "FirstClass";
    
        // Filling out the structure that builds the window
        WndClsEx.cbSize = sizeof(WndClsEx);
        WndClsEx.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
        WndClsEx.lpfnWndProc = WindowProc;
        WndClsEx.cbClsExtra = 0;
        WndClsEx.cbWndExtra = 0;
        WndClsEx.hInstance = hInstance;
        WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
        WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        WndClsEx.lpszMenuName = NULL;
        WndClsEx.lpszClassName = szAppName;
        WndClsEx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
    
        RegisterClassEx(&WndClsEx);
        return 0;
    }
    //---------------------------------------------------------------------------

     

Window Creation 

The use of the WNDCLASS or the WNDCLASSEX structures allow you to "build" a window. In other words, you lay the foundation of a window as a structural object. To create the actual window, you use either the CreateWindow() or the CreateWindowEx() functions and fill it out.

The CreateWindow() function is declared as follows:

HWND CreateWindow(
LPCTSTR lpClassName, // registered class name 
LPCTSTR lpWindowName, // window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // menu handle or child identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // window-creation data);
)

The CreateWindowEx() function has the following arguments:

HWND CreateWindowEx(
DWORD dwExStyle, // extended window style
LPCTSTR lpClassName, // registered class name
LPCTSTR lpWindowName, // window name
DWORD dwStyle, // window style
int X, // horizontal position of window
int Y, // vertical position of window
int Width, // window width
int Height, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // menu handle or child identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // window-creation data);
)

For this tutorial, we will use the CreateWindowEx() version. This function takes quite a few arguments:

The dwExStyle (Window-Extended-Style) argument specifies the style that would control the window.

The lpClassName (Long-Pointer-to-the-Class'-Name) is a pointer to a null-terminated string that specifies or represents the name of the class as the lpszClassName member that was passed to the WNDCLASS or the WNDCLASSEX structures..

The lpWindowName (Long-Pointer-to-the-Window's-Name) is a string that would display as the caption of the window. If you do not want a caption, you can set this argument to NULL or type two double-quotes (that would represent an empty string).

Author Note Not providing or specifying the lpWindowName as NULL does not delete the title bar. In that case, the window would simply not have a caption.

The dwStyle (Window-Style) is an unsigned integer that specifies how to display the window or what style should be used.

The X (X-axis-coordinate) represents the horizontal distance of the top-left corner of the window from the top left corner of the monitor when the window appears (See the following picture). If you do not know or cannot make up your mind on the value of X, you can give it a value of CW_USEDEFAULT (Class-Window-Use-The-Default-Value). If you set the X argument to CW_USEDEFAULT, the operating system would use a default value. The CW_USEDEFAULT value can be selected randomly.

The Y (Y-axis coordinate) represents the vertical distance of the  top-left corner of the window from the top-left corner of the monitor when the window appears. If you do not know or cannot make up your mind on the value of Y, you can give it a value of CW_USEDEFAULT. If you set the Y argument to CW_USEDEFAULT, the operating system would use a default value. The CW_USEDEFAULT value can be selected randomly.

Both the X and Y arguments represent the Location of the window:

The location of the window

 

The Width argument specifies the horizontal measurement of the window. If you do not know or cannot make up your mind on the width of the window, you can give it a value of CW_USEDEFAULT. If you set the Width argument to CW_USEDEFAULT, the operating system would use a default width.

The Height argument specifies the vertical measurement of the window. If you do not know or cannot make up your mind on the height of the window, you can give it a value of CW_USEDEFAULT. If you set the Height argument to CW_USEDEFAULT, the operating system would use a default height.

The Width and the Height represents the Size of the window:

The location and size of a window

 

The hWndParent (Handle-to-the-Window's-Parent) argument can be used if the window you are creating will be "owned" by another window. Such a second window would be considered the parent of the window you are creating. In that case, use the hWndParent argument to specify the parent of the window you are creating.

The hMenu (Handle-to-a-Menu) specifies the menu to be used with the current window. If you do not have a menu, pass this argument as NULL.

The hInstance (Handle-Instance) argument is the instance of the current window, the same that was specified in the window structure.

The lpParam (Long-Pointer-to-a-Parameter) is a long pointer to a value passed to another class, in case your application is made of various objects, such as various windows.

 

Practical Learning: Creating a Window

  • Change the content of the file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <windows.h>
    #pragma hdrstop
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
    {
        // The variable that will define the window
        WNDCLASSEX  WndClsEx;
        // The window's name
        static char szAppName[] = "FirstClass";
        MSG         Msg;
    
        // Filling out the structure that builds the window
        WndClsEx.cbSize = sizeof(WndClsEx);
        WndClsEx.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
        WndClsEx.lpfnWndProc = WindowProc;
        WndClsEx.cbClsExtra = 0;
        WndClsEx.cbWndExtra = 0;
        WndClsEx.hInstance = hInstance;
        WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
        WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        WndClsEx.lpszMenuName = NULL;
        WndClsEx.lpszClassName = szAppName;
        WndClsEx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
    
        RegisterClassEx(&WndClsEx);
    
        CreateWindowEx( WS_EX_OVERLAPPEDWINDOW,
                        szAppName,
                        "Basic Win32 Application",
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                        0,
                        0,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL
                      );
    
        while( GetMessage(&Msg, NULL, 0, 0) )
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
    
        return Msg.wParam;
        // return 0;
    }
    //---------------------------------------------------------------------------

Windows Processing of Object's Requests

Every time you create an object in your program, like the window we have created using the WNDCLASSEX structure, such an object needs to find a way to communicate with the operating system. It is not the job of the WinMain() function to let the operating system know what an object wants to do. As it happens, Microsoft Windows is a message-oriented operating system. Each object of your program sends messages to Microsoft Windows. Whenever the operating system receives one of those messages, it must analyze and process it.

To send its messages to the operating system, an object, such as a window, must send four pieces of information to the operating system. To send these pieces of information as one request (instead of sending four disparate requests), the object must put them in a function that would carry them as arguments. The name of the function is not important but there are rules the object (actually it is your responsibility) must follow. The function that carries the message of the object must

  • be a callback type. A function is considered as "callback" when its name can be assigned as a value, that is, without arguments, as if the name of the function were a regular value (a "normal" C++ function cannot be assigned to a variable as a value); to make a function call back, you can declare and define it using the CALLBACK keyword or you can declare and define it using the WINAPI keyword (CALLBACK and WINAPI are interchangeable)
  • return LRESULT as its value

As stated already, the name of the function is not important but the name of the function must be exactly assigned to the lpfnWndProc member of the object you are creating. The syntax used for the function is:

LRESULT CALLBACK MyMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

or

LRESULT WINAPI MyMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

By tradition or pure habit, most programmers define and declare this function using words or suffixes like Wind, Wnd, Proc, and Procedure. Therefore, it is usual to create this function with a name like WndProc or WindowProc. The syntax of the function can be written as follows:

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

The hWnd (Handle-Window) argument is a handle to the object or window that is sending the message(s).

The uMsg (Message) is an unsigned integer that represents the message that is being sent. Most or all messages are represented by a map of integral values of the Win32 library.

The wParam (Parameter, the w does not necessarily mean window) is an additional piece of information that can accompany the uMsg argument. The value of wParam depends on the type of message that is being sent. It would mean different things to the operating system if the message sent has to do with an action on the keyboard (for example if the message was sent because the user pressed a key on the keyboard) or an action on the mouse (for example if the message was sent because the user pressed the right button on the mouse).

The lParam (Parameter, the l does not necessarily mean window or long integer) is an additional piece of information that can be sent with the uMsg argument.

Practical Learning: Processing Window Messages

  1. Just on top of the WinMain() function, add the implementation of the following function (and here is the complete file):
     
    //---------------------------------------------------------------------------
    
    #include <windows.h>
    #pragma hdrstop
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg,
                                WPARAM wParam, LPARAM lParam)
    {
        switch(Msg)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            break;
        }
    
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    //---------------------------------------------------------------------------
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
    {
        // The variable that will define the window
        WNDCLASSEX WndClsEx;
        // The window's name
        static char szAppName[] = "FirstClass";
        MSG         Msg;
    
        // Filling out the structure that builds the window
        WndClsEx.cbSize = sizeof(WndClsEx);
        WndClsEx.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
        WndClsEx.lpfnWndProc = WindowProc;
        WndClsEx.cbClsExtra = 0;
        WndClsEx.cbWndExtra = 0;
        WndClsEx.hInstance = hInstance;
        WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
        WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        WndClsEx.lpszMenuName = NULL;
        WndClsEx.lpszClassName = szAppName;
        WndClsEx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
    
        RegisterClassEx(&WndClsEx);
    
        CreateWindowEx( WS_EX_OVERLAPPEDWINDOW,
                        szAppName,
                        "Basic Win32 Application",
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL
                      );
    
        while( GetMessage(&Msg, NULL, 0, 0) )
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
    
        return Msg.wParam;
        // return 0;
    }
    //---------------------------------------------------------------------------
  2. To test your program, press F9
     
    Pen
  3. After viewing the window, return to Bcb.

C++ Builder Application Fundamentals

To make application development easy, that is, to provide Rapid Application Development (RAD), Borland simpliefied the above steps.

C++ Builder uses the same WinMain() function to create an application. Instead of defining a window class structure and creating a window using the CreateWindow() function, you can simply add a form and use the TApplication::CreateForm() function to start the application by displaying a form.

Practical Learning: Creating a Basic Application

  1. To create a new Win32 application, from the main menu, click File -> New -> Other…
  2. From the New Items dialog, double-click the Console Wizard icon.
  3. Since Bcb remembers the last selection made on the Console Wizard dialog, click OK.
  4. To add a form to the application, on the main menu, click File -> New -> Form.
  5. Press F12 to access the Code Editor window.
  6. Click the Unit1.cpp tab and change the content of the file as follows:
     
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #include <windows.h>
    #pragma hdrstop
    #include "Unit2.h"
    //---------------------------------------------------------------------------
    
    #pragma argsused
    WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    	            LPSTR lpCmdLine, int nCmdShow)
    {
        Application->Initialize();
        Application->CreateForm(__classid(TForm2), &Form2);
        Application->Run();
    
        return 0;
    }
    //---------------------------------------------------------------------------
  7. If the form was created with a unit name other than Unit2, change the name accordingly.
    To test the application, press F9.

Introduction to the VCL

When creating applications using Borland C++ Builder, you will essentially be choosing objects that are necessary for your application. The objects are provided in a pool, ranging from very simple to fairly complicated. To manage all these objects, Borland created a library called the Visual Component Library (VCL) based on the Pascal language but fully adhering to the C++ language.

The VCL is a set of functions, classes, variables, and libraries that provide the application developer to choose which objects are appropriate to respond to a particular scenario.

The Visual Component Library is organized like a tree (upside-down) with objects inheriting from earlier ones:

The Visual Component Library (VCL) Tree

Introducing TObject

A class called TObject is the ancestor or the parent of all classes used in the VCL. This class provides the starting point for the other objects. When you will be implementing an object in your application, you can use either the Help files or the poster that ships with C++ Builder to trace the ancestry of the object: but this is not always important.

There are three categories of objects you will be using when creating your programs: the VCL objects, your own objects, and Win32 objects. A program can include one category. Many of the programs we will be writing essentially consist of VCL objects. A program can also combine data types and objects of any of the three categories.

Here are examples of two objects that implement two geometric figures, namely a trapezoid and a parallelogram:

//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
//---------------------------------------------------------------------------
class TParallelogram
{
public:
    __fastcall TParallelogram(double B = 0.00, double H = 0.00)
        : Base(B), Height(H) {}
    __fastcall TParallelogram(const TParallelogram& P)
        : Base(P.Base), Height(P.Height) {}
    virtual __fastcall ~TParallelogram() {}
    double __fastcall getBase() const { return Base; }
    double __fastcall getHeight() const { return Height; }
    double __fastcall Area() const { return Base * Height; }
private:
    double Base;
    double Height;
};
//---------------------------------------------------------------------------
struct TTrapezoid
{
public:
    __fastcall TTrapezoid(double B = 0.00, double b = 0.00, double H = 0.00)
        : Base(B), base(b), Height(H) {}
    __fastcall TTrapezoid(const TTrapezoid& t)
        : Base(t.Base), base(t.base), Height(t.Height) {}
    virtual __fastcall ~TTrapezoid() {}
    void __fastcall setDimensions(double B, double b, double H)
        { Base = B; base = b; Height = H; }
    void __fastcall setBase(const double B) { Base = B; }
    void __fastcall setbase(const double b) { base = b; }
    void __fastcall setHeight(const double H) { Height = H; }
    double __fastcall getBase() const { return Base; }
    double __fastcall getbase() const { return base; }
    double __fastcall getHeight() const { return Height; }
    double __fastcall Area() const { return Height * (Base + base) / 2; }
private:
    double Base;
    double base;
    double Height;
};
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    TParallelogram Para(6.95, 10.65);

    cout << "Characteristics of the Parallelogram";
    cout << "\nBase:   " << Para.getBase();
    cout << "\nHeight: " << Para.getHeight();
    cout << "\nArea:   " << Para.Area();
    cout << "\n\n";

    TTrapezoid Trapper(16.25, 20.28, 12.44);

    cout << "Characteristics of the Trapezoid";
    cout << "\nLower Base: " << Trapper.getBase();
    cout << "\nUpper Base: " << Trapper.getbase();
    cout << "\nHeight:     " << Trapper.getHeight();
    cout << "\nArea:       " << Trapper.Area();
    cout << "\n\n";

    cout << "Press any key to continue...";
    getchar();
    return 0;
}
//---------------------------------------------------------------------------

This would produce:

Characteristics of the Parallelogram
Base:   6.95
Height: 10.65
Area:   74.0175

Characteristics of the Trapezoid
Lower Base: 16.25
Upper Base: 20.28
Height:     12.44
Area:       227.217

Press any key to continue...

TObject is the ancestor of all objects and classes you will be using when writing your applications using the VCL. Like any library, the VCL has some implementations and syntaxes that are particular to it. There are some details you should be aware of about objects that are part of the VCL. One of those details involves deriving an object from TObject.

Inheriting From TObject

To inherit an object from the TObject class:

  • you must use the vcl.h header file in your application
  • follow the normal rules applied to C++ inheritance. For example, to create a TBook object based on TObject, you could write: class TBook : public TObject
  • to access a class that is derived from TObject, you must dynamically declare an instance of the class.

Based on these rules, the above classes can be made children of the TObject as follows:

//---------------------------------------------------------------------------
#include <iostream.h>
#include <vcl.h>
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
//---------------------------------------------------------------------------
class TParallelogram : public TObject
{
public:
    __fastcall TParallelogram(double B = 0.00, double H = 0.00)
        : Base(B), Height(H) {}
    __fastcall TParallelogram(const TParallelogram& P)
        : Base(P.Base), Height(P.Height) {}
    virtual __fastcall ~TParallelogram() {}
    double __fastcall getBase() const { return Base; }
    double __fastcall getHeight() const { return Height; }
    double __fastcall Area() const { return Base * Height; }
private:
    double Base;
    double Height;
};
//---------------------------------------------------------------------------
struct TTrapezoid : TObject
{
public:
    __fastcall TTrapezoid(double B = 0.00, double b = 0.00, double H = 0.00)
        : Base(B), base(b), Height(H) {}
    __fastcall TTrapezoid(const TTrapezoid& t)
        : Base(t.Base), base(t.base), Height(t.Height) {}
    virtual __fastcall ~TTrapezoid() {}
    void __fastcall setDimensions(double B, double b, double H)
        { Base = B; base = b; Height = H; }
    void __fastcall setBase(const double B) { Base = B; }
    void __fastcall setbase(const double b) { base = b; }
    void __fastcall setHeight(const double H) { Height = H; }
    double __fastcall getBase() const { return Base; }
    double __fastcall getbase() const { return base; }
    double __fastcall getHeight() const { return Height; }
    double __fastcall Area() const { return Height * (Base + base) / 2; }
private:
    double Base;
    double base;
    double Height;
};
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    TParallelogram *Para = new TParallelogram(6.95, 10.65);

    cout << "Characteristics of the Parallelogram";
    cout << "\nBase:   " << Para->getBase();
    cout << "\nHeight: " << Para->getHeight();
    cout << "\nArea:   " << Para->Area();
    cout << "\n\n";

    TTrapezoid *Trapper = new TTrapezoid(16.25, 20.28, 12.44);

    cout << "Characteristics of the Trapezoid";
    cout << "\nLower Base: " << Trapper->getBase();
    cout << "\nUpper Base: " << Trapper->getbase();
    cout << "\nHeight:     " << Trapper->getHeight();
    cout << "\nArea:       " << Trapper->Area();
    cout << "\n\n";

    cout << "Press any key to continue...";
    getchar();
    return 0;
}
//---------------------------------------------------------------------------

Following the hierarchy of VCL objects, most of the objects we will use in this book will be derived from a class of the VCL. Your object does not have to use any of the features of VCL or any of the access techniques of C++ Builder.

 

Home Copyright © 2005-2012, FunctionX, Inc.