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:
Figure 9: The VCL Tree Preview
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. For example, all of our
previous programs consisted only of C++. Later on, you will write a program in Win32. 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.
To inherit an object from the TObject class, first include the vcl.h file to your application. Second, follow the same rules we have applied to inheritance. For example, to create a TBook object based on
TObject, you could write:
class TBook : public TObject
The third rule is that, to access a class that is derived from TObject, you must dynamically declare an instance of the class.
The classes above 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;
}
//---------------------------------------------------------------------------
|
Your object does not have to use any of the features of VCL or any of the access techniques of C++ Builder.
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. Win32 is a library 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.
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.
The WinMain() Function Definition |
|
Just like every C++ application starts from a function called main(), every Win23 application starts with a function called WinMain. This function is defined as:
Integer WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow);
|
The first argument of the function represents the current instance of the running application.
The second argument represents a previous instance of the application. In our applications, this parameter will always be ignored or set to NULL.
The third argument is a long pointer to a null terminated string that represents the attribute(s) of the command line when running the application.
The last argument is an integer that directs how the window should appear.
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, 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.
|
Starting a Win32 Application |
- If you did not do so already, start Borland C++ Builder. From the main menu, click File
-> New -> Other (or File -> New).
- From the New Items dialog box, click the Console Wizard icon and click OK.
- In the Console Wizard dialog, make sure the C++ radio button is selected. On the right side,
leave the check boxes empty:
- Click OK. Notice the content of the file with the WinMain() function:
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 former 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 using the techniques we have learned about declaring variables. 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 display 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-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. For this exercise, both members will receive a value of 0;
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-Menu-Name). If you do not have a menu, set this variable to NULL.
Every window must 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-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.
|
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);
RegisterClassEx(&WndClsEx);
return 0;
}
//---------------------------------------------------------------------------
|
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 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); |
) |
|
|
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;
}
//---------------------------------------------------------------------------
|
Microsoft Windows is an event-driven operating system. It receives requests in forms of messages and acts accordingly. To process these requests or messages, you use a special function that can treat any type of valid message. This processing is handled by the
WindowProc() function. The syntax of the WindowProc() function is as follows:
LRESULT CALLBACK WindowProc( |
|
HWND hwnd, |
// handle to window |
UINT uMsg, |
// message identifier |
WPARAM wParam, |
// first message parameter |
LPARAM lParam |
// second message parameter |
) |
|
|
Processing Window Messages |
- Just on top of the WinMain() function, add the implementation of the following function (and is 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,
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;
}
//---------------------------------------------------------------------------
|
- To test your program, press F9
- After viewing the window, close it and return to Bcb.
- To control the dimensions of the starting window, change the value of the nWidth from CW_USEDEFAULT to 325
- Also, change the value of the nHeight argument from CW_USEDEFAULT to 240:
CreateWindowEx( WS_EX_OVERLAPPEDWINDOW,
szAppName,
"Basic Win32 Application",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,
0,
325,
240,
NULL,
NULL,
hInstance,
NULL
);
|
- Test the program and return to Bcb.
- To maximize the window at startup, change the value of the nWidth and the nHeight arguments (same lines as previously) as follows:
CreateWindowEx( WS_EX_OVERLAPPEDWINDOW,
szAppName,
"Basic Win32 Application",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,
0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
hInstance,
NULL
);
|
- Test the program and return to Bcb.
C++ Builder Application Fundamentals |
|
To make application development easy, instead of using the whole techniques and features we
have just seen, there are only two actions necessary to create the same fundamental application in Bcb: visually add a form to the application and write three basic lines of code.
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.
|
A basic application |
- To create a new Win32 application, from the main menu, click File -> New
-> Other…
- From the New Items dialog, double-click the Console Wizard icon.
- Since Bcb remembers the last selection made on the Console Wizard dialog, click OK.
- To add a form to the application, on the main menu, click File -> New
-> Form.
- Press F12 to access the Code Editor window.
- 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;
}
//---------------------------------------------------------------------------
|
- If the form was created with a unit name other than Unit2, change the name accordingly.
To test the application, press F9.
|
|