|  | Click Here!

Search the site:
EXPERT SEARCH

| Programming Languages
| Databases
| Security
| Web Services
| Network Services
| Middleware
| Components
| Operating Systems
| User Interfaces
| Groupware & Collaboration
| Content Management
| Productivity Applications
| Hardware
| Fun & Games

EarthWeb sites
Crossnodes
Datamation
Developer.com
DICE
EarthWeb.com
EarthWeb Direct
ERP Hub
Gamelan
GoCertify.com
HTMLGoodies
Intranet Journal
IT Knowledge
IT Library
JavaGoodies
JARS
JavaScripts.com
open source IT
RoadCoders
Y2K Info

| ## Charlie Calvert's C++ Builder Unleashed ## - 2 - ## Basic Facts About C++Builder This chapter and the next five cover the basic facts that everyone needs to know about BCB. Important subjects included in this chapter are as follows: The IDE Projects The VCL Core VCL Technologies: Components, Properties, and Events Stepping into the Pascal source for the VCL The syntax of the VCL An overview of the component architecture A brief look at Run Time Type Information (RTTI) This introduction to BCB continues in the next chapter, where I cover the new Borland additions to the C++ language and introduce several key BCB classes such as `AnsiString`s and `Sets`. These special classes emulate features of Object Pascal. Then, in Chapter 4 you will have a look at events. Chapter 5 focuses on exceptions, Chapter 6 on using Delphi code in BCB, and Chapter 7 on graphics programming with the VCL. The latter chapter will complete my introduction to the VCL and to the syntax that is common to almost all BCB programs. When reading this chapter, you need to remember the basic philosophy of this book. My goal here is not to plumb the depths of C++, the VCL, the Windows API, or any other hardcore technical syntax. Instead, I want to show you how to quickly build real-world applications without losing touch with the underlying Windows architecture. In these chapters there are many times when I make a pass over very complicated subjects such as C++ constructors, templates, rules of precedence, the GDI, and so on. I am, of course, aware that these are sticky subjects that take many pages to cover appropriately. However, you will not find in-depth discussions of these subjects in this book, for there are many other volumes dedicated to those topics. Furthermore, the goal of this book is to show how to use RAD tools and high-level objects to perform complicated tasks quickly, easily, and safely. C++ is already at least 10 times faster than interpreted languages such as Visual Basic, Java, or PowerBuilder. If slowing down performance by five percent yields a 10- or 20-fold increase in reliability or ease of use, I think it is worth it to play a somewhat more cautious game. In my opinion, it is better to be nine times faster and nearly as safe as an interpreted tool than it is to be 10 times faster and 10 times more dangerous than an interpreted tool. That last 5 or 10 percent that you can eke out of the language by using every imaginable trick just isn't worth it, except in a few unusual circumstances such as compilers, operating systems, and game engines. Even in those cases, it is still probably best to use the relatively small and fast OOP-based techniques outlined in this book. This particular chapter is unique in that it covers a number of technical subjects that are not very complex. Everything in this chapter is here because I either Think that you have to know it in order to complete BCB programs. Think that you have to know it in order to feel at all comfortable inside the BCB programming environment. Don't worry if you find most of the material in this chapter a bit too simplistic. There is some basic material that almost has to be covered in a book of this type, and once I get it out of the way, I will move on to more interesting subject matter in the next chapters. It's time now to get started with an overview of the BCB environment, project management, the VCL, and the basic syntax used by BCB programmers. When you have completed this and the next five chapters, you should have all the knowledge you need to begin a robust, broad exploration of the all the exciting features found in BCB. ### Creating C++Builder Projects C++Builder has a project manager that you can access from the View menu. You can use this tool to add files to a project or to remove files from a project. You can add files with the following extensions to your project, and C++Builder will compile and/or link them automatically, as shown in Table 2.1: Table 2.1. Files you can add to a BCB project.
Type of File | Description
CPP | C++ Source module. OWL and MFC are treated in the appendices.
C | C Source module.
PAS | Any Pascal module that will compile in Delphi 2.01.
RC | Resource script.
RES | Resource file.
OBJ | Compiled C++, C, or PAS file.
LIB | C or C++ Library file.
DEF | Module Definition file.
You can use the IDE to produce Windows executables, DLLs, or console applications: To create a 32-bit Windows executable, you need do nothing. The default behavior of the IDE is to generate this type of executable. To create a DLL, go to File | New and select DLL from the Object Repository. Click OK. Everything else is automatic. I discuss exporting functions from a DLL in several later chapters of the book, including Chapter 26, "Extending an Internet Server with ISAPI." In a word, the key to exporting a method from a DLL is to use `__declspec(dllexport)`, as described in Chapter 26 and in the comments at the top of the file `ISAPI1.CPP` from Chapter 26. To create a console application, go to the Options | Project | Linker option from the menu and select Console Application. If you want to create a console application as a quick way to produce text output, you should consider using the BCB `TMemo`, `TListBox`, and `TEdit` controls instead. I can output text to these controls at least as quickly as I can use `printf` or `cout`. I find these components are more useful than outputting text to the command line, because they support concepts like scrolling and saving their contents to a file or the clipboard. NOTE: Delphi programmers need to remember that it is not enough merely to `#include` a C, CPP, or PAS file in a module of an existing project. You also have to add the file itself to the project using the Project Manager or the Add to Project menu choices or speed buttons. Delphi's linker assumed that you would not reference a file from your `uses` clause unless you wanted it to be part of your project. C++Builder, for better or worse, makes no such assumption. You must incorporate the new file into your makefile listing, or it will not be linked into your project. BCB projects are managed in a standard C++ makefile. The easiest way to get something into your makefile is through the project manager. Editing the makefile itself is not recommended, but C++ experts will find there are some changes to your project that can only be made by editing the makefile. Most of the important changes which can be made to a makefile are configurable through the Options | Project or Options | Environment menu choices. The developers of BCB do not expect you to find many occasions when you will need to edit the makefile. I believe the primary reason the makefile exists is that the team grew tired of trying to manage a binary project file. The Microsoft C++ team, on the other hand, recently grew tired of trying to manage a text-based project file! This is probably one of those cases where developers have a choice between two evils. If you are trying to manage projects that consist of multiple executables and DLLs, you will almost certainly find the current BCB project manager inadequate. Borland C++ 5.02 will support compiling C++Builder projects. You will therefore want to consider using the advanced tools in BC 5.02 for managing huge projects. BC5 also supports a powerful scripting language not available in BCB. As a result, I think some programmers will find a combination of BC5 and BCB to produce the ultimate C++ programming environment. Having made my pitch to that special group of programmers who are managing massive projects, I want to end this section by stating that I find BCB includes everything I need and considerably more. The goal of this book is to talk about completing high quality projects as quickly and efficiently as possible. If that is your goal, stick with BCB and with third-party tools tailored for this environment. BCB is the ideal tool for creating C++ applications. It is state of the art and leagues ahead of any other C++ environment that is planned or available at the time of this writing. #### BCB File Extensions In the last section, in Table 2.1, I list the types of files you can include in C++Builder. Most of these files will be generated automatically for you by the compiler, and I list them here just so you will know why they exist and what they do. In this section, I will talk about all the important files that become part of your project. Table 2.2 lists the key extensions in BCB projects. Table 2.2. File types used in a BCB project.
File extension | Description | File type
RC | Source for resource file. | Text
RES | Resource file. There will usually be one RES file with the same name as your project that contains only an icon. It's best to leave this file alone. | Binary
CPP, C | C++ source file. | Text
PAS | Delphi 2.01 source file. | Text
H or HPP | C++ header file. | Text
DSK | The location of files on the desktop. | Text
DFM | Binary file containing form definition. Use `CONVERT.EXE` to translate into text. | Binary
MAK | The project makefile in text format. | Text
TDS | Turbo debugger symbols. | Binary
ILX | Incremental linker symbols. | Binary
> When browsing this table, take special notice of the incremental linker files. These four files, all of which begin with ILX, are huge. They are the key files needed to produce BCB's incredibly fast link times. If you turn incremental linking off, as explained later in this chapter, these files will disappear. Turning incremental linking off means that your compilation and link times will be from 5 to 10 times slower than they are with incremental linking turned on. #### The include and lib Directory Paths Issue There are, confusingly enough, two places where you can designate the paths to your `include` and `lib` files. One is located in the Options | Project | Directories/Conditionals menu choice, and the second is located in the Options | Environment | Library section. These pages are shown below in Figures 2.1, 2.2, and 2.3. There is also a Path for Source option in the Options | Environment | Preferences page. FIGURE 2.1. The Options menu leads to the Project dialog where you can set paths for your project. ###### FIGURE 2.2. The Options menu is also the gateway to the Environment dialog where you can find the Library page. ###### FIGURE 2.3. The Options | Environment | Preferences page gives you a place to add the path to modules you include in your projects. The BCB macro shown in the Path statements from Figures 2.1 through 2.3 resolves into the path that points to your current installation of BCB. This kind of information is stored in the Registry under `HKEY_CURRENT_USER/Software` and `HKEY_LOCAL_MACHINE/Software`. For instance, see the `RootDir` entry in `HKEY_LOCAL_MACHINE/Software/C++Builder/1.0`. To view the Registry, select Run from the Windows Start menu, type in the word `RegEdit`, and press the Enter key. As a rule, you make changes specific to one project in the Options | Project dialog, and make global changes that you want reflected in all programs in the Options | Environment dialog. Use the Path for Source to include any directories that contain utility code that you use frequently. As a rule, additions to these various path statements are made automatically when you add modules to your project through the Project Manager. However, there are times when I need to go in and explicitly edit one of these options. Remember that if you are adding a component to the Component Palette, you have to add the path to that component in the Options Environment dialog or the Component Palette will not load. This addition to the Path statement will be made automatically if you add a component from inside the IDE. If you add the component from the command line by recompiling `CMPLIB32.CCL`, you need to update the Library path statement yourself. If you are using DLLs from inside a component, make sure the DLL is in a directory that is on your global DOS/Windows path. For instance, you might consider putting it in the `Windows` or `Windows/System` directory. NOTE: The question of whether to call a C module used in a BCB program a unit or a module is something of an open matter in BCB. My inclination is to call it a module, because that is traditional C usage, but BCB seems to refer to them as units. To be utterly frank, this is the kind of issue that doesn't really grip me all that deeply. In particular, I'm sure you will have no trouble understanding me regardless of which term I use. As a result, you will hear me referring to C modules as either modules or units, depending more on whim than on any clearly defined practice. ### Working in the IDE Here are some tips for working inside the IDE. I'll make this section brief, because I don't want to waste time on issues like this in a book that is clearly aimed at experienced programmers. However, this is a new environment, so it might help to share a few tips. Whatever you do, be sure that you understand that this tool is meant to be used from inside its IDE. This is not a command-line environment! NOTE: I'm sure that most programmers who investigate the matter will see that the command-line approach makes no sense with BCB. If that sentence strikes a sour note with you, all I ask is that you don't develop contempt prior to investigation. In my opinion, this IDE has something so powerful to offer that it finally makes command-line programming obsolete. With BC5, and even with MSVC, I usually worked from the command line. I was one of the last of the hardcore C++ command-line junkies. With BCB, however, I have changed my ways. I'm totally sold on this environment, and would never consider going back to the command line except for a few rare situations. #### Tips on Manipulating Controls Here are a few tips for using the visual tools. If you are new to the environment, you should boot up BCB and follow along when reading these time-saving tips. When dropping controls on a form, do the following: Use the Control key plus the arrow keys to move the location of a component one pixel at a time. In particular, drop a component such as a button on a form. Select it with the mouse. Hold down the Control key and press the left arrow key. Repeat the previous steps, only this time use Shift plus the arrow keys to resize a component one pixel at a time. Hold down the Shift key when selecting a component from the Component Palette if you want to drop multiple copies of it on a form without having to go back to the palette. Click the "arrow" icon at the far left of the Component Palette to break out of this process. Become familiar with the Align and Size options from the Edit menu. Quickly drop down five buttons on a form, each one below the last, without taking the time to carefully align their right and left sides. Hold down the Shift key, then select the five buttons with the mouse by clicking on each one. Now use the Align dialog from the Edit menu to align the tops or sides of all the selected controls. A second technique for selecting a large group of components is to click on the main form and hold down the left mouse button while dragging over several components. When you let up the mouse, you will find the components are selected. If the components you want to select are resting on top of another control such as a panel, then you will need to hold the control button down before and during the process of dragging the mouse. When designing a form, make it as large as you want. Then, when you have everything in place, use the Scale option from the Edit menu to make your form as small as you want, while still keeping each item on the form in proportion. Right-click a component, as shown in Figure 2.4, to bring up a menu that lets you change the size, alignment, tab order, scaling, or creation order. FIGURE 2.4. Right-clicking a `TTable` object to bring up a list of custom options. #### Making the Most of the IDE Here are some tips on using the IDE: Right-click almost anything in the IDE to bring up a menu to configure the component or tool you are currently using. For instance, right-click the colorful toolbar at the top left of the environment. Select Properties from the popup menu to bring up the Toolbar editor. Now drag a colorful button from the toolbar onto the Toolbar editor and grab another button from the ToolBar editor and drag it back onto the toolbar. I sometimes delete the Trace, Trace Into, and Pause buttons from the extreme right of the toolbar and replace them with Copy, Cut, and Paste buttons or with compiler buttons such as Make, Build All, and Compile Unit. Notice that you can view the Project Source and Project Makefile from the View menu. The project source contains the `WinMain()` or `main()` block for your code. You rarely will need to edit this code. Its contents are usually configurable from the Options | Project menu. For instance, you can change the code in the Project Source from Forms page of the Options | Project menu. Check out the Project Manager, which is also available from the View menu. You can lock the controls on a form by selecting the Lock Controls option from the Edit menu. If you have spent some time working on a form and want to be sure that it does not accidentally get changed, select Lock Controls, and it will not be possible to move the controls on that form, or any other, until you deselect this option. If you want to set the text on the editor page to read only, right-click the editor page and select Read Only. Watch out for the `AutoScroll` property of a form. This is set to `true` by default, but it can bite back if you leave it set to `true` and then move your form to a different resolution. For instance, if you move from 640x480 to 800x600, you generally should not have `AutoScroll` set to `true`, especially if your form is populated with a large number of controls. Use the `Position` property of a form to decide whether the form should first appear in the screen center, at the place where you positioned it at design time, or at a default location defined by Windows. Use the `WindowState` property of a form to decide if the form should first be shown minimized, maximized, or at normal size. Before releasing a project to the public, check out its appearance in at least three different resolutions and make sure at least one of them toggles the font from Small Fonts to Big Fonts, or vice versa. (You can change Windows' resolution by right-clicking the desktop, selecting Properties, and going to the settings page. Make sure you change between Big Fonts and Small Fonts during your testing!) #### Project Options Other than the path-related issues covered in the last section, there are only a few options that you need to know about when programming BCB. The rest of the setup-related issues are handled for you automatically by the environment. All the options you choose in the Project and Environment dialogs are written to the Registry. If you want to write custom programs that change these settings, you can learn how to proceed by reading the sections on the Registry in Chapter 13, "Flat-File, Real-World Databases." The Options | Project menu has six pages in it: Forms: This page is discussed in depth later in the chapter when I discuss the Project Source file for the ShapeDem program in the section called "Creating Forms." The core functionality on this page addresses the question of which unit will be the main module for your application--that is, which will come up first when you start the program. A secondary issue addressed in this page is whether a form will have memory allocated for it automatically at startup, or whether you want to create it explicitly at some point during your application's runtime. Forms listed in the left-hand list box shown on this form are created automatically; those on the right-hand list box must be created explicitly by the developer. The following code will create a form, show it to the user, and delete it:
>     Form2 = new TForm2(this);

>     Form2->ShowModal();

>     delete Form2;
> This code would not work unless the header for Form2 was included in the module that wanted to call the code quoted here:
>     #include "unit2.h"
Application: This is where you can set up the icon or help file for your project. This is an intuitive process; click Help in the dialog if you have questions. C++: This is where you can set the Debug and Release compiler options. You can also do a small amount of fine-tuning here, but this book hardly ever steps beyond recommending that you use the Debug option in development and the Release version when you ship. I almost never have occasion to do more than choose the simple binary Debug or Release option, except for occasionally toggling the precompiled headers option. Pascal: Here is where Pascal aficionados can fine-tune their code. I would recommend leaving all these options untouched unless you have a specific reason to change them. If you want to get involved in this page, the first level of advice is to turn Range and Stack checking on only during debug cycles, and to turn Optimizations on only when you ship. Linker: This is where you can decide to produce a Windows or console application, an EXE, or a DLL. This is also the place where you can toggle the incremental linker on and off. In development, you probably want the incremental linker on to speed compilation; when you ship, you should test the size of your executables when it is off and when it is on, and ship the smallest version. Directories / Conditionals: The key features of this page were covered earlier in this chapter. Note that this is also where you can define conditionals. The whole subject of unit aliases is an Object Pascal-specific issue that enables you to create an alias for the name of a unit. For instance, the 16-bit version of Delphi kept all the Windows API calls in a unit called `WinProcs.pas`, and all the Windows types in a unit called `WinTypes.pas`. When the big segment sizes of 32-bit Windows became available, the two units were consolidated into one called `Windows.pas`. To remove the burden of having to change the uses (`#include`) statements in a Pascal file, the developers enabled you to create aliases. The most common alias told the compiler to use `Windows.pas` whenever it saw a request to include the `WinTypes` or `WinProcs` units. As you can see, I don't put a lot of weight on fine-tuning the settings for your project. If you flip through these pages and see the small number of options available, you can see that the developers were not very concerned about this issue either. One of the major goals of BCB is to make C++ once again a mainstream language. The programming world used to be much simpler than it is today. Now we are all expected to know about OLE, MAPI, the Internet, multimedia, or other cutting-edge technologies. I invest my time in learning these valuable new technologies, and ask little more of my compiler than that it link quickly and easily and automatically produce small, tight code. #### Environment Options There are six pages in the Options | Environment menu choice. I play with many of these options all the time because they do nothing more than tweak the appearance or feel of the IDE. You aren't going to accidentally mess up the link process in your program or add 500KB to the size of an executable by tweaking one of these options. Feel free to set them as you please. Following is a list of the options I often play with during development. There are some choices that are listed in both the Environment Options pages and the Project Options pages. If you make a change in the Project pages, you are changing an option for just that one project, while if you make the change in the Environment page, you are changing things globally for the entire environment. Local options always override global options. Preferences: In the preferences page I always set Show Compiler Progress to true so that I can tell how far along I am in the compile cycle. I set AutoSave to true for Desktop files so that the environment will remember which project I was working on and which files I had open in the IDE. I also frequently tweak Break On Exception, depending on whether or not I want to catch problems in my code (turn it on) or just test to see if exceptions are popping up as expected at runtime (turn it off). This is also where you can turn integrated debugging on and off and change the path, as described above in the section on setting the project path. Library: This is where you can set the path for `include` and `lib` files, as described previously. You can also globally decide for all projects whether or not to use the incremental linker. If you are adding components to the Component Palette, you should set Save Library source code to true so that you can build the Component Palette from the command line to save time or to repair a damaged Component library. Editor: I discuss this page in a later section called "Feeling at Home in the IDE." It is here you can customize the behavior of the editor. All the major third-party editors (CodeWright, SlickEdit, MultiEdit) have some customizations for BCB, but none of them can get into the environment to the degree to which you, I, and they would like. Hopefully, improvements will come in this area in later releases. Display: I discuss this page in a later section called "Feeling at Home in the IDE." It is here you can choose the keystroke emulation and font for the editor. Colors: I discuss this page in a later section called "Feeling at Home in the IDE." It is here you can customize the colors of the editor. It particular, it enables you to switch between different color schemes or customize the colors for each element in the language, such as string, identifiers, integers, and so on. Like all the settings mentioned in these pages, the results of your decisions are written to the Registry. The Address2 program from Chapter 13 shows how you could write custom programs that tweak the Registry. For instance, you could write a program that automatically switched between four or five additional color schemes. Palette: If you want to change the order in which components appear in the Component Palette, this is the place to make your changes. You can also reach this page by right-clicking the Component Palette and choosing Properties. It is pretty hard to do any serious damage to the environment using this page, but if you feel you need help, just press the Help button on the dialog itself. As you can see, most of the options on these pages address only aesthetic or habit-based preferences regarding how the IDE works. From a development point of view, the key issues involve incremental linking, paths, and saving the source for the Component Palette. Make sure you understand those important issues before moving on to the next topic of discussion. #### Feeling at Home in the IDE To help make the IDE comfortable, you might go to the Options | Environment | Editor page, shown in Figure 2.5. FIGURE 2.5. The Options menu gives you access to the Environments dialog where you find the Editor page. From the Editor page you can make the following changes: Turn the Use tab character option on or off, depending on your liking. (I prefer to turn it off, so I always know exactly what my code will look like regardless of the editor or tab settings I happen to use.) Decide what tab stops you want to use. I set mine to 3 and 5. Choose the Editor speed setting you want. You can choose between the Default keymapping, IDE Classic, Brief, or Epsilon emulations. Go to the Colors page and set the colors you want to use in the editor. Consider setting Undo after save to true so that you can keep a buffer of changes you make, even after you save. There are third-party tools such as SlickEdit, MultiEdit, and CodeWright that have some degree of integration with C++Builder. However, none of these products is able to work as closely with the IDE as one would like, due to limitations in the current Tools API for BCB. #### Converting Forms to Text and Back Everything you can do in BCB through the visual tools you can also do in code. The visual tools are just a means of expediting the programming process. They do not supplant code, they complement it. This is what the Borland marketing department means when they talk about "two way tools." The are two different ways to approach some parts of a BCB project: in code or by using the RAD tools. If you right-click a form, you can select the View as Text menu item to convert a form to text. To convert back, just right-click the text version of the form. BCB also ships with a command-line utility called Convert that will convert DFM files to text, or text to DFM files. At the command line type either
    convert MyForm.dfm
or
    convert MyForm.txt
The first example converts a binary form to a text form with the extension TXT, and the second example reverses the process. If you have 4DOS on your system, you can use the following command to convert all the DFM files in a branch of subdirectories from DFM to text files:
    global /I convert *.dfm
This command will iterate through all the subdirectories below your current position and convert all the files in those directories to text. If you are concerned about archiving files, this is a good way to proceed. In particular, a text file is a much more robust storage medium than a binary file. If you lose one byte of a binary file, it may become worthless. Losing one byte from a text file rarely causes any serious mischief. If you have one form and want to paste all or part of it into a second form, you can select multiple objects from the first form, choose Edit | Copy, focus the second form, and then paste the selections from the first form into it. If you want, you can have an intermediate step where you paste the items from the first form into a text editor such as Notepad, edit them, and then paste them onto a form. NOTE: If you are a Delphi programmer and want to port a form from Delphi to BCB, you might consider using the technique outlined in the last paragraph as a way to proceed. Of course, you can compile your Delphi forms directly in BCB, but if you want to port them, just cutting and pasting to the clipboard is a good way to proceed. Here is a what a BCB button looks like in text form:
    object Button1: TButton

      Left = 96

      Top = 16

      Width = 75

      Height = 25

      Caption = `Button1'

      TabOrder = 0

    end
To get this code, I Alt+Tabbed out of my word processor over to BCB, selected a button on a form, and chose Edit | Copy from the menu. I then Alt+Tabbed back to my word processor, and chose Edit | Paste. During the process the Windows button was automatically converted to text. Here is a second version of the button code that has been slightly modified:
    object MyButton: TButton

      Left = 1

      Top = 16

      Width = 75

      Height = 25

      Caption = `My Button'

      TabOrder = 0

    end
As you can see, I have changed the name of the button from `Button1` to `MyButton`, and I have changed the `Caption` and `Left` properties. Now I can select this text in my word processor, Alt+Tab over to BCB, select and form, and choose Edit | Paste to paste it back into the form. However, this time it has a new name, a new location, and new caption. This is what is meant by a two-way tool. I can edit the form using the visual tools, or I can edit it in a word processor. It works in two different ways, depending on my current needs. NOTE: When working with forms, remember that the currently selected component will be the target for a Paste operation. For instance, if I have selected a `TButton` object, and I chose Paste, BCB will attempt to make the control currently in the clipboard into a child of the button. In most cases, this is not what I want. Instead, I should first select a form or a panel, and then paste the controls onto that object. You also want to make sure the object you are pasting into is big enough to receive the control or controls you are about to dump from the Clipboard. You have now made it through the first section of this chapter. In the next section I am going to switch my approach from a "hot tips" format to a more discursive style. If you want more information of the type you have seen so far in this chapter, you should look in the online help or pick up a book aimed at introductory BCB programming issues. Everyone has to know the kind of information I have been ladling out in the last few pages, and indeed it is vital information, but it is not the subject matter of this book. I have included this much only because I feel many of the issues addressed here are not immediately obvious when you first open BCB, and yet you absolutely have to know these facts in order to get any serious work done in the environment. ### Core Technology: Components, Properties, Delegation Many people are confused about Borland C++Builder. They are not used to the idea of having a RAD tool that works with C++, and they don't know quite what to make of it when they see it. Some people think they are seeing a code generator; others think this is a visual tool meant for programmers who don't want to write code. Some people think they have found a great tool for building databases, and others a tool for prototyping applications. There is some truth to all of these ideas, yet they all miss the mark if your aim is to find the essence of Borland C++. The core pieces of the technology are threefold: Right up front you have components and properties. Buried a little deeper you have the delegation model, which involves events and method pointers. Tying the whole picture together are exceptions and a very sophisticated RTTI system located in a file called `TYPINFO.HPP`. Most programmers rarely have to deal with this side of the product, but it is part and parcel of what makes the tool possible in its current form. These are things that lie at the core of C++Builder. Don't let anyone else lead you astray with tales about prototyping or about BCB being a replacement for PowerBuilder. This tool may in fact perform those roles at times, but that's not what it is all about. NOTE: It may be that from a commercial perspective the majority of programmers will find the database support to be the most valuable aspect of this tool. Indeed, I spend a large portion of this book covering that subject. However, the emphasis on databases is market-driven, while the technological core of the product lies elsewhere. To get at the heart of BCB, you have to understand components, you have to understand the delegation model, and you have to understand RTTI. In particular, the first two points are essential to an understanding of how this product works, while the third helps you understand why it works. You have, no doubt, either already noticed or have heard talk about the fact that BCB has some proprietary extensions to C++. These extensions are there to support the creation and use of components as well as the associated concepts of properties and events that make components so powerful. There was no way to create a product like BCB without extending C++ to support components, properties, and the delegation model. This is a better way to program, and there is no force in the world that can suppress it. I have no problem at all asserting that in five years time, all compilers will support these features and most programmers will use them by two years from now (1999). Let me say it one more time, because this is so crucially important: What's key is the component model, and its reliance on properties and events. Components, properties, the delegation model. Those are the things that stand at the heart of this technology. The three tools make it easy to build databases or multimedia applications. To say that the tool is primarily about building games or databases or Web sites is putting the cart before the horse. The tool is primarily about components, properties, and the delegation model. The other strengths of the tool fall out more or less automatically once the ground work has been laid. #### Why the VCL? Now that you know something about the environment in which BCB exists, it's time to dig a little deeper and start examining the VCL object model used by BCB. The VCL (Visual Component Library) is an object-oriented library designed to ease the process of creating visual components. NOTE: When I say that BCB uses the VCL, I mean for the phrase to be taken in at least two distinct ways. BCB uses the VCL in the sense that the physical IDE is literally built into VCL, and also in the sense that we, as BCB programmers, use the VCL as the object model of choice when creating applications. Borland is not asking you to do anything they wouldn't do. Delphi is built into the VCL. BCB is built into the VCL, and much of Latte, the new Java product, is built into the VCL. The VCL is the tool of choice for people who have a choice. Many C++ programmers who come to C++Builder find themselves wondering why the VCL exists in the first place. What was wrong with OWL or with MFC? Why should there be yet another object framework? The simple answer is that visual programming, RAD, needed a whole new framework with new features. RAD relied on new concepts such as event handlers, properties, property editors, components, component editors, experts, forms, and a slew of other features. The language that implemented these new syntactical elements also desperately needed improvements in the areas of streaming, string handling, object initialization, and referencing. These features simply were not available in either the C++ or Object Pascal versions of OWL. As a result, a new framework was created that supported these features; it is called the VCL, or Visual Component Library. The name goes a long way toward explaining why OWL could never do this job correctly. This is an object-oriented library built around visual components, and visual components do not have even the most oblique reference anywhere in OWL or MFC. They are a completely new entity and required their own object-oriented framework. Having said that, I should add that VCL is closely related to OWL, just as the current version of OWL is closely related to the 16-bit version of OWL from which it grew. If you know OWL, you will find much in VCL that is familiar. Indeed, even MFC is a good background for understanding VCL. However, this is a fundamentally different kind of beast, one that is built around a new concept called a visual component. NOTE: I am aware, of course, that ActiveX is another specification for building visual components. The difference between ActiveX and the VCL is that the VCL is specifically designed to be used with advanced programming languages such as C++ or Object Pascal. ActiveX was designed to be used in a broader context featuring a wide variety of languages and operating systems. ActiveX is more powerful than VCL, but it is also much bigger, much more complex, and slower. #### Come on Charlie, Tell Us What You Really Think! To conclude this brief introduction to the long discussion of the VCL found in this chapter, I feel it is important to explicitly state that I am aware that many hardcore C++ programmers will not automatically greet the VCL and its occasional bits of nonstandard C++ syntax with open arms. When writing this chapter, I am conscious of the need both to explain the VCL and also explain exactly why the VCL exists. I want to make it absolutely clear that I am one hundred and ten percent committed to the VCL, and have absolutely no doubt that it represents the correct model for programming at this point in the ongoing development of programming tools and languages. I will occasionally make statements that explicitly justify some part of the VCL in the face of possible criticisms. These statements do not in any sense represent doubts in my own mind about the VCL. I prefer the VCL to OWL or MFC, and I am absolutely certain that all of the extensions to the C++ language that it introduces are necessary and represent significant advances for the language. I am aware that some readers have large quantities of legacy OWL and MFC code that they want to preserve. I do not take those needs lightly and feel it is my obligation to state explicitly why changes have been made to the C++ object model. BCB enables you to use MFC and OWL code, but the only reason this feature exists is to support legacy code. I personally do not think either MFC or OWL is the best choice any longer for large programming projects. The introduction of the component, property, delegation model offers such vast improvements in our ability to write code, that I don't think it's advisable to use OWL or MFC simply because of the poignant weight of all that legacy code. This is not a criticism of these two excellent object frameworks. The point is simply that they do not support components, properties, or events, and without that support they don't meet my current needs. I simply cannot imagine that anyone else who works with BCB for any significant length of time could possibly come to any other conclusion. I am aware, however, that this is a controversial subject. Over the last four years I have been using the VCL almost every day. Most of that experience is on the Delphi side, but I have also been using BCB every day for about five months at the time of this writing. During the last four years, I have had many occasions to also use MFC and OWL. After my first six months with the VCL, there was never one single time that I went back to MFC or OWL without the feeling that I was using a much loved but outdated system that lacked fundamental features that have become a necessary part of what I believe to be the best contemporary programming model. This doesn't mean that I won't use OWL or MFC if it has an existing object in it that I find appealing, but only that I prefer to use the VCL if that is an option. Indeed, in most cases, the VCL provides for all my needs. If a language or programming model does not support properties, components, and delegation, I personally find it lacking, no matter how many other fine features it may present to the user. VCL is the right way to go, and it would be absurd to read my occasional arguments on its behalf as representative of doubts in my own mind about this programming model. In a sense, my job would be easier if the VCL were harder to use. It was very frustrating for me to realize that I had to start leaving behind all that detailed knowledge about OWL in order to use a system that was so much simpler to use. Wasn't there something that the VCL was missing? Didn't there have to be a catch? How could the solution to so many long-term problems turn out to be so simple? Well, I believe that there isn't a catch, and that the VCL does everything that OWL or MFC did, but does it better. Of course, OWL and VCL have tremendous depth in terms of the number of objects in the existing hierarchy, which is one reason why BCB supports them. You will find, however, the VCL has great depth itself, and that it supports all the features, if not all the objects, found in MFC and OWL. In other words, if you find that a particular object you used in OWL is not part of VCL, you could either use the existing object or create a new one that does the same thing in the VCL. The VCL supports all the features of OWL, but may not at this time have duplicates of all its objects. Furthermore, there is tremendous existing third-party support for the VCL that helps fill in some of the gaps. For good measure, the VCL adds some new tricks regarding components, properties, and events that can't be found in either OWL or MFC. The kicker, of course, is that the VCL produces code that is at least as fast and small as OWL or MFC, but it is literally about ten times easier to use. Let me give it to you straight. Back in the old days I loved OWL and thought it was the greatest thing I had ever seen. I used it all the time and was a fanatical adherent of that programming model. I now use VCL for everything, and go back to OWL or MFC only when I absolutely must. To my eyes, the support for components, properties, and events makes VCL clearly better than OWL or MFC in the same sense that OWL was clearly better than structured programming. If you love OWL, it is sad to hear this kind of thing, but components, properties, and events simply bring something new to the table that OWL and MFC simply can't emulate. It is hard to accept the rate at which programming languages are evolving at this time. The burden this places on programmers is immense. The size of this burden is one of the key reasons I advocate, again and again, doing things the simplest, easiest, safest way. You have enough to worry about without trying to figure out the last picayune details of constantly changing standards! The learning curve associated with the onrush of progress, our attachment to legacy code, a sentimental attachment to the ANSI committee (of all things!)--none of these represent a reason to stick with an outdated technology when a clear advancement in programming tools appears. I obviously have a involvement with Object Pascal. But I am also a long-term (10 years) C++ programmer, and I know about the deep attachment we all feel to the rules of this language, and I know what a huge improvement OWL and MFC represent over structured programming. However, things have changed again, and personally, I love it! VCL is wonderful. I never waste two seconds thinking about going back to the old way of doing things. NOTE: One final note on this subject ought to go out to readers of my Teach Yourself Windows and Teach Yourself Windows 95 Programming books. Those books talk about straight C Windows API programming (a la Petzold) without the aid of any object framework. I do not believe there is anything in this book that makes the material in those books obsolete. To be a good Windows programmer you still have to know the Windows API, and you still have to know about message loops and window procedures. Indeed, in Delphi 2 Unleashed, I went on for several hundred pages about material of that sort. I do not include any of that kind of material in this book because there are many C++ programming books that cover that material. (There were not any, as far as I knew, Pascal books that covered that material, which is why I included it in Delphi 2 Unleashed.) Needless to say, I think you ought to use the VCL to write contemporary Windows programs. However, if you also know the Windows API, you can become a great VCL programmer. If you don't know the Windows API, you will always be at a loss when using some features of the VCL, at least until such time as Windows becomes a true object-oriented operating system. Do you have to know OWL or MFC to become a great VCL programmer? No. Do you have to know the Windows API in order become a great VCL programmer? Absolutely! The Windows API material found in my Teach Yourself... books has a very long life from a technical, if not a commercial, point of view. Assuming that Java does not take over the world, a knowledge of the Windows API is always invaluable to a contemporary programmer. Remember, however, that even the glorious VCL has a shadow over it, in the form of Java. I never get too bogged down in the details of the VCL or any other framework, because I never know when this rapidly changing programming world is going to enter another period of mind-numbing change in which the slow ones get left behind! The Windows API is the only really complex programming paradigm that is worth learning in depth, because all the others are likely to change over time. The fact that the VCL is easy to use is not just a nice feature, it's a necessity in this contemporary programming world where the only constant is change. I should perhaps add that the reason you use the VCL instead of the raw Windows API is because you get your work done in about one-tenth the time. If you use OWL or MFC, your code will be much bigger than if you use raw Windows API code, but you will also have a better chance of getting your work done on time. If you want another four- or five-fold increase in productivity, use the VCL. ### Using the VCL Now that you have heard an advertisement for the VCL, it might help to provide a few more basic examples illustrating some of the virtues of this programming system. These are very simple examples that are a bit atypical of the type of code you will see in this book, or even in the latter portions of this chapter. I feel, however, that these basic examples are useful when illustrating some of the key features of RAD programming with the VCL. Their presence ensures that everyone understands the benefits of visual programming with the VCL. I will, however, use these basic examples to explore some fairly complex aspects of the VCL, and especially of the code that executes just before and after the main form of your application is made visible. In particular, I will look at the code in the project source file for a typical BCB application that uses the VCL. The first program I want to discuss uses a standard Delphi component called `TShape`. If you open up BCB and drop the `TShape` component on a form, you will see that it draws a simple white rectangle on the screen. Of course, the `TShape` object can perform more than this one simple trick. For instance, if you pull down the list associated with the `Shape` property in the Object Inspector, you see that you can easily work with ellipses, circles, squares, and other assorted shapes. Furthermore, if you expand the `Brush` property, you can change the shape's color. The `pen` property enables you to change the width and color of the outline of a `TShape` object. NOTE: Don't forget that you can expand properties that have a plus sign (+) next to them by double-clicking the property's name. A `Color` property always has a dialog associated with it. To bring up the dialog, double-click the area to the right of the `Color` property. This area is called the property editor. (Later in the book I will show how to create your own property editors and how to use existing property editors.) Select a color from the dialog, click the OK button, and the color you chose automatically takes effect. As just described, it's trivial to change the major characteristics of a `TShape` object at design time. However, I spoke earlier about BCB supporting two-way tools. Anything that you do with the visual tools you can also do in code. It is, of course, a little more work to make the same changes at runtime that you made at design time, but the basic principles are still simple. The SHAPEDEM and SHAPEDEM2 programs on the CD that accompanies this book show you how to proceed. NOTE: I try to avoid it, but you might find a few places in the sample programs where I hard-code in the path to a file. You will probably have to edit these paths to get the program to run on your system. I go to a great deal of effort to ensure that the code that accompanies this book works correctly. If you are having trouble running any particular program, check the readme files found on the CD that accompanies this book. If you still can't get the program running, go to my Web site and see if there is an update, hint, or bug report available. My Web site is `users.aol.com/charliecal`. At its core, the SHAPEDEM program consists of nothing more than a `TShape` object placed on a form, along with two scroll bars and a menu. What's interesting about the program is the ease with which you can change the size, color, and shape of the `TShape` object at runtime. You can find the code for the program in Listings 2.1 through 2.3. Remember that if you want to view the source for the project file in your application, you can select the View | Project Source menu item. Listing 2.1. The code for SHAPEDEM.CPP.
    #include <vcl.h>

    #pragma hdrstop

    USEFORM("Main.cpp", Form1);

    USERES("ShapeDem.res");

    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

    {

      Application->Initialize();

      Application->CreateForm(__classid(TForm1), &Form1);

      Application->Run();

      return 0;

    }
Listing 2.2. The header for the main unit in SHAPEDEM.
    #ifndef MainH

    #define MainH

    #include <Classes.hpp>

    #include <Controls.hpp>

    #include <StdCtrls.hpp>

    #include <Forms.hpp>

    #include <ExtCtrls.hpp>

    #include <Dialogs.hpp>

    #include <Menus.hpp>

    class TForm1 : public TForm

    {

    __published:

      TShape *Shape1;

      TScrollBar *ScrollBar1;

      TScrollBar *ScrollBar2;

      TColorDialog *ColorDialog1;

      TMainMenu *MainMenu1;

      TMenuItem *Shapes1;

      TMenuItem *ShapeColor1;

      TMenuItem *FormColor1;

      TMenuItem *Shapes2;

      TMenuItem *Rectangle1;

      TMenuItem *Square1;

      TMenuItem *RoundRect1;

      TMenuItem *RoundSquare1;

      TMenuItem *Ellipes1;

      TMenuItem *Circle1;

      void __fastcall ShapeColor1Click(TObject *Sender);

      void __fastcall FormColor1Click(TObject *Sender);

      void __fastcall Rectangle1Click(TObject *Sender);

      void __fastcall ScrollBar1Change(TObject *Sender);

      void __fastcall ScrollBar2Change(TObject *Sender);

      void __fastcall FormResize(TObject *Sender);

    private:

    public:

      virtual __fastcall TForm1(TComponent* Owner);

    };

    extern TForm1 *Form1;

    #endif
Listing 2.3. The code for the main unit in SHAPEDEM.
    #include <vcl.h>

    #pragma hdrstop

    #include "Main.h"

    #pragma resource "*.dfm"

    TForm1 *Form1;

    __fastcall TForm1::TForm1(TComponent* Owner)

      : TForm(Owner)

    {

      Shape1->Left = 0;

      Shape1->Top = 0;

    }

    void __fastcall TForm1::ShapeColor1Click(TObject *Sender)

    {

      if (ColorDialog1->Execute())

        Shape1->Brush->Color = ColorDialog1->Color;

    }

    void __fastcall TForm1::FormColor1Click(TObject *Sender)

    {

      if (ColorDialog1->Execute())

        Form1->Color = ColorDialog1->Color;

    }

    void __fastcall TForm1::Rectangle1Click(TObject *Sender)

    {

      Shape1->Shape = TShapeType(dynamic_cast<TMenuItem*>(Sender)->Tag);

    }

    void __fastcall TForm1::ScrollBar1Change(TObject *Sender)

    {

      Shape1->Width = ScrollBar1->Position;

    }

    void __fastcall TForm1::ScrollBar2Change(TObject *Sender)

    {

      Shape1->Height = ScrollBar2->Position;

    }

    void __fastcall TForm1::FormResize(TObject *Sender)

    {

      ScrollBar1->Max = ClientWidth - (ScrollBar2->Width + 1);

      ScrollBar2->Max = ClientHeight - (ScrollBar1->Height + 1);

      ScrollBar1->Left = 0;

      ScrollBar2->Top = 0;

      ScrollBar2->Left = ClientWidth - ScrollBar2->Width;

      ScrollBar2->Height = ClientHeight;

      ScrollBar1->Top = ClientHeight - ScrollBar1->Height;

      ScrollBar1->Width = ClientWidth - ScrollBar2->Width;

    }
In the next few paragraphs, you'll hear a discussion of how to change the color of the form, the shape shown on the form, and the size and shape of the object itself. When you run the SHAPEDEM program, it looks like the screen shot shown in Figure 2.6. Use the program's scrollbars to change the size of the figure in the middle of the screen. Use the menu to select a new shape for the object and to bring up a dialog that enables you to change the color of either the form or the shape. ###### FIGURE 2.6. You can use the scrollbars and buttons to change the appearance of the SHAPEDEM program's form. #### The Project Source: Where Pascal Meets the C Before getting into any details about how the ShapeDem program works, it might be helpful to take one moment to look at the project source. You can access the project source from the View menu. This is the place in the book I have chosen to give you a close look at how Borland blended its Pascal and C++ technology into one product. I will not show much Object Pascal code in this book, but you will see quite a bit in the next few pages. At the top of the project source you see code that brings in the VCL:
    #include <vcl/vcl.h>

    #pragma hdrstop
In many programs, you will not have to add any other `include` statements to your program other than this one, except when you want to include other units from your current project, and even that can be automated through the File Include Unit Hdr menu option. That's not a hard and fast statement; I only mean to imply that you don't tend to spend a lot of time adding `include` statements unless you want to access obscure features of the Windows API. Many other `include` statements will be added to your header files, however, when you drop components down on a form. The `pragma` statement shown here tells the compiler that you only want to have the VCL in your precompiled headers. Any additional files should be recompiled each time you do a build or a make. This is done for the sake of efficiency, because your own header files are likely to change on a regular basis. The next few lines tell the project manager to bring in forms or resources:
    USEFORM("Main.cpp", Form1);

    USERES("ShapeDem.res");
You would not normally add this kind of code yourself, but would ask the visual tools to insert it for you. In this case, the tool you would use is the Project Manager from the View menu. However, you don't have to use the Project Manager; you can make this changes manually if you wish, and the Project Manager will pick up on your work. Here is the `WinMain` block for your program:
    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

    {

      Application->Initialize();

      Application->CreateForm(__classid(TForm1), &Form1);

      Application->Run();

      return 0;

    }
As you can see, BCB assumes you won't be using any of the parameters passed to it. In particular, the VCL provides a global variable called `HInstance`, which provides the `HInstance` for your application. The `HPrevInstance` variable is never used in Win32 programming. Parameters passed to your program are available in the form of a VCL function called `ParamStr`, and a variable called `ParamCount`. To get at the name and path of your executable, access `ParamStr(0)`, to get at the first parameter passed to it, access `ParamStr(1)`, and so on. `ParamCount` contains the number of parameters passed to your executable. For instance, the following code pops up a message box showing the name and path of your executable:
    void __fastcall TForm1::Open1Click(TObject *Sender)

    {

      ShowMessage(ParamStr(0));

    }
NOTE: Wary C++ programmers may be concerned about the fact that the VCL has gotten at the `HInstance` and program parameters before they reached `WinMain`. Don't worry, there is no huge subsystem underlying your entire program! However, a few things do happen before `WinMain` is called, just as a few things happen in all C++ compilers before `WinMain` is called. This is a case where it might help to talk about how Object Pascal handles program startup. Object Pascal simply did not support `WinMain` on the grounds that it was faster and more convenient to perform processing of `HInstance` and the program parameters without setting up a stack frame for a function call. The Object Pascal system is faster and more efficient because you don't have to push things on the stack before calling a function named `WinMain`. On the other hand, the overhead of calling `WinMain` with four parameters is hardly significant in the face of the time it takes to load a contemporary Windows program into memory. Of course, BCB provides a `WinMain` for you so you will be able to compile standard C++ programs without modification. The key point to notice here is that the VCL provides extra support for you without affecting the performance of your program and without changing the way that C++, or standard Windows programs, operate. This is the right way to handle the interface between C++ and Object Pascal. No changes to C++, no impact on performance, no changes to the standard Windows programming model, and yet additional features are provided for the programmer in terms of `ParamStr` and the global `HInstance`. After getting to `WinMain`, the program uses the pre-initialized `Application` object to get your program up and running:
      Application->Initialize();

      Application->CreateForm(__classid(TForm1), &Form1);

      Application->Run();
I will discuss each of these calls in their own sections of this chapter. Brace yourself, because I am going to step you through the Object Pascal code that underlies each of these calls. #### Initializing the Application The first call in `WinMain` performs some initialization:
    Application->Initialize();
The two most important tasks performed by this code involve OLE and database code. If there is database programming in your application, the database code starts an object called `TSession`. If there is OLE code in your program, the program may call a method that updates the Registry automatically so that your program is a properly registered automation server. If the code uses neither technology, nothing happens in the call to initialize. Here is the code for the `Initialize` method of `TApplication` as it appears in `Forms.pas`:
    procedure TApplication.Initialize;

    begin

      if InitProc <> nil then

        TProcedure(InitProc);

    end;
If you want to step through this code, simply copy `Forms.pas`,`Controls.pas`, `Classes.pas`, and `VCL.INC` from the `BCB\SOURCE\VCL` subdirectory into your project directory and add `Forms.pas`,`Controls.pas`, and `Classes.pas` to your C++ project. To add the files, bring up the Project Manager from the View menu, click the plus button, and use the drop-down list from the Files of Type section to browse for files with a `.pas` extension. Next, select `Forms.pas`,`Classes.pas`, and `Controls.pas`, and close the Project Manager. This technique is probably preferable to bringing in the source to the whole VCL by adding the `CBuilder\SOURCE\VCL` to the include or library path for your project. When you step through this Object Pascal code in the BCB integrated debugger, you will find that `InitProc` is never called, because it is set to `NULL` unless you bring in database code or OLE automation code. Needless, to say, it takes one line of assembly code to test for `NULL`, so there is no significant overhead involved here other than the call to the `Initialize` method itself. Here is the code at the bottom of the `OLEAuto` unit that would initialize `InitProc` if you used `OLEAutomation` in your program:
    initialization

    begin

      OleInitialize(nil);

      VarDispProc := @VarDispInvoke;

      Automation := TAutomation.Create;

      SaveInitProc := InitProc;

      InitProc := @InitAutomation;

    end;

    finalization

    begin

      Automation.Free;

      OleUninitialize;

    end;

    end.
This call starts by initializing OLE and then setting up a dispatch point for use when making calls into `IDispatch`. Next, it allocates memory for the `Automation` object, calls its constructor, and finally points `InitProc` at the proper method after saving the previous value of the function pointer. Of course, none of this code will be called unless you are using OLE Automation in your program through the routines found in the `OleAuto` unit. #### Creating Forms The second call in `WinMain` creates the `MainForm` for your application:
    Application->CreateForm(__classid(TForm1), &Form1);
You already have the `Forms` unit linked into the project, so you can step into this code without any further work. However, if you want to get into more detail here, you can also add `Classes.pas` and `Controls.pas` to your project. However, there are very few users of the VCL who really need to know what happens in either controls or classes. Here is the call to `CreateForm`:
    procedure TApplication.CreateForm(InstanceClass:

    TComponentClass; var Reference);

    var

      Instance: TComponent;

    begin

      Instance := TComponent(InstanceClass.NewInstance);

      TComponent(Reference) := Instance;

      try

        Instance.Create(Self);

      except

        TComponent(Reference) := nil;

        raise;

      end;

      if (FMainForm = nil) and (Instance is TForm) then

      begin

        TForm(Instance).HandleNeeded;

        FMainForm := TForm(Instance);

      end;

    end;
The vast majority of this code does nothing but initialize variables or check for errors. The base VCL object is called `TObject`. All VCL objects descend from `TObject` by definition. It is impossible to create a VCL object that does not descend from `TObject`, because any object that does not descend from `TObject` is not part of the VCL. The call to `TObject.NewInstance` does nothing more than allocate memory for an object and return a pointer to it, as you can see from viewing this call in `System.pas`:
    class function TObject.NewInstance:TObject;

    asm

            PUSH    EDI

            PUSH    EAX

            MOV     EAX,[EAX].vtInstanceSize

            CALL    _GetMem

            MOV     EDI,EAX

            MOV     EDX,EAX

            POP     EAX

            STOSD   { Set VMT pointer }

            MOV     ECX,[EAX].vtInstanceSize{ Clear object }

            XOR     EAX,EAX

            PUSH    ECX

            SHR     ECX,2

            DEC     ECX

            REP     STOSD

            POP     ECX

            AND     ECX,3

            REP     STOSB

            MOV     EAX,EDX

            POP     EDI

    end;
Needless to say, this is probably the only place you will ever see anyone allocate memory for an object by calling `NewInstance`. As a rule, the constructor for an object will call `NewInstance` automatically. Here is the standard code for creating an object:
    TMyObject *MyObject = new TMyObject();
This will call `NewInstance` for you automatically, and it would be madness to proceed in any other fashion. NOTE: `TObject.NewInstance` is what is called in Object Pascal a class method and what C++ implements as a static method. Class methods and static methods can be called without an object instance; that is, they can be called before you allocate memory for an object or call its constructor. Class methods could have been implemented as functions that are associated with a class, and indeed, there is no significant difference between a function associated with a class and a class method. However, it is syntactically useful from the user's point of view to include them in a class declaration, because it makes the association between the class and the method obvious. In other words, class methods are aesthetically pleasing, and they help you create logical, easy-to-read code. Besides `NewInstance`, the following methods of `TObject` are all class methods: `ClassName`, `ClassNameIs`, `ClassParent`, `ClassInfo`, `InstanceSize`, `InheritsFrom`, `MethodAddress`, and `MethodName`. These methods are segregated out of the BCB declaration for `TObject` and declared as a class with the somewhat intriguing name `TMetaClass`. This metaclass is a trick that allows C++ to get along with the VCL and its associated RTTI. `TMetaClass` plays no significant role in standard BCB programming and is designed primarily for the use of the compiler team itself. You may have occasion to use this metaclass when working with RTTI, but as a rule, it lies outside the realm of standard BCB programming. If you have the time and inclination to pursue this matter, the whole class is declared and implemented in `SYSDEFS.H`. For instance, the `ClassType` method of `TObject` returns a variable of type `TClass`, and `TClass` is defined as a pointer to `TMetaClass`. You can use variables of this type to perform the same kinds of comparisons you would perform on standard C++ classes with `typeid`. The most important call in `TApplication` `CreateForm` is to `Instance.Create(Self)`. It is the call that ends up calling the constructor for the main form, as well as calling the Windows API `CreateWindowEx` function. If you step into this code with the debugger, you will find that it ends up stepping right into the constructor for your main form:
    __fastcall TForm1::TForm1(TComponent* Owner)

      : TForm(Owner)

    {

    }
The last few lines of code in the `CreateForm` method set the variable `FMainForm` to the current form if it has not already been assigned. The main form for your application will be the one that appears first when someone launches your executable. As you can see from examining the code in `CreateForm`, the first object passed to `CreateForm` will be the main form for that application:
      if (FMainForm = nil) and (Instance is TForm) then

      begin

        TForm(Instance).HandleNeeded;

        FMainForm := TForm(Instance);

      end;
Each project that you create can have zero, one, or more forms. You can add forms to a project from the File menu or from the File | New menu choice. If you add three forms to a project, this is what the project source looks like:
    Application->Initialize();

    Application->CreateForm(__classid(TForm1), &Form1);

    Application->CreateForm(__classid(TForm2), &Form2);

    Application->CreateForm(__classid(TForm3), &Form3);

    Application->Run();
In this case, `Form1` will be the main form for the application. If you change the order of these statements, another form could become the main form:
    Application->Initialize();

    Application->CreateForm(__classid(TForm3), &Form3);

    Application->CreateForm(__classid(TForm1), &Form1);

    Application->CreateForm(__classid(TForm2), &Form2);

    Application->Run();
In the preceding code, `Form3` is now the main form for the application. Normally, I do not edit the project source for my application directly. Instead, I go to the Options | Project menu item and use the Forms page from the Project Options dialog to make these kinds of changes. Once again, this is a two-way tool, and you can do things visually via the Project Options dialog or you can do things manually in code. It's up to you to make the decision. #### Calling Run: Finding the Message Loop The last call in `WinMain` is to the `Run` method:
    Application->Run();
`TApplication.Run` does a few initialization chores, and then calls a method called `HandleMessage` that in turn calls `ProcessMessage`:
    function TApplication.ProcessMessage: Boolean;

    var

      Handled: Boolean;

      Msg: TMsg;

    begin

      Result := False;

      if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then

      begin

        Result := True;

        if Msg.Message <> WM_QUIT then

        begin

          Handled := False;

          if Assigned(FOnMessage) then FOnMessage(Msg, Handled);

          if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and

            not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then

          begin

            TranslateMessage(Msg);

            DispatchMessage(Msg);

          end;

        end

        else

          FTerminate := True;

      end;

    end;
This is the standard message loop that lies at the bottom of all Windows applications. As you can see, it calls `TranslateMessage` and `DispatchMessage` just like every other message loop in every other Windows application. The `HandleMessage` routine that calls `ProcessMessage` also ends up calling a method named `Idle`. If you hook the `OnIdle` handler to `TApplication`, you can get a chance to perform background tasks while your application is running. It is generally not a good idea to respond to `OnIdle` events unless you are absolutely positive you know what you are doing. On the other hand, I would not suggest starting up a second `PeekMessage` loop in your application, so if you have to do background processing, I would indeed do it in response to `OnIdle`. You now know what happens when a VCL application is first launched. I've shown it to you in such depth for two reasons: You need to know this information if you are going to use BCB for serious work. You have to understand how your application is launched, where the message loop is, and how forms are allocated. There has to be some time when you actually see the place where C++ and Object Pascal meet. So now you've seen it. The point I hope you take home from this is that there just plain isn't any real difference between C++ and Object Pascal. There may be a difference between ANSI C and ANSI Pascal, but C++ and Object Pascal are the same. Certainly there is no significant difference in the way the two languages perform or in the capabilities of the two languages. It should also now be obvious that the compiler just doesn't care which language you use. I mix and match C++ and Object Pascal all the time. I know both languages well enough so half the time I am not even conscious of which language I'm using. You can find a language bigot on every street corner. What's rare is to find someone who can look beneath the surface and see that at bottom the two languages are virtually identical. The differences are almost all superficial, and they tend to cancel each other out. C++ does some things better than Object Pascal, and Object Pascal does some things better than C++. Who cares? The point is they are both great languages. Now you can use them both together without penalty, so you can take the best from both worlds. #### Creating the ShapeDem Program It's time now to come back to the original purpose of this section of the chapter, which is to examine the ShapeDem program. To create the program yourself, start by dropping down a `TMainMenu` and a `TColorDialog`. The `TColorDialog` is found on the Dialogs page of the Component Palette, while the `TMenu` is on the Standards page. Now create a menu heading called Options and beneath it two menu items with captions that read `Shape Color` and `Form Color`. NOTE: I briefly introduced using the Menu Designer in Chapter 1. Remember that you can get help on most (in a perfect world it would be all) BCB components, code elements, or tools by selecting the item in question and pressing F1. After closing the menu designer, double-click the menu item you made called `Form Color` to create a method in the editor that looks like this:
    void __fastcall TForm1::FormColor1Click(TObject *Sender)

    {

      if (ColorDialog1->Execute())

        Form1->Color = ColorDialog1->Color;

    }
When you run the program, the code shown here pops up the `ColorDialog`, as shown in Figure 2.7. FIGURE 2.7. The Color Dialog gives the user an easy way to select a valid color at runtime. If the user clicks the OK button in the form, the following line of code is executed:
    Form1->Color = ColorDialog1->Color;
This line of code sets the `Color` property for `Form1` to the color that was selected by the user inside of `ColorDialog1`. The technique just shown can be used to change the color of the `TShape` object. All you need to do is drop down a `TShape` object from the additional page, and then associate some code with the Shape Color menu item:
    void __fastcall TForm1::ShapeColor1Click(TObject *Sender)

    {

      if (ColorDialog1->Execute())

        Shape1->Brush->Color = ColorDialog1->Color;

    }
What could be simpler? You should now run the SHAPEDEM program so that you can see how easy it is to change the color of the elements on the form. Of course, you don't have to give the user the exclusive right to control all the elements of your program. Sometimes you can take the initiative. For instance, you could change the color of your form or of an element on your form in order to focus the user's attention on a particular part of the screen. Notice that the code written here is all but self-documenting. Anyone with even the slightest acquaintance with programming can just glance at this procedure and determine what it does. Assuming you have more than a passing acquaintance with programming, here is how to translate the code into English: "If the user clicks on a visual element on `Form1` that is called `ShapeColor1`, that visual element will delegate an activity to `Form1`. That activity consists of popping up a color dialog and asking the user to make a selection. If the user chooses the OK button, the color of `Shape1` is set to the color selected in the `TColorDialog` object." What do I mean when I say that the `ShapeColor` menu item "delegates" an activity to `Form1`? Well, this means that the `ShapeColor` `TMenuItem` object does not itself handle being clicked, but instead allows the form to decide what happens when someone clicks it. It delegates the job to the main form. The delegation model works through events, which are listed in the Object Inspector on the page sitting next to the properties for an object. Some people call events closures, though I regard that as a very technical term with certain platform-specific ramifications that I have never fully explored. As a result, I will usually play it safe and call events nothing more than events and leave it at that. The delegation model is implemented through events, and events are explored in depth in Chapter 3, "Events," and Chapter 4, "Exceptions." In the beginning, it is probably simplest to think of events as being similar to standard Windows messages, such as `WM_CREATE`, `WM_COMMAND`, or `WM_VSCROLL`. Indeed, handling standard Windows messages is one of the functions of events. However, you will see that events can also delegate to another control tasks that you usually could not handle unless you subclassed a component such as an edit control, or else descended from an object that wrapped a control, as you would in OWL or MFC. Perhaps an acceptable first crack at defining events would be to say that: "Events allow you to delegate tasks from one component to another component so that you do not have to subclass the first component, nor respond inside a window procedure to messages that the first control generates. In particular, events are usually delegated by the controls on a form to the form itself." The advantages of the delegation model are threefold: They do not force you to subclass a control, nor inherit from a class in order to override one of its properties. For instance, you can change an edit control's behavior without subclassing the control or descending from an OWL or MFC type object that wraps the control. They enable you to forgo the ugly, lengthy, and confusing `switch` statement found in standard window procedures. It provides for contract-free programming. You can do whatever you want in an event handler. There are no rules binding what you can and cannot do inside an event handler. Any code you can write legally elsewhere in a program you can also write in an event handler. It makes sense that it should not be very difficult to change the color of an object found on one of the forms you create. But using scrollbars to change its shape at least appears to be a more difficult task. In fact, experienced Windows programmers know that using scrollbars in a Windows program can be a fairly difficult task, one that requires you to trap and parse a number of messages in a complex `switch` statement. BCB, however, reduces the entire task of responding to a scrollbar to a single line of code. To get started, first drop two scrollbars on the screen and set the `Kind` property of one of them to `sbHorizontal`, and the `Kind` property of the other to `sbVertical`. Now, turn to the events page of the Object Inspector and create a method for the `OnChange` event of each scrollbar. Fill in the methods with two lines of code so that they look like this:
    void __fastcall TForm1::ScrollBar1Change(TObject *Sender)

    {

      Shape1->Width = ScrollBar1->Position;

    }

    void __fastcall TForm1::ScrollBar2Change(TObject *Sender)

    {

      Shape1->Height = ScrollBar2->Position;

    }
The code shown here sets the `Width` and `Height` of the `TShape` object to the current position of the thumb on the scrollbar. Clearly it is extremely easy to write BCB code that performs a task, which would be relatively complex to execute if you had to work directly with the Windows API. The VCL always makes you feel as though you are working directly with an object, and tries to hide the complexities that are introduced by the Windows API or by standard object frameworks. NOTE: Note in particular that you don't have to first set a property of a control and then ask it to redraw itself! This magic is the result of the set method associated with the `Height` property of `Shape1`. I will explore the `Set` and `Get` methods of properties later in this chapter. You use the program's menu to change the shape of the `TShape` component. In particular, a portion of the main menu for the program should have the following items on it:
    Rectangle1: TMenuItem

    Tag = 0

    Caption = `Rectangle'

    Square1: TMenuItem

    Tag = 1

    Caption = `Square'

    RoundRect1: TMenuItem

    Tag = 2

    Caption = `RoundRect'

    RoundSquare1: TMenuItem

    Tag = 3

    Caption = `RoundSquare'

    Ellipes1: TMenuItem

    Tag = 4

    Caption = `Ellipse'

    Circle1: TMenuItem

    Tag = 5

    Caption = `Circle'
The `Tag` field is a special field associated with all components that can be set to an integer value. The VCL has no use for this field; it is designed explicitly for you to use as you wish, for whatever purpose you want. All six menu items should be associated with the same event handler through their `OnClick` method. You can create the original handler by open up the Menu Designer, turning to the Events page in the Object Inspector, and double-clicking the `OnChange` event. If you then select the `OnChange` event for the other menu items, you will see that it opens up into a combo box from which you can select all the compatible events. For each of the other five menu items, select the event you created for the first menu item. The event itself should look like this:
    void __fastcall TForm1::Rectangle1Click(TObject *Sender)

    {

      Shape1->Shape = TShapeType(dynamic_cast<TMenuItem*>(Sender)->Tag);

    }
I will explain what this code means over the course of the next few paragraphs. NOTE: Just now I said that the events that appear in the drop-down combo for the Events page of the Object Inspector must be compatible with a particular event. This means that they must have the same signature, which is yet another term that needs explanation! The signature of an event is found in the header for the method handler associated with a particular event, and in particular it is represented by the parameters passed to the handler. For instance, the signature for the `Rectangle1Click` method is represented by the fact that it is a method that returns nothing and which accepts a single parameter of type `TObject *`. Methods that look like this are of type `TNotifyEvent`. Here is the declaration for `TNotifyEvent` as it appears in `CLASSES.HPP`:

    typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);

> When you see this signature for an event, you can assume that `Sender` contains an instance of the object that sent the event. For instance, in the case currently under consideration, it is a `TMenuItem` that sent the event, and the specific `TMenuItem` that sent the message is passed in the `Sender` parameter.

The items in the menu designate each of the possible shapes the `TShape` component can assume. You can find these words listed in the online help under the listing for `TShapeType`. Or, if you want to go back to the original source code, you find the following enumerated type:

    enum TShapeType { stRectangle, stSquare, stRoundRect,

                      stRoundSquare, stEllipse, stCircle }

> NOTE: You can also access the names of the members of enumerated type by using the `GetEnumName` and `GetEnumValue` functions from the `TypInfo` unit, which is pronounced "tip-info."

In this particular case, you need to write only one line of code in response to the event that occurs when a user clicks a `TMenuItem`:

    Shape1->Shape = TShapeType(dynamic_cast<TMenuItem*>(Sender)->Tag);

This line of code sets the `Shape1->Shape` property to the shape that the user has selected in the combo box. The code works because of the correspondence between the ordinal members of an enumerated type and the numerical value you assigned to the `tag` property of a menu. In other words, the first element in an enumerated type has the value zero, as does the first `tag` property.

You know, and I know, that the `Sender` variable contains an instance of the `TMenuItem` item class. However, the wonders of polymorphism allow BCB to declare this variable to be of type `TObject`. That way, a `TNotifyEvent` can accept objects of any type. (Polymorphism will be addressed later in the book in Chapter 21, "Polymorphism.")

The programmer's knowledge of the `Sender` parameter needs to be shared with the compiler. In other words, you and I need to have some way of telling the compiler that the object is not really of type `TObject`, but that it is a just a polymorphic disguise for a `TMenuItem`. This is an important step because the `TObject` class does not have a `Tag` field, and the `TMenuItem` class does have a `Tag` field. In this case, it is absolutely necessary to get at the `Tag` field because it contains the code information about the shape the user wants to select.

To cast a `TObject` as a `TMenuItem` you can use the `dynamic_cast` syntax. This syntax can be used as part of RTTI to test whether a component is of a particular type, or it can be used to actually make the cast. In this case I am daring and make the cast without bother to test it first. This is safe in this case because I know the only object that can be passed here is a `TMenuItem`. However, if I wanted to be extra careful, I could write the following:

    if (dynamic_cast<TMenuItem*>(Sender))

      Shape1->Shape = TShapeType(dynamic_cast<TMenuItem*>(Sender)->Tag);

This would ensure that no exceptions were raised if the cast should happen to fail, which it won't in this particular case.

The final part of the `ShapeDem` program that is worthy of discussion involves making sure that the scrollbars cling to the bottom and right edges of the control. To do this, you need to respond to `WM_SIZE` messages, which come to BCB programmers under the friendly guise of an `OnResize` event:

    void __fastcall TForm1::FormResize(TObject *Sender)

    {

      ScrollBar1->Max = ClientWidth - (ScrollBar2->Width + 1);

      ScrollBar2->Max = ClientHeight - (ScrollBar1->Height + 1);

      ScrollBar1->Left = 0;

      ScrollBar2->Top = 0;

      ScrollBar2->Left = ClientWidth - ScrollBar2->Width;

      ScrollBar2->Height = ClientHeight;

      ScrollBar1->Top = ClientHeight - ScrollBar1->Height;

      ScrollBar1->Width = ClientWidth - ScrollBar2->Width;

    }

This code uses third grade math (the only kind I ever understood!) to ensure that the scrollbars are allowed as tall or as wide as the form, no matter how it is stretched or pulled by the user. Furthermore, it ensures that the `Min` and `Max` property for the control ranges from zero to the exact size of the current client window. This ensures that you can use the `OnChange` event for the scrollbar to make the `TShape` object as large as the client window, but no larger.

Notice also that the `TForm` object has properties called `ClientWidth` and `ClientHeight`. These properties calculated the client size of the current window; that is, the size of the window minus the menu, caption, and frame. If this was done for you, you would have to write code that looked something like this:

    int Menu, Caption, Frame;

    Caption = GetSystemMetrics(SM_CYCAPTION);

    Frame = GetSystemMetrics(SM_CXFRAME) * 2;

    Menu = GetSystemMetrics(SM_CYMENU);

    ScrollBar1->Left = 0;

    ScrollBar2->Top = 0;

    ScrollBar1->Max = Width;

    ScrollBar2->Max = Height;

    ScrollBar2->Left =  Width - Frame - ScrollBar2->Width;

    ScrollBar2->Height = Height - Frame - Caption- Menu;

    ScrollBar1->Top = Height - ScrollBar2->Width - Frame - Caption - Menu;

    ScrollBar1->Width = Width - ScrollBar2->Width - Frame;

The point here is that without having to know about `GetSystemMetrics` and all its associated constants, you can still write code that calculates the size of the `TShape` object down to the last pixel.

#### A First Look at RTTI and TypInfo

If you look on the disk, you will find a second copy of the ShapeDem program, called ShapeDem2, that uses a combo box as well as a menu to let the user select the current shape of the object. For instance, you can drop down the combo box and pick a shape such as `stCircle` or `stSquare`. These shapes have funny-looking Hungarian squiggles prefixed to them because they are taken directly from the source code of the program at runtime rather than typed in by the programmer at design time. In the next few paragraphs I explain how to use that control, primarily because it also contains an interesting description of how to use Run Time Type Information.

You would think that you need to explicitly type in the names of the shapes that appear in the combo box. For instance, you might assume you need to manually type in the words `stCircle` and `stSquare`, and so on. These are the same names you see listed in the Object Inspector for the `Shape1` object under the property called `Shape`, and they are the same words that appear in the combo box at runtime. In other words, if you highlight `Shape1` on the form and look at the `Shape` property in the Object Inspector, you find a list of the possible shapes that can be associated with this object. These are the same shapes you should list in the combo box.

As I said earlier, it's not possible to get access to the Object Inspector at runtime. As a result, if you wanted to explicitly type in the names, you would need to first pop open the Property editor for the `Items` property, and then manually type these names. To get started, first highlight the combo box on the form by clicking it. Then, double-click the right side of the `Items` property in the Object Inspector, or you can click the [...] button on the `Strings` property once. This pops up a String list editor, as shown in Figure 2.8.\
FIGURE 2.8. The String list editor enables you to type in a set of default names that appear in a combo box.

> NOTE: In the bottom-left corner of the String list editor is a button that says "Code Editor." If you press this button you can edit your list inside the regular editor for the IDE. This can be especially useful with SQL query statements, which actually provide syntax highlighting. You access the SQL list editor from inside a `TQuery` component as explained in Chapter 10, "SQL and the `TQuery` Object."

The actual items that you would type into the String list editor are shown next. Be sure to type them in exactly as shown, and in the identical order.

    stRectangle

    stSquare

    stRoundRect

    stRoundSquare

    stEllipse

    stCircle

Now when you run the program, the user can drop down this list and select a shape. Here is the code associated with the `OnClick` event for the combo box:

    void __fastcall TForm1::ComboBox1Change(TObject *Sender)

    {

      Shape1->Shape = TShapeType(ComboBox1->ItemIndex);

    }

As you can see, there is no significant difference between this code and the code written in response to a click on the shapes listed in the menu. Of course, in this case you don't have to perform a dynamic cast, but that is a mere bagatelle.

The interesting thing about this second version of the ShapeDem program is the code that appears in the constructor for the form:

    __fastcall TForm1::TForm1(TComponent* Owner)

      : TForm(Owner)

    {

      int i;

      PPropInfo PropInfo = GetPropInfo(PTypeInfo(ClassInfo(__classid(TShape))),"Shape");

      for (i = 0; i < 6; i++)

        ComboBox1->Items->Add(GetEnumName(PropInfo->PropType, i));

      ... // Code irrelevant to this example omitted here.

    }

This code uses RTTI to retrieve the names of the enumerated type that underlies the `Shape` property for the `TShape` object.

All VCL classes are illuminated with type information. You can find out virtually anything you want about these published properties of a class at runtime merely by asking through one or more of the functions in the `TypInfo` unit.

RTTI is an essential part of RAD programming because there must be a way for the Object Inspector to query an object about its published properties. For instance, the Object Inspector has to list the names of the `TShapeType` so that you can select them from the Property editor for the `Shape` property. The code shown in the constructor for the main form of this application uses the same technique to retrieve this information that the Object Inspector uses. It would not do to have BCB developers type in this information manually before releasing the project because the Object Inspector must be able to retrieve this information for any component, including the ones that you create or find after purchasing the product.

Are classes illuminated with RTTI larger than non-illuminated classes? You bet! RTTI is bought at a price. However, it is a price that I am willing to pay for two reasons:

- It makes RAD possible, as described previously in the text that explains how the property types are listed in the Property editor.

- It enables me to query objects at runtime. Querying objects at runtime gives me the ability to create generic code that will work automatically, regardless of the type of object I pass to it. For instance, the RTTI example using `dynamic_cast` shown previously explains how you can safely test the type of an object before performing an action on it. You will see many examples of that type of code in this book, including cases where you can pass an entire form to a routine, and ask that routine to perform some function on all the controls of a certain type on that form. Generic code of that type can be tested once and then used over and over again with multiple objects. The ability to talk to an object and ask it its type gives us the ability to manage objects automatically. This can be especially useful in Ole Automation, and particularly in DCOM. For instance, you can start wandering about on a network, looking for objects. If you find one, you can use RTTI to ask it questions about itself, and to query its capabilities!

### Using the RGB Function

In this section I take a very quick look at a second program that uses many of the same controls from the first program. This is just an example, but it is interesting in that it involves using at least one simple Windows API function, or rather, macro. It's important to understand that you can, of course, call the Windows API whenever you want.

Whenever a `TShape` component is painted, its interior and border are drawn in particular, predefined colors. By default, these colors are white and black, respectively. More specifically, the interior of the ellipse is filled with the color of the currently selected brush. You can change this color by making an assignment of the following type:

    Shape1->Brush->Color = MyNewColor;

The `RGBSHAPE` program on your disk shows how you can get very specific control over the colors of an object that you paint to the screen. The letters RGB stand for red, green, and blue; each of the these colors makes up one of the colors passed to the Windows API RGB macro itself:

    COLORREF RGB(

        BYTE  bRed,   // red component of color

        BYTE  bGreen, // green component of color

        BYTE  bBlue   // blue component of color

       );

The parameters passed to this function describe an intensity to be assigned to one of these three colors. These numbers always exist within a range between 0 and 255.

If you pass the RGB function the following parameters, it will return a long integer representing the color red:

    void __fastcall TForm1::Button1Click(TObject *Sender)

    {

      int Red;

      Red = RGB(255, 0, 0);

      Shape1->Brush->Color = TColor(Red);

    }

The `Color` property of a `TBrush` object is of type `TColor`, but `TColor` is nothing but an enumerated type ranging over all the possible values that can be returned by the RGB macro.

> NOTE: You can call the entire Windows API from inside BCB. However, most of the time your calls to the Windows API will be mapped through `WINDOWS.HPP`, which is a wrapper around the Pascal version of these calls. The Object Pascal team did not translate all the headers for the Windows API. As a result, when you call some of the more obscure or some of the most recent Windows API functions, you may have to explicitly include the header files for these calls. For instance, there is no Pascal translation of the headers for DirectX. As a result, you must include `DDRAW.H`, and so on in your project if you want to make calls to `DirectDraw` or other DirectX functions. The vast majority of Windows API calls are in `WINDOWS.HPP`, however, and that unit is included in all your projects automatically, so you don't have to `#include` anything in your projects. Needless to say, all Windows API calls are just mappings into a DLL, and it doesn't matter one wit whether you are mapped into the call through Pascal or C++. The compiler does the exact same thing in both cases, and there is no difference in performance, size, and so on.

Here's how you get the colors green and blue:

    Green = RGB(0, 255, 0);

    Blue = RGB(0, 0, 255);

If you combine these three colors in various ways, you can produce particular shades. For instance, if you drop a button into a form and respond to a click on the button with the following code, you draw a bright yellow ellipse on the screen:

    Shape1->Brush->Color = RGB(255, 255, 0);

    Shape1->Shape = stEllipse;

To achieve the color gray, pass in the following parameters:

    Gray = RGB(127, 127, 127);

To get a fleshlike color, enter

    Skin = RGB(255, 127, 127);

You see how it works. Remember that the first parameter controls the amount of red in the final color, the second the amount of green, and the third the amount of blue. RGB: red, green, blue!

The RGBSHAPE program has a `TShape` component, three labels, three scrollbars, and three edit controls.

The RGBSHAPE program has only one method:

    void __fastcall TForm1::ScrollBar1Change(TObject *Sender)

    {

      Shape1->Brush->Color = RGB(ScrollBar1->Position,

                                 ScrollBar2->Position,

                                 ScrollBar3->Position);

      Edit1->Text = IntToStr(ScrollBar1->Position);

      Edit2->Text = IntToStr(ScrollBar2->Position);

      Edit3->Text = IntToStr(ScrollBar3->Position);

    }

This method first uses the current positions of the scrollbars to assign a color the `TShape` objects brush. To make this work correctly, I set the `Max` property for each scrollbar to 255. When the color has been drawn on the screen, I show the actual numbers passed to the scrollbar in the edit components.

The point of the RGB program is to give you a graphical representation of the way the RGB function works. You might also find that this program helps you choose colors that you want to use in your own programs.

> NOTE: When working with the RGBSHAPE program, some users may find that Windows cannot create pure tones for some colors, but instead creates a kind of patchwork that approximates the shade described by the parameters passed to the RGB function. However, you can generally get pure tones if you set each of the parameters to 0, 128, or 255. Numbers halfway between 0 and 128 also usually produce pure tones. Of course, the actual results you see depend on whether you are using a 16-color card, 256-color card, or some video card that offers many thousands of colors. You also need to have the correct video drivers in place. For instance, you don't want to be using a powerful video card and get only 16 colors from it simply for want of the right driver! If you suspect your card is not performing correctly, get on the Web, visit the home page of the company that makes your video card or computer, and download the latest drivers. In Windows 95, you can usually simply unzip the drivers into a temporary directory, right click the desktop, and select Properties | Settings | Change Display Type. When Windows asks for your new drivers, simply point it at the directory where you unzipped the files and it will add them to the system automatically. Be sure to test your work before you restart Windows!

Listing 2.4. The code for the main unit in the RGBSHAPE program.

    #include <vcl.h>

    #pragma hdrstop

    #include "Main.h"

    #pragma resource "*.dfm"

    TForm1 *Form1;

    __fastcall TForm1::TForm1(TComponent* Owner)

      : TForm(Owner)

    {

    }

    void __fastcall TForm1::ScrollBar1Change(TObject *Sender)

    {

      Shape1->Brush->Color = RGB(ScrollBar1->Position,

                                 ScrollBar2->Position,

                                 ScrollBar3->Position);

      Edit1->Text = IntToStr(ScrollBar1->Position);

      Edit2->Text = IntToStr(ScrollBar2->Position);

      Edit3->Text = IntToStr(ScrollBar3->Position);

    }

### Summary

In this chapter you have been introduced to the basic facts about Borland C++Builder. In particular, you learned about the environment, manipulating components, and some of the basic tricks of RAD programming. You also had a brief introduction to some advanced topics such as RTTI.

By now the boards are clear to head into some more technical subject matter, such as the examination of extensions to the language featured in the next chapter. After that you will look at events, exceptions, graphics, and sharing code with Delphi. By the time you have finished all these sections, you will have a solid base from which you can launch an exploration of how to use BCB to create cutting-edge Windows applications.

There is so much information to give out in a book like this that I sometimes forget to mention how much I love this programming environment. All the information I am presenting here adds up to a tool that is more powerful, more flexible, and easier to use than any other C++ compiler on the market. Furthermore, this is just the 1.0 version of a product that should become the environment of choice for serious programmers during the next few years.

©Copyright, Macmillan Computer Publishing. All rights reserved.

| Use of this site is subject certain Terms & Conditions. Copyright (c) 1996-1999 EarthWeb, Inc.. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Please read our privacy policy for details.