Copyright: Copyright © 1999 Inprise Corporation.                      All rights reserved.                                                 This Help file was compiled on   Tuesday, January 19, 1999 12:22:59.


The C++Builder development environment

Topic groups

When you start C++Builder, you are immediately placed within the visual development environment, also called the IDE. This environment provides all the tools you need to design, develop, test, debug, and deploy applications.

C++Builder’s development environment includes a visual form designer, Object Inspector, Component palette, Project manager, source code editor, debugger, and installation tool. You can move freely from the visual representation of an object (in the form designer), to the Object Inspector to edit the initial runtime state of the object, to the source code editor to edit the execution logic of the object. Changing code-related properties in the Object Inspector, such as the name of an event handler, automatically changes the corresponding source code. In addition, changes to the source code, such as renaming an event handler method in a form class declaration, is immediately reflected in the Object Inspector.


Designing applications

Topic groups	See also

C++Builder includes all the tools necessary to start designing applications:

Blank window, known as a form, on which to design the UI for your application.

Extensive class library with many reusable objects.

Object Inspector for examining and changing object traits.

Code editor that provides direct access to the underlying program logic.

Project manager for managing the files that make up one or more projects.

Many other tools such as an image editor on the toolbar and an integrated debugger on menus to support application development in the IDE.

Command line tools including compilers, linkers, and other utilities.

You can use C++Builder to design any kind of 32-bit application—from general-purpose utilities to sophisticated data access programs or distributed applications. C++Builder’s database tools and data-aware components let you quickly develop powerful desktop database and client/server applications. Using C++Builder’s data-aware controls, you can view live data while you design your application and immediately see the results of database queries and changes to the application interface.

Creating applications introduces C++Builder’s support for different types of applications.


Using components

Topic groups	See also

Many visual components are provided in the development environment itself on the Component palette. You select components from the Component palette and drop them onto the form to design the application user interface. Once a visual component is on the form, you can adjust its position, size, and other design-time properties.

C++Builder components are grouped functionally on the different pages of the Component palette. For example, commonly used components such as those to create menus, edit boxes, or buttons are located on the Standard page of the Component palette. Handy controls such as a timer, paintbox, media player, and OLE container are on the System page.

At first glance, C++Builder’s components appear to be just like any other C++ class. But there are differences between components in C++Builder and the standard C++ class hierarchies that most C++ programmers work with. Some differences are

All C++Builder components are descended from TComponent.

Components are most often used as is and are manipulated through their properties, rather than serving as “base classes” to be subclassed to add or change functionality. When a component is inherited, it is usually to add specific code to existing event handling member functions.

VCL components can only be allocated on the heap, not on the stack (that is, they must be created with the new operator).

Properties of components intrinsically contain runtime type information.

Components can be added to the Component palette in the C++Builder user interface and manipulated on a form.

Components often achieve a better degree of encapsulation than is usually found in standard C++ classes. For example, consider the use of a dialog containing a push button. In a C++ Windows program, when a user clicks on the button, the system generates a WM_LBUTTONDOWN message. The program must catch this message (typically in a switch statement, a message map, or a response table) and dispatch it to a routine that will execute in response to the message.

In C++Builder, the push button component is pre-programmed to respond to a mouse click using its built-in OnClick event handler. Your program does not have to determine that a button has been clicked. You only provide the routine that is called when the button is clicked, and through the Object Inspector, assign that routine to the OnClick event handler of the button.

Similarly, most Windows messages are handled by C++Builder components. When you want to respond to a windows message, you need only provide an event handler.

To read these topics in sequence, press the >> button.


Creating applications

Topic groups	See also

The main use of C++Builder is designing, building, and compiling of Windows applications. There are three basic kinds of Windows applications:

Windows GUI applications

Console applications

Service applications

Windows GUI applications comprise the bulk of software available for the Windows platform. The User Interface (UI) consists of windows and dialog boxes which work together to perform a group of functions. Word processors, spreadsheets, and C++Builder are examples of GUI applications.

Console applications are 32-bit Windows applications that run without a GUI interface, usually in a console window. These applications typically don’t require much user input, and perform a limited set of functions. The included Grep utility is an example of a console application, as is the command-line compiler and linker included with C++Builder.

Service applications are applications that take requests from client applications, process those requests, and return information to the client applications. They typically run in the background, without much user input. A web, FTP, or e-mail server is an example of a service application.


Windows EXEs

Topic groups	See also

When you compile a project in C++Builder, an executable (.EXE) file is created that can then be run. The executable usually provides the basic functionality of your program, and simple programs often consist of only an EXE. You can extend the application by calling DLLs, packages, and other support files from the executable.

In designing a Windows EXE, there are two UI models for the implementation of the application:

Single document interface (SDI)

Multiple document interface (MDI)

In addition to the implementation model of your applications, the design-time behavior of your project and the runtime behavior of your application can be manipulated by setting project options in the IDE.


User interface models

Topic groups	See also

Any form you design can be implemented in your application as a multiple document interface (MDI) or single document interface (SDI) form. In an MDI application, more than one document or child window can be opened within a single parent window. This is common in applications such as spreadsheets or word processors. An SDI application, by contrast, normally contains a single document view. To make your form an SDI application, set the FormStyle property of your Form object to fsNormal.

For more information on developing the UI for an application, see Developing the application user interface.


SDI Applications

Topic groups	See also

To create a new SDI application,

1	Select File|New to bring up the New Items dialog.

2	Click on the Projects page and select SDI Application.

3	Click OK.

By default, the FormStyle property of your Form object is set to fsNormal, so C++Builder assumes that all new applications are SDI applications.


MDI applications

Topic groups	See also

To create a new MDI application,

1	Select File|New to bring up the New Items dialog.

2	Click on the Projects page and select MDI Application.

3	Click OK.

MDI applications require more planning and are somewhat more complex to design than SDI applications. However, the same principles used to create a well designed UI in an SDI application apply to MDI applications.

MDI applications spawn child windows that reside within the client window. In an MDI application, the application’s main form contains child forms. Set the FormStyle property of the TForm object to specify whether a form is a child (fsMDIForm) or main form (fsMDIChild). It is a good idea to define a base class for your child forms, and derive each individual child form from this base class, to avoid having to redefine the child form’s settings.


Setting IDE, project, and compilation options

Topic groups

Use Project|Project Options to specify the various options for your project. The tabbed pages in the Project Options dialog affect both the visible and the back-end behavior of your programs as well as the design-time behavior of your project.

Setting default project options

To change the default options that apply to all future projects, set the options in the Project Options dialog box and check the Default box at the bottom right of the window. All new projects will now have the current options selected by default.


Programming templates

Topic groups

Programming templates are part of the Code Insight features of C++Builder, and are common, general code structures that allow you to add code specific to your programming task without having to reenter the general code structure. For instance, if you want to insert a for loop into your project you could select one of the for loop code templates. The following code is inserted:

for (|; ;)

{

}

To insert a code template in the Code editor, press Ctrl-j and select the template you want to use. You can also add your own templates to this collection. To add a template:

1	Select Tools|Environment Options.

2	Click the Code Insight tab.

3	In the templates section click Add.

4	Choose a shortcut name and enter a brief description of the new template.

5	Add the template code to the Code text box.

6	Click OK.

Now your new template is available when pressing Ctrl-j.


Console applications

Topic groups	See also

To create a new console application, choose File|New and select Console Wizard from the New Items dialog box. Radiobox options allow you to choose the Window Type and Execution Type. A checkbox option allows you to include the Visual Component Library (VCL). Some of these combinations are mutually exclusive.

The EXE Execution Type lets you create either a Console Window type application, that can optionally use the VCL, or a non-VCL Windows (GUI) Window type application.

The DLL Execution Type lets you create a non-VCL DLL.

Using the VCL in console applications

Console applications are programs written without a Graphical User Interface, or GUI. When a console application is run, it runs in a Windows console window. The visual controls of the VCL normally used in Windows programming are not used in console applications.

When you create a new console application, the IDE does not create a new form. Only the code editor is displayed. You can, however, use the VCL in console applications. To do this, you must indicate in the Console Wizard that you will be using the VCL. If you do not indicate in the Wizard that you want to use the VCL, you can’t use any of the VCL classes later. Trying to do so will cause linker errors.

Creating C console applications

If you want your project compiled for “C”, not C++, you will need to make some modifications to your code. CBuilder projects are managed using two text files; a .BPR ( a makefile ) and a .CPP, to hold settings, flags, and files that you add to your project. The IDE is constantly reading and writing these two project text files ( this is part of the means of implementing RAD ). One of the things the IDE expects to find in the .CPP portion of the project is the word "main" and it also expects/needs to find it in a file with a .CPP extension. So, for you, to get a real "C" compile of your program that contains main, just create a new console app ( no VCL ) and edit the .CPP to look like the following:

#include

#define main

You want to define main before removing the function main() because, again, the IDE is reading this file constantly. Then choose Project|Add to Project and select your .C file that has main. Now the BCB project source looks like the following and you can edit your C code, compile, run and debug in the IDE.

#include

USEUNIT("mymain.c");

#define main


Service applications

Topic groups	See also

To create an application that implements a Win32 service, Choose File|New, and select Service Application from the New Items page. This adds a global variable named Application to your project, which is of type TServiceApplication.

Once you have created a service application, you will see a window in the designer that corresponds to a service (TService). Implement the service by setting its properties and event handlers in the Object Inspector. You can add additional services to your service application by choosing Service from the new items dialog. Do not add services to an application that is not a service application. While a TService object can be added, the application will not generate the requisite events or make the appropriate Windows calls on behalf of the service.

Example:	This service has a TServerSocket whose port is set to 80. This is the default port for Web Browsers to make requests to Web Servers and for Web Servers to make responses to Web Browsers. This particular example produces a text document in the C:\Temp directory called WebLogxxx.log (where xxx is the ThreadID). There should be only one Server listening on any given port, so if you have a web server, you should make sure that it is not listening (the service is stopped).

To see the results: open up a web browser on the local machine and for the address, type 'localhost' (with no quotes). The Browser will time out eventually, but you should now have a file called weblogxxx.log in the C:\temp directory.

1	To create the example, choose File|New and select Service Application from the New Items dialog. You will see a window appear named Service1. From the Internet page of the component palette, add a ServerSocket component to the service window (Service1).

2	Next, add a private data member of type TMemoryStream to the TService1 class. The header for your unit should now look like this:

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

#ifndef Unit1H

#define Unit1H

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

#include <SysUtils.hpp>

#include <Classes.hpp>

#include <SvcMgr.hpp>

#include <ScktComp.hpp>

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

class TService1 : public TService

{

__published:	// IDE-managed Components

        TServerSocket *ServerSocket1;

private:	// User declarations

        TMemoryStream *Stream; // add this line here

public:	// User declarations

__fastcall TService1(TComponent* Owner);

 	PServiceController __fastcall GetServiceController(void);

friend void __stdcall ServiceController(unsigned CtrlCode);

};

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

extern PACKAGE TService1 *Service1;

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

#endif

3	Next, select ServerSocket 1, the component you added in step 1. In the Object Inspector, double click the OnClientRead event and add the following event handler:

void __fastcallTService1::ServerSocket1ClientRead(TObject *Sender,

      TCustomWinSocket *Socket)

{

  char *Buffer = NULL;

  int len = Socket->ReceiveLength();

  while (len > 0)

  {

    try

    {

      Buffer = (char *)malloc(len);

      Socket->ReceiveBuf((void *)Buffer, len);

      Stream->Write(Buffer, strlen(Buffer));

    }

    __finally

    {

      free(Buffer);

    }

    Stream->Seek(0, soFromBeginning);

    AnsiString LogFile = "C:\\Temp\\WebLog";

    LogFile = LogFile + IntToStr(ServiceThread->ThreadID) + ".log";

    Stream->SaveToFile(LogFile);

  }

}

4	Finally, select Service1 by clicking in the window’s client area (but not on the ServiceSocket). In the Object Inspector, double click the OnExecute event and add the following event handler:

void __fastcall TService1::Service1Execute(TService *Sender)

{

  Stream = new TMemoryStream();

  try

  {

    ServerSocket1->Port = 80; // WWW port

    ServerSocket1->Active = true;

    while (!Terminated)

       ServiceThread->ProcessRequests(false);

    ServerSocket1->Active = false;

   }

   __finally

   {

     delete Stream;

   }

  }

When working with services you should be aware of:

Service threads

Service name properties


Service threads

Topic groups	See also

Each service has its own thread (TServiceThread), so if your service application implements more than one service you must ensure that the implementation of your services is thread-safe. TServiceThread is designed so that you can implement the service in the TService OnExecute event handler. The service thread has its own Execute method which contains a loop that calls the service’s OnStart and OnExecute handlers before processing new requests. Because service requests can take a long time to process and the service application can receive simultaneous requests from more than one client, it is more efficient to spawn a new thread (derived from TThread, not TServiceThread) for each request and move the implementation of that service to the new thread’s Execute method. This allows the service thread’s Execute loop to process new requests continuallly without having to wait for the service’s OnExecute handler to finish. The following example demonstrates.

Example:	This service beeps every 500 milliseconds from within the standard thread. It handles pausing, continuing, and stopping of the thread when the service is told to pause, continue, or stop.

1	Choose File|New and select Service Application from the New Items dialog. You will see a window appear named Service1.

2	In you unit’s header file, declare a new descendant of TThread named TSparkyThread. This is the thread that does the work for your service. The declaration should appear as follows:

class TSparkyThread : public TThread

{

private:

protected:

      void __fastcall Execute();

public:

        __fastcall TSparkyThread(bool CreateSuspended);

};

3	Next, in the .cpp file for your unit, create a global variable for a TSparkyThread instance:

TSparkyThread *SparkyThread;

4	Add the following code to the .cpp file for the TSparkyThread constructor:

__fastcall TSparkyThread::TSparkyThread(bool CreateSuspended)

        : TThread(CreateSuspended)

{

}

5	Add the following code to the .cpp file for the TSparkyThread Execute method (the thread function):

void __fastcall TSparkyThread::Execute()

{

  while (!Terminated)

  {

    Beep();

    Sleep(500);

  }

}

6	Select the Service window (Service1), and double-click the OnStart event in the Object Inspector. Add the following OnStart event handler:

void __fastcall TService1::Service1Start(TService *Sender, bool &Started)

{

  SparkyThread = new TSparkyThread(false);

  Started = true;

}

7	Double-click the OnContinue event in the Object Inspector. Add the following OnContinue event handler:

void __fastcall TService1::Service1Continue(TService *Sender, bool &Continued)

{

  SparkyThread->Resume();

  Continued = true;

}

8	Double-click the OnPause event in the Object Inspector. Add the following OnPause event handler:

void __fastcall TService1::Service1Pause(TService *Sender, bool &Paused)

{

  SparkyThread->Suspend();

  Paused = true;

}

9	Finally, double-click the OnStop event in the Object Inspector and add the following OnStop event handler:

void __fastcall TService1::Service1Continue(TService *Sender, bool &Stopped)

{

  SparkyThread->Terminate();

  Stopped = true;

}

When developing server applications, choosing to spawn a new thread depends on the nature of the service being provided, the anticipated number of connections, and the expected number of processors on the computer running the service.


Service name properties

Topic groups	See also

The VCL provides classes for creating service applications. These include TService and TDependency. When using these classes, the various name properties can be confusing. This section describes the differences.

Services have user names (called Service start names) that are associated with passwords, display names for display in manager and editor windows, and actual names (the name of the service). Dependencies can be services or they can be load ordering groups. They also have names and display names. And because service objects are derived from TComponent, they inherit the Name property. The following sections summarize the name properties:

TDependency properties

The TDependency DisplayName is both a display name and the actual name of the service. It is nearly always the same as the TDependency Name property.

TService name properties

The TService Name property is inherited from TComponent. It is the name of the component, and is also the name of the service. For dependencies that are services, this property is the same as the TDependency Name and DisplayName properties.

TService’s DisplayName is the name displayed in the Service Manager window. This often differs from the actual service name (TService::Name, TDependency::DisplayName, TDependency::Name). Note that the DisplayName for the Dependency and the DisplayName for the Service usually differ.

Service start names are distinct from both the service display names and the actual service names. A ServiceStartName is the user name input on the Start dialog selected from the Service Control Manager.


Creating packages and DLLs

Topic groups	See also

Dynamic link libraries (DLLs) are modules of compiled code that work in conjunction with an executable to provide functionality to an application.

Packages are special DLLs used by C++Builder applications, the IDE, or both. There are two kinds of packages: runtime packages and design-time packages. Runtime packages provide functionality to a program while that program is running. Design-time packages extend the functionality of the IDE.

For more information on packages, see Working with packages and components.


When to use packages and DLLs

Topic groups

For most applications written in C++Builder, packages provide greater flexibility and are easier to create than DLLs. However, there are several situations where DLLs would be better suited to your projects than packages:

Your code module will be called from non-C++Builder applications.

You are extending the functionality of a web server.

You are creating a code module to be used by third-party developers.

Your project is an OLE container.


Using DLLs in C++Builder

Topic groups

A Windows DLL can be used in a C++Builder application just as it would be in any C++ application.

To statically load a DLL when your C++Builder application is loaded, link the import library file for that DLL into your C++Builder application at link time. To add an import library to a C++Builder application, open the make file (.BPR) for the application and add the import library name to the library file list assigned to the ALLLIB variable. If necessary, add the path of the import library to the path(s) listed for the -L option of LFLAGS (linker options) variable.

The exported functions of that DLL then become available for use by your application. Prototype the DLL functions your application uses with the __declspec (dllimport) modifier:

__declspec(dllimport) return_type imported_function_name(parameters);

To dynamically load a DLL during the run of a C++Builder application, use the Windows API function LoadLibrary() to load the DLL, then use the API function GetProcAddress() to obtain pointers to the individual functions you want to use.

Additional information on using DLLs can be found in the Microsoft¨ Win32 SDK Reference.


Creating DLLs in C++Builder

Topic groups

Creating DLLs in C++Builder is the same as in standard C++:

1	Choose File|New to display the New Items dialog box.

2	Click DLL to create a DLL containing VCL components.

See Creating DLLs containing VCL components.

To create a non-VCL DLL:

1	Choose File|New to display the New Items dialog box.

2	Click Console Wizard.

From here, you can create a non-VCL DLL. See Console Applications.

Exported functions in the code should be identified with the __declspec (dllexport) modifier as they must be in Borland C++ or Microsoft Visual C++. For example, the following code is legal in C++Builder and other Windows C++ compilers:

// MyDLL.cpp

double dblValue(double);

double halfValue(double);

extern "C" __declspec(dllexport) double changeValue(double, bool);

double dblValue(double value)

{

return value * value;

};

double halfValue(double value)

{

return value / 2.0;

}

double changeValue(double value, bool whichOp)

{

return whichOp ? dblValue(value) : halfValue(value);

}

In the code above, the function changeValue is exported, and therefore made available to calling applications. The functions dblValue and halfValue are internal, and cannot be called from outside of the DLL.

In the C++Builder IDE, you can create a new DLL project by selecting File|New and selecting the DLL icon from the New tab. A new edit window opens and the project options are set to build a DLL rather than an EXE. Notice that by default VCL.H is included in the new DLL source. If your DLL does not use any VCL components, use the console wizard.

Additional information on creating DLLs can be found in the Microsoft¨ Win32 SDK Reference.


Creating DLLs containing VCL components

Topic groups

One of the strengths of DLLs is that a DLL created with one development tool can often be used by application written using a different development tool. When your DLL contains VCL components (such as forms) that are to be utilized by the calling application, you need to provide exported interface routines that use standard calling conventions, avoid C++ name mangling, and do not require the calling application to support the VCL library in order to work. To create VCL components that can be exported, use runtime packages. For more information, see Working with packages and components.

For example, suppose you want to create a DLL to display the following simple dialog box:

The code for the dialog box DLL is as follows:

// DLLMAIN.H

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

#ifndef dllMainH

#define dllMainH

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

#include <vcl\Classes.hpp>

#include <vcl\Controls.hpp>

#include <vcl\StdCtrls.hpp>

#include <vcl\Forms.hpp>

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

class TYesNoDialog : public TForm

{

__published:    // IDE-managed Components

   TLabel *LabelText;

   TButton *YesButton;

   TButton *NoButton;

   void __fastcall YesButtonClick(TObject *Sender);

   void __fastcall NoButtonClick(TObject *Sender);

private:        // User declarations

   bool returnValue;

public:         // User declarations

   virtual __fastcall TYesNoDialog(TComponent *Owner);

   bool __fastcall GetReturnValue();

};

// exported interface function

extern "C" __declspec(dllexport) bool InvokeYesNoDialog();

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

 extern TYesNoDialog *YesNoDialog;

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

#endif

// DLLMAIN.CPP

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

#include <vcl\vcl.h>

#pragma hdrstop

#include "dllMain.h"

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

#pragma resource "*.dfm"

TYesNoDialog *YesNoDialog;

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

__fastcall TYesNoDialog::TYesNoDialog(TComponent *Owner)

 : TForm(Owner)

{

  returnValue = false;

}

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

void __fastcall TYesNoDialog::YesButtonClick(TObject *Sender)

{

   returnValue = true;

   Close();

}

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

void __fastcall TYesNoDialog::NoButtonClick(TObject *Sender)

{

   returnValue = false;

   Close();

}

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

bool __fastcall TYesNoDialog::GetReturnValue()

{

   return returnValue;

}

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

// exported standard C++ interface function that calls into VCL

bool InvokeYesNoDialog()

{

   bool returnValue;

TYesNoDialog *YesNoDialog = new TYesNoDialog(NULL);

   YesNoDialog->ShowModal();

returnValue = YesNoDialog->GetReturnValue();

delete YesNoDialog;

   return returnValue;

}

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

The code in this example displays the dialog and stores the value true in the private data member returnValue if the “Yes” button is pressed. Otherwise, returnValue is false. The public GetReturnValue() function retrieves the current value of returnValue.

To invoke the dialog and determine which button was pressed, the calling application calls the exported function InvokeYesNoDialog(). This function is declared in DLLMAIN.H as an exported function using C linkage (to avoid C++ name mangling) and the standard C calling convention. The function is defined in DLLMAIN.CPP.

By using a standard C function as the interface into the DLL, any calling application, whether or not it was created with C++Builder, can use the DLL. The VCL functionality required to support the dialog is linked into the DLL itself, and the calling application does not need to know anything about it.

Note that when creating a DLL that uses the VCL, the required VCL components are linked into the DLL resulting in a certain amount of overhead. The impact of this overhead on the overall size of the application can be minimized by combining several components into one DLL which only needs one copy of the VCL support components.


Linking DLLs

Topic groups

You can set the linker options for your DLL on the Linker page of the Project Options dialog. The default checkbox on this page also creates an import library for your DLL. If compiling from the command line, invoke the linker, ILINK32.EXE, with the -Tpd switch. For example,

ilink32 /c /aa /Tpd c0d32.obj mydll.obj, mydll.dll, mdll.map, import32.lib cw32mt.lib

If you need an import library, use the -Gi switch also, to generate an import library.

You can optionally create an import library with the command line utility IMPLIB.EXE. For example,

implib mydll.lib mydll.dll

For more information about the different options for linking DLLs and using them with other modules that are statically or dynamically linked to the runtime library, see the online Help.


Writing database applications

Topic groups

One of C++Builder’s strengths is its support for creating advanced database applications. C++Builder includes built-in tools that allow you to connect to Oracle, Sybase, Informix, dBASE, Paradox, or other servers while providing transparent data sharing between applications. The Borland Database Engine (BDE) supports scaling from desktop to client/server applications.

Tools, such as the Database Explorer, simplify the task of writing database applications. The Database Explorer is a hierarchical browser for inspecting and modifying database server-specific schema objects including tables, fields, stored procedure definitions, triggers, references, and index descriptions.

Through a persistent connection to a database, Database Explorer lets you

Create and maintain database aliases

View schema data in a database, such as tables, stored procedures, and triggers

View table objects, such as fields and indexes

Create, view, and modify data in tables

Enter SQL statements to directly query any database

Create and maintain data dictionaries to store attribute sets


Building distributed applications

Topic groups

Distributed applications are applications that are deployed to various machines and platforms and work together, typically over a network, to perform a set of related functions. For instance, an application for purchasing items and tracking those purchases for a nationwide company would require individual client applications for all the outlets, a main server that would process the requests of those clients, and an interface to a database that stores all the information regarding those transactions. By building a distributed client application (for instance, a web-based application), maintaining and updating the individual clients is vastly simplified.

C++Builder provides several options for the implementation model of distributed applications:

TCP/IP applications

COM and DCOM applications

CORBA applications

Database applications


Distributing applications using TCP/IP

Topic groups	See also

TCP/IP is a communication protocol that allows you to write applications that communicate over networks. You can implement virtually any design in your applications. TCP/IP provides a transport layer, but does not impose any particular architecture for creating your distributed application.

The growth of the Internet has created an environment where most computers already have some form of TCP/IP access, which simplifies distributing and setting up the application.

Applications that use TCP/IP can be message-based distributed applications (such as Web server applications that service HTTP request messages) or distributed object applications (such as distributed database applications that communicate using Windows sockets).

The most basic method of adding TCP/IP functionality to your applications is to use client or server sockets. C++Builder also provides support for applications that extend Web servers by creating CGI scripts or DLLs. In addition, C++Builder provides support for TCP/IP-based database applications.


Using sockets in applications

Topic groups	See also

Two VCL classes, TClientSocket and TServerSocket, allow you to create TCP/IP socket connections to communicate with other remote applications. For more information on sockets, see Working with sockets.


Creating Web server applications

Topic groups	See also

To create a new Web server application, select File|New and select Web Server Application in the New Items dialog box. Then select the Web server application type:

ISAPI and NSAPI

CGI stand-alone

Win-CGI stand-alone

CGI and Win-CGI applications use more system resources on the server, so complex applications are better created as ISAPI or NSAPI applications.

For more information on building Web server applications, see Creating Internet server applications.

ISAPI and NSAPI Web server applications

Selecting this type of application sets up your project as a DLL. ISAPI or NSAPI Web server applications are DLLs loaded by the Web server. Information is passed to the DLL, processed, and returned to the client by the Web server.

CGI stand-alone Web server applications

CGI Web server applications are console applications that receive requests from clients on standard input, processes those requests, and sends back the results to the server on standard output to be sent to the client.

Win-CGI stand-alone Web server applications

Win-CGI Web server applications are Windows applications that receive requests from clients from an INI file written by the server and writes the results to a file that the server sends to the client.


Distributing applications using COM and DCOM

Topic groups	See also

COM is the Component Object Model, a Windows-based distributed object architecture designed to provide object interoperability using predefined routines called interfaces. .COM applications use objects that are implemented by a different process or, if you use DCOM, on a separate machine.

COM and DCOM

C++Builder has classes and wizards that make it easy to create the essential elements of a COM, OLE, or ActiveX application. Using C++Builder to create COM-based applications offers a wide range of possibilities, from improving software design by using interfaces internally in an application, to creating objects that can interact with other COM-based API objects on the system, such as the Win95 Shell extensions and DirectX multimedia support.

For more information on COM and Active X controls, see Overview of COM Technologies,  Creating an ActiveX control and Distributing a client application as an ActiveX control.

For more information on DCOM, see Using DCOM connections.

MTS

The Microsoft Transaction Server (MTS) is a an extension to DCOM that provides transaction services, security, and resource pooling for distributed COM applications.

For more information on MTS, see Creating MTS objects and Using MTS.


Distributing applications using CORBA

Topic groups

Common Object Request Broker Architecture (CORBA) is a method of using distributed objects in applications. The CORBA standard is used on many platforms, so writing CORBA applications allows you to make use of programs that are not running on a Windows machine.

Like COM, CORBA is a distributed object architecture, meaning that client applications can make use of objects that are implemented on a remote server.

For more information on CORBA, see Writing CORBA applications.


Distributing database applications

Topic groups	See also

C++Builder provides support for creating distributed database applications using the MIDAS technology. This powerful technology includes a coordinated set of components that allow you to build a wide variety of multi-tiered database applications. Distributed database applications can be built on a variety of communications protocols, including DCOM, TCP/IP, and OLEnterprise.

For more information about building distributed database applications, see Creating multi-tiered applications..

Distributing database applications often requires you to distribute the Borland Database Engine (BDE) in addition to the application files. For information on deploying the BDE, see Deploying database applications.


Developing the application user interface: Overview

Topic groups

One of C++Builder’s most powerful features is how easy it is to create the user interface (UI) using the VCL. By clicking and dropping components from the Component palette onto forms, the interface of your application can be quickly designed.


Understanding TApplication, TScreen, and TForm

Topic groups	See also

TApplication, TScreen, and TForm are VCL classes that form the backbone of all C++Builder applications by controlling the behavior of your project. The TApplication class forms the foundation of a Windows application by providing properties and methods that encapsulate the behavior of a standard Windows program. TScreen is used at runtime to keep track of forms and data modules that have been loaded as well as system specific information such as screen resolution and what fonts are available for display. Instances of the TForm class are the building blocks of your application’s user interface. The windows and dialog boxes of your application are based on TForm.


Using the main form

Topic groups	See also

TForm is the key class for creating Windows GUI applications.

The first form you create and save in a project becomes, by default, the project’s main form, which is the first form created at runtime. As you add forms to your projects, you might decide to designate a different form as your application’s main form. Also, specifying a form as the main form is an easy way to test it at runtime, because unless you change the form creation order, the main form is the first form displayed in the running application.

To change the project main form,

1	Choose Project|Options and select the Forms page.

2	In the Main Form combo box, select the form you want as the project main form and choose OK.

Now if you run the application, your new main form choice is displayed.


Adding additional forms

Topic groups	See also

To add an additional form to your project, select File|New Form. You can see all your project’s forms and their associated units listed in the Project Manager (View|Project Manager).


Linking forms

Topic groups	See also

Adding a form to a project adds a reference to it in the project file, but not to any other units in the project. Before you can write code that references the new form, you need to add a reference to it in the referencing forms’ unit files. This is called form linking.

A common reason to link forms is to provide access to the components in that form. For example, you’ll often use form linking to enable a form that contains data-aware components to connect to the data-access components in a data module.

To link a form to another form,

1	Select the form that needs to refer to another.

2	Choose File|Use Unit.

3	Select the name of the form unit for the form to be referenced.

4	Choose OK.

Linking a form to another just means that one form unit contains the header for the other’s form unit, meaning that the linked form and its components are now in scope for the linking form.


Working at the application level

Topic groups	See also

The global variable Application, of type TApplication, is in every VCL-based Windows application. Application encapsulates your application as well as providing many functions that occur in the background of the program. For instance, Application would handle how you would call a help file from the menu of your program. Understanding how TApplication works is more important to a component writer than to developers of stand-alone applications, but you should set the options that Application handles in the Project|Options Application page when you create a project.


Handling the screen

Topic groups	See also

An global variable of type TScreen called Screen is created when you create a project. Screen encapsulates the state of the screen on which your application is running. Common tasks performed by Screen include specifying the look of the cursor, the size of the window in which your application is running, the list of fonts available to the screen device, and multiple screen behavior. If your application runs on multiple monitors, Screen maintains a list of monitors and their dimensions so that you can effectively manage the layout of your user interface.


Managing layout

Topic groups	See also

At its simplest, you control the layout of your user interface by how you place controls in your forms. The placement choices you make are reflected in the control’s Top, Left, Width, and Height properties. You can change these values at runtime to change the position and size of the controls in your forms.

Controls have a number of other properties, however, that allow them to automatically adjust to their contents or containers. This allows you to lay out your forms so that the pieces fit together into a unified whole.

Two properties affect how a control is positioned and sized in relation to its parent. The Align property lets you force a control to fit perfectly within its parent along a specific edge or filling up the entire client area after any other controls have been aligned. When the parent is resized, the controls aligned to it are automatically resized and remain positioned so that they fit against a particular edge.

If you want to keep a control positioned relative to a particular edge of its parent, but don’t want it to necessarily touch that edge or be resized so that it always runs along the entire edge, you can use the Anchors property.

If you want to ensure that a control does not grow too big or too small, you can use the Constraints property. Constraints lets you specify the control’s maximum height, minimum height, maximum width, and minimum width. Set these to limit the size (in pixels) of the control’s height and width. For example, by setting the MinWidth and MinHeight of the constraints on a container object, you can ensure that child objects are always visible.

The value of Constraints propagates through the parent/child hierarchy so that an object’s size can be constrained because it contains aligned children that have size constraints. Constraints can also prevent a control from being scaled in a particular dimension when its ChangeScale method is called.

TControl introduces a protected event, OnConstrainedResize, of type TConstrainedResizeEvent:

void __fastcall (__closure *TConstrainedResizeEvent)(System::TObject* Sender, int &MinWidth, int &MinHeight, int &MaxWidth, int &MaxHeight);

This event allows you to override the size constraints when an attempt is made to resize the control. The values of the constraints are passed as var parameters which can be changed inside the event handler. OnConstrainedResize is published for container objects (TForm, TScrollBox, TControlBar, and TPanel). In addition, component writers can use or publish this event for any descendant of TControl.

Controls that have contents that can change in size have an AutoSize property that causes the control to adjust its size to its font or contained objects.


Working with messages

Topic groups	See also

A message is a notification that some event has occurred that is sent by Windows to an application. The message itself is a record passed to a control by Windows. For instance, when you click a mouse button on a dialog box, Windows sends a message to the active control and the application containing that control reacts to this new event. If the click occurs over a button, the OnClick event could be activated upon receipt of the message. If the click occurs just in the form, the application can ignore the message.

The record type passed to the application by Windows is called a TMsg. Windows predefines a constant for each message, and these values are stored in the message field of the TMsg record. Each of these constants begin with the letters wm.

The VCL automatically handles messages unless you override the message handling system and create your own message handlers. For more information on messages and message handling, see Understanding the message-handling system, Changing message handling, and Creating new message handlers.


More details on forms

Topic groups	See also

When you create a form in C++Builder from the IDE, C++Builder automatically creates the form in memory by including code in the WinMain() function. Usually, this is the desired behavior and you don’t have to do anything to change it. That is, the main window persists through the duration of your program, so you would likely not change the default C++Builder behavior when creating the form for your main window.

However, you may not want all your application’s forms in memory for the duration of the program execution. That is, if you do not want all your application’s dialogs in memory at once, you can create the dialogs dynamically when you want them to appear.

Forms can be modal or modeless. Modal forms are forms with which the user must interact before switching to another form (for example, a dialog box requiring user input). Modeless forms, though, are windows that are displayed until they are either obscured by another window or until they are closed or minimized by the user.


Controlling when forms reside in memory

Topic groups	See also

By default, C++Builder automatically creates the application’s main form in memory by including the following code in the application’s WinMain() function:

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

This function creates a global variable with the same name as the form. So, every form in an application has an associated global variable. This variable is a pointer to an instance of the form’s class and is used to reference the form while the application is running. Any source code (.cpp) file that includes the form’s header (.h) file can access the form via this variable.

Because the form is added to the WinMain(), the form appears when the program is invoked and it exists in memory for the duration of the application.


Displaying an auto-created form

Topic groups	See also

If you choose to create a form at startup, and do not want it displayed until sometime later during program execution, the form’s event handler uses the ShowModal method to display the form that is already loaded in memory:

void __fastcall TMainMForm::FirstButtonClick(TObject *Sender)

{

ResultsForm->ShowModal();

}

In this case, since the form is already in memory, there is no need to create another instance or destroy that instance.


Creating forms dynamically

Topic groups	See also

You may not always want all your application’s forms in memory at once. To reduce the amount of memory required at load time, you may want to create some forms only when you need to use them. For example, a dialog box needs to be in memory only during the time a user interacts with it.

To create a form at a different stage during execution using the IDE, you:

1	Select the File|New Form from the Component bar to display the new form.

2	Remove the form from the Auto-create forms list of the Project Options|Forms page.

This removes the form’s invocation in WinMain(). As an alternative, you can manually remove the following line from WinMain():

Application->CreateForm(__classid(TResultsForm), &ResultsForm);

3	Invoke the form when desired by using the form’s Show method, if the form is modeless, or ShowModal method, if the form is modal.

An event handler for the main form must create an instance of the result form and destroy it. One way to invoke the result form is to use the global variable as follows. Note that ResultsForm is a modal form so the handler uses the ShowModal method.

void __fastcall TMainMForm::FirstButtonClick(TObject *Sender)

{

ResultsForm = new TResultsForm(this);

 ResultsForm->ShowModal();

 deleteResultsForm;

}

The event handler in the example deletes the form after it is closed, so the form would need to be recreatedusing new if you needed to use ResultsForm elsewhere in the application. If the form were displayed using Show you could not delete the form within the event handler because Show returns while the form is still open.

Note:	If you create a form using the new operator, be sure to check that the form is not in the Auto-create forms list on the Project Options|Forms page. Specifically, if you create the new form without deleting the form of the same name from the list, C++Builder creates the form at startup and this event-handler creates a new instance of the form, overwriting the reference to the auto-created instance. The auto-created instance still exists, but the application can no longer access it. After the event-handler terminates, the global variableno longer points to a valid form. Any attempt to dereference the global variablewill likely crash the application.


Creating modeless forms such as windows

Topic groups	See also

You must guarantee that reference variables for modeless forms exist for as long as the form is in use. This means that these variables should have global scope. In most cases, you use the global reference variable that was created when you made the form (the variable name that matches the name property of the form). If your application requires additional instances of the form, declare separate global variables (of type pointer to the form class) for each instance.


Using a local variable to create a form instance

Topic groups	See also

A safer way to create a unique instance of a modal form is to use a local variable in the event handler as a reference to a new instance. If a local variable is used, it does not matter whether ResultsForm is auto-created or not. The code in the event handler makes no reference to the global form variable. For example:

void __fastcall TMainMForm::FirstButtonClick(TObject *Sender)

{

TResultsForm *rf = new TResultsForm(this);	// rf is local form instance

 rf->ShowModal();

 delete rf;	// form safely destroyed

}

Notice how the global instance of the form is never used in this version of the event handler.

Typically, applications use the global instances of forms. However, if you need a new instance of a modal form, and you use that form in a limited, discrete section of the application, such as a single function, a local instance is usually the safest and most efficient way of working with the form.

Of course, you cannot use local variables in event handlers for modeless forms because they must have global scope to ensure that the forms exist for as long as the form is in use. Show returns as soon as the form opens, so if you used a local variable, the local variable would go out of scope immediately.


Passing additional arguments to forms

Topic groups	See also

Typically, you create forms for your application from within the IDE. When created this way, the forms have a constructor that takes one argument, Owner, which is a pointer to the owner of the form being created. (The owner is the calling application object or form object.) Owner can be NULL.

To pass additional arguments to a form, create a separate constructor and instantiate the form using the new operator. The example form class below shows an additional constructor, with the extra argument whichButton. This new constructor is added to the form class manually.

class TResultsForm : public TForm

{

__published:    // IDE-managed Components

   TLabel *ResultsLabel;

   TButton *OKButton;

   void __fastcall OKButtonClick(TObject *Sender);

private:        // User declarations

public:         // User declarations

   virtual __fastcall TResultsForm(TComponent* Owner);

virtual __fastcall TResultsForm(int whichButton, TComponent* Owner);

};

Here’s the manually coded constructor that passes the additional argument, whichButton. This constructor uses the whichButton parameter to set the Caption property of a Label control on the form.

void__fastcall TResultsForm::TResultsForm(int whichButton, TComponent* Owner)

 : TForm(Owner)

{

switch (whichButton) {

case 1:

ResultsLabel->Caption = "You picked the first button!";

break;

case 2:

ResultsLabel->Caption = "You picked the second button!";

break;

case 3:

ResultsLabel->Caption = "You picked the third button!";

}

}

When creating an instance of a form with multiple constructors, you can select the constructor that best suits your purpose. For example, the following OnClick handler for a button on a form calls creates an instance of TResultsForm that uses the extra parameter:

void __fastcall TMainMForm::SecondButtonClick(TObject *Sender)

{

TResultsForm *rf = new TResultsForm(2, this);

rf->ShowModal();

delete rf;

}


Retrieving data from forms

Topic groups	See also

Most real-world applications consist of several forms. Often, information needs to be passed between these forms. Information can be passed to a form by means of parameters to the receiving form’s constructor, or by assigning values to the form’s properties. The way you get information from a form depends on whether the form is modal or modeless.


Retrieving data from modeless forms

Topic groups	See also

You can easily extract information from modeless forms by calling public member functions of the form or by querying properties of the form. For example, assume an application contains a modeless form called ColorForm that contains a listbox called ColorListBox with a list of colors (“Red”, “Green”, “Blue”, and so on). The selected color name string in ColorListBox is automatically stored in a property called CurrentColor each time a user selects a new color. The class declaration for the form is as follows:

class TColorForm : public TForm

{

__published:    // IDE-managed Components

TListBox *ColorListBox;

void __fastcallColorListBoxClick(TObject *Sender);

private:        // User declarations

String getColor();

void   setColor(String);

String curColor;

public:         // User declarations

virtual __fastcall TColorForm(TComponent* Owner);

__property String CurrentColor = {read=getColor, write=setColor};

};

The OnClick event handler for the listbox, ColorListBoxClick, sets the value of the CurrentColor property each time a new item in the listbox is selected. The event handler gets the string from the listbox containing the color name and assigns it to CurrentColor. The CurrentColor property uses the setter function, setColor, to store the actual value for the property in the private data member curColor:

void __fastcall TColorForm::ColorListBoxClick(TObject *Sender)

{

int index = ColorListBox->ItemIndex;

if (index >= 0) {	// make sure a color is selected

CurrentColor = ColorListBox->Items->Strings[index];

}

else	// no color selected

CurrentColor = "";

}

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

void TColorForm::setColor(String s)

{

curColor = s;

}

Now suppose that another form within the application, called ResultsForm, needs to find out which color is currently selected on ColorForm whenever a button (called UpdateButton) on ResultsForm is clicked. The OnClick event handler for UpdateButton might look like this:

void __fastcall TResultsForm::UpdateButtonClick(TObject *Sender)

{

if (ColorForm) {	// verify ColorForm exists

String s = ColorForm->CurrentColor;

// do something with the color name string

}

}

The event handler first verifies that ColorForm exists by checking whether the point is NULL. It then gets the value of ColorForm’s CurrentColor property. The query of CurrentColor calls its getter function getColor which is shown here:

String TColorForm::getColor()

{

return curColor;

}

Alternatively, if ColorForm’s getColor function were public, another form could get the current color without using the CurrentColor property (for example, String s = ColorForm->getColor();). In fact, there’s nothing to prevent another form from getting the ColorForm’s currently selected color by checking the listbox selection directly:

String s = ColorListBox->Items->Strings[ColorListBox->ItemIndex];

However, using a property makes the interface to ColorForm very straightforward and simple. All a form needs to know about ColorForm is to check the value of CurrentColor.


Retrieving data from modal forms

Topic groups	See also

Just like modeless forms, modal forms often contain information needed by other forms. The most common example is form A launches modal form B. When form B is closed, form A needs to know what the user did with form B to decide how to proceed with the processing of form A. If form B is still in memory, it can be queried through properties or member functions just as in the modeless forms example above. But how do you handle situations where form B is deleted from memory upon closing? Since a form does not have an explicit return value, you must preserve important information from the form before it is destroyed.

To illustrate, consider a modified version of the ColorForm form that is designed to be a modal form. The class declaration is as follows:

class TColorForm : public TForm

{

__published:    // IDE-managed Components

TListBox *ColorListBox;

TButton *SelectButton;

TButton *CancelButton;

void __fastcall CancelButtonClick(TObject *Sender);

void __fastcallSelectButtonClick(TObject *Sender);

private:        // User declarations

String* curColor;

public:         // User declarations

virtual __fastcall TColorForm(TComponent* Owner);

virtual __fastcall TColorForm(String* s, TComponent* Owner);

};

The form has a listbox called ColorListBox with a list of names of colors. When pressed, the button called SelectButton makes note of the currently selected color name in ColorListBox then closes the form. CancelButton is a button that simply closes the form.

Note that a user-defined constructor was added to the class that takes a String* argument. Presumably, this String* points to a string that the form launching ColorForm knows about. The implementation of this constructor is as follows:

void__fastcall TColorForm::TColorForm(String* s, TComponent* Owner)

 : TForm(Owner)

{

curColor = s;

*curColor = "";

}

The constructor saves the pointer to a private data member curColor and initializes the string to an empty string.

Note:	To use the above user-defined constructor, the form must be explicitly created. It cannot be auto-created when the application is started. For details, see Controlling when forms reside in memory.

In the application, the user selects a color from the listbox and presses SelectButton to save the choice and close the form. The OnClick event handler for SelectButton might look like this:

void __fastcall TColorForm::SelectButtonClick(TObject *Sender)

{

int index = ColorListBox->ItemIndex;

if (index >= 0)

*curColor = ColorListBox->Items->Strings[index];

Close();

}

Notice that the event handler stores the selected color name in the string address that was passed to the constructor.

To use ColorForm effectively, the calling form must pass the constructor a pointer to an existing string. For example, assume ColorForm was instantiated by a form called ResultsForm in response to a button called UpdateButton on ResultsForm being clicked. The event handler would look as follows:

void __fastcall TResultsForm::UpdateButtonClick(TObject *Sender)

{

String s;

GetColor(&s);

if (s != "") {

// do something with the color name string

}

else {

// do something else because no color was picked

}

}

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

void TResultsForm::GetColor(String *s)

{

ColorForm = new TColorForm(s, this);

ColorForm->ShowModal();

delete ColorForm;

ColorForm = 0; // NULL the pointer

}

UpdateButtonClick creates a String called s. The address of s is passed to the GetColor function which creates ColorForm, passing the pointer to s as an argument to the constructor. As soon as ColorForm is closed it is deleted, but the color name that was selected is still preserved in s, assuming that a color was selected. Otherwise, s contains an empty string which is a clear indication that the user exited ColorForm without selecting a color.

This example uses one string variable to hold information from the modal form. Of course, more complex objects can be used depending on the need. Keep in mind that you should always provide a way to let the calling form know if the modal form was closed without making any changes or selections (such as having s default to an empty string).


Creating and managing menus

Topic groups	See also

Menus provide an easy way for your users to execute logically grouped commands. The Menu Designer enables you to easily add a menu—either predesigned or custom tailored—to your form. You simply add a menu component to the form, open the Menu Designer, and type menu items directly into the Menu Designer window. You can add or delete menu items, or drag and drop them to rearrange them during design time.

You don't even need to run your program to see the results—your design is immediately visible in the form, appearing just as it will during runtime. Your code can also change menus at runtime, to provide more information or options to the user.

This section explains how to use the Menu Designer to design menu bars and pop-up (local) menus. It discusses the following ways to work with menus at design time and runtime:

Opening the Menu Designer

Building menus

Editing menu items in the Object Inspector

Using the Menu Designer context menu

Using menu templates

Saving a menu as a template

Adding images to menu items


Opening the Menu Designer

Topic groups	See also

To start using the Menu Designer, first add either a MainMenu or PopupMenu component to your form. Both menu components are located on the Standard page of the Component palette.

A MainMenu component creates a menu that’s attached to the form’s title bar. A PopupMenu component creates a menu that appears when the user right-clicks in the form. Pop-up menus do not have a menu bar.

To open the Menu Designer, select a menu component on the form, and then choose from one of the following methods:

Double-click the menu component.

From the Properties page of the Object Inspector, select the Items property, and then either double-click [Menu] in the Value column, or click the ellipsis (...) button.

The Menu Designer appears, with the first (blank) menu item highlighted in the Designer, and the Caption property highlighted in the Object Inspector.


Building menus

Topic groups	See also

You add a menu component to your form, or forms, for every menu you want to include in your application. You can build each menu structure entirely from scratch, or you can start from one of the predesigned menu templates.

This section discusses the basics of creating a menu at design time.For more information about menu templates, see Using menu templates.


Naming menus

Topic groups	See also

As with all components, when you add a menu component to the form, C++Builder gives it a default name; for example, MainMenu1. You can give the menu a more meaningful name that follows Object Pascal naming conventions.

C++Builder adds the menu name to the form’s type declaration, and the menu name then appears in the Component list.


Naming the menu items

Topic groups	See also

In contrast to the menu component itself, you need to explicitly name menu items as you add them to the form. You can do this in one of two ways:

Directly type in the value for the Name property.

Type in the value for the Caption property first, and let C++Builder derive the Name property from the caption.

For example, if you give a menu item a Caption property value of File, C++Builder assigns the menu item a Name property of File1. If you fill in the Name property before filling in the Caption property, C++Builder leaves the Caption property blank until you type in a value.

Note:	If you enter characters in the Caption property that are not valid for C++ identifiers, C++Builder modifies the Name property accordingly. For example, if you want the caption to start with a number, C++Builder precedes the number with a character to derive the Name property.

The following table demonstrates some examples of this, assuming all menu items shown appear in the same menu bar.

Component caption	Derived name	Explanation
&File	File1	Removes ampersand
&File (2nd occurrence)	File2	Numerically orders duplicate items
1234	N12341	Adds a preceding letter and numerical order
1234 (2nd occurrence)	N12342	Adds a number to disambiguate the derived name
$@@@#	N1	Removes all non-standard characters, adding preceding letter and numerical order
- (hyphen)	N2	Numerical ordering of second occurrence of caption with no standard characters
As with the menu component, C++Builder adds any menu item names to the form’s type declaration, and those names then appear in the Component list.


Adding, inserting, and deleting menu items

Topic groups	See also

The following procedures describe how to perform the basic tasks involved in building your menu structure. Each procedure assumes you have the Menu Designer window open.

To add menu items at design time,

1	Select the position where you want to create the menu item.

If you’ve just opened the Menu Designer, the first position on the menu bar is already selected.

2	Begin typing to enter the caption. Or enter the Name property first by specifically placing your cursor in the Object Inspector and entering a value. In this case, you then need to reselect the Caption property and enter a value.

3	Press Enter.

The next placeholder for a menu item is selected.

If you entered the Caption property first, use the arrow keys to return to the menu item you just entered. You’ll see that C++Builder has filled in the Name property based on the value you entered for the caption. (See Naming the menu items.)

4	Continue entering values for the Name and Caption properties for each new item you want to create, or press Esc to return to the menu bar.

Use the arrow keys to move from the menu bar into the menu, and to then move between items in the list; press Enter to complete an action. To return to the menu bar, press Esc.

To insert a new, blank menu item,

1	Place the cursor on a menu item.

2	Press Ins.

Menu items are inserted to the left of the selected item on the menu bar, and above the selected item in the menu list.

To delete a menu item or command,

1	Place the cursor on the menu item you want to delete.

2	Press Del.

Note:	You cannot delete the default placeholder that appears below the item last entered in a menu list, or next to the last item on the menu bar. This placeholder does not appear in your menu at runtime.


Adding separator bars

Topic groups	See also

Separator bars insert a line between menu items. You can use separator bars to indicate groupings within the menu list, or simply to provide a visual break in a list.

To make the menu item a separator bar, type a hyphen (-) for the caption.


Specifying accelerator keys and keyboard shortcuts

Topic groups	See also

Accelerator keys enable the user to access a menu command from the keyboard by pressing Alt+ the appropriate letter, indicated in your code by the preceding ampersand. The letter after the ampersand appears underlined in the menu.

Keyboard shortcuts enable the user to perform the action without accessing the menu directly, by typing in the shortcut key combination.

To specify an accelerator,

Add an ampersand in front of the appropriate letter.

For example, to add a Save menu command with the S as an accelerator key, type &Save.

To specify a keyboard shortcut,

Use the Object Inspector to enter a value for the ShortCut property, or select a key combination from the drop-down list.

This list is only a subset of the valid combinations you can type in.

When you add a shortcut, it appears next to the menu item caption.

Caution:	C++Builder does not check for duplicate shortcut keys or accelerators, so you need to track values you have entered in your application menus.+


Creating submenus

Topic groups	See also

Many application menus contain drop-down lists that appear next to a menu item to provide additional, related commands. Such lists are indicated by an arrow to the right of the menu item. C++Builder supports as many levels of such submenus as you want to build into your menu.

Organizing your menu structure this way can save vertical screen space. However, for optimal design purposes you probably want to use no more than two or three menu levels in your interface design. (For pop-up menus, you might want to use only one submenu, if any.)

To create a submenu,

1	Select the menu item under which you want to create a submenu.

2	Press Ctrl® to create the first placeholder, or right-click and choose Create Submenu.

3	Type a name for the submenu item, or drag an existing menu item into this placeholder.

4	Press Enter, or ¯, to create the next placeholder.

5	Repeat steps 3 and 4 for each item you want to create in the submenu.

6	Press Esc to return to the previous menu level.


Creating submenus by demoting existing menus

Topic groups	See also

You can create a submenu by inserting a menu item from the menu bar (or a menu template) between menu items in a list. When you move a menu into an existing menu structure, all its associated items move with it, creating a fully intact submenu. This pertains to submenus as well—moving a menu item into an existing submenu just creates one more level of nesting.


Moving menu items

Topic groups	See also

During design time, you can move menu items simply by dragging and dropping. You can move menu items along the menu bar, or to a different place in the menu list, or into a different menu entirely.

The only exception to this is hierarchical: you cannot demote a menu item from the menu bar into its own menu; nor can you move a menu item into its own submenu. However, you can move any item into a different menu, no matter what its original position is.

While you are dragging, the cursor changes shape to indicate whether you can release the menu item at the new location. When you move a menu item, any items beneath it move as well.

To move a menu item along the menu bar,

1	Drag the menu item along the menu bar until the arrow tip of the drag cursor points to the new location.

2	Release the mouse button to drop the menu item at the new location.

To move a menu item into a menu list,

1	Drag the menu item along the menu bar until the arrow tip of the drag cursor points to the new menu.

This causes the menu to open, enabling you to drag the item to its new location.

2	Drag the menu item into the list, releasing the mouse button to drop the menu item at the new location.


Adding images to menu items

Topic groups	See also

Images can help users navigate in menus by matching glyphs and images to menu item action, similar to toolbar images. To add an image to a menu item:

1	Drop a TMainMenu or TPopupMenu object on a form.

2	Drop a TImageList object on the form.

3	Open the ImageList editor by double clicking on the TImageList object.

4	Click Add to select the bitmap or bitmap group you want to use in the menu. Click OK.

5	Set the TMainMenu or TPopupMenu object’s Images property to the ImageList you just created.

6	Create your menu items and submenu items as described in this topic group.

7	Select the menu item you want to have an image in the Object Inspector and set the ImageIndex property to the corresponding number of the image in the ImageList (the default value for ImageIndex is -1, which doesn’t display an image).

Note:	Use images that are 16 by 16 pixels for proper display in the menu. Although you can use other sizes for the menu images, alignment and consistency problems may result when using images greater than or smaller than 16 by 16 pixels.


Viewing the menu

Topic groups	See also

You can view your menu in the form at design time without first running your program code. (Pop-up menu components are visible in the form at design time, but the pop-up menus themselves are not. Use the Menu Designer to view a pop-up menu at design time.)

To view the menu,

1	If the form is visible, click the form, or from the View menu, choose the form whose menu you want to view.

2	If the form has more than one menu, select the menu you want to view from the form’s Menu property drop-down list.

The menu appears in the form exactly as it will when you run the program.


Editing menu items in the Object Inspector

Topic groups	See also

This section has discussed how to set several properties for menu items—for example, the Name and Caption properties—by using the Menu Designer.

The section has also described how to set menu item properties, such as the ShortCut property, directly in the Object Inspector, just as you would for any component selected in the form.

When you edit a menu item by using the Menu Designer, its properties are still displayed in the Object Inspector. You can switch focus to the Object Inspector and continue editing the menu item properties there. Or you can select the menu item from the Component list in the Object Inspector and edit its properties without ever opening the Menu Designer.

To close the Menu Designer window and continue editing menu items,

1	Switch focus from the Menu Designer window to the Object Inspector by clicking the properties page of the Object Inspector.

2	Close the Menu Designer as you normally would.

The focus remains in the Object Inspector, where you can continue editing properties for the selected menu item. To edit another menu item, select it from the Component list.


Using the Menu Designer context menu

Topic groups	See also

The Menu Designer context menu provides quick access to the most common Menu Designer commands, and to the menu template options. (For more information about menu templates, refer to Using menu templates.)

To display the context menu, right-click the Menu Designer window, or press Alt+F10 when the cursor is in the Menu Designer window.


Commands on the context menu

Topic groups	See also

The following table summarizes the commands on the Menu Designer context menu.

Menu command	Action
Insert	Inserts a placeholder above or to the left of the cursor.
Delete	Deletes the selected menu item (and all its sub-items, if any).
Create Submenu	Creates a placeholder at a nested level and adds an arrow to the right of the selected menu item.
Select Menu	Opens a list of menus in the current form. Double-clicking a menu name opens the designer window for the menu.
Save As Template	Opens the Save Template dialog box, where you can save a menu for future reuse.
Insert From Template	Opens the Insert Template dialog box, where you can select a template to reuse.
Delete Templates	Opens the Delete Templates dialog box, where you can choose to delete any existing templates.
Insert From Resource	Opens the Insert Menu from Resource file dialog box, where you can choose an .MNU file to open in the current form.


Switching between menus at design time

Topic groups	See also

If you’re designing several menus for your form, you can use the Menu Designer context menu or the Object Inspector to easily select and move among them.

To use the context menu to switch between menus in a form,

1	Right-click in the Menu Designer and choose Select Menu.

The Select Menu dialog box appears.

This dialog box lists all the menus associated with the form whose menu is currently open in the Menu Designer.

2	From the list in the Select Menu dialog box, choose the menu you want to view or edit.

To use the Object Inspector to switch between menus in a form,

1	Give focus to the form whose menus you want to choose from.

2	From the Component list, select the menu you want to edit.

3	On the Properties page of the Object Inspector, select the Items property for this menu, and then either click the ellipsis button, or double-click [Menu].


Using menu templates

Topic groups	See also

C++Builder provides several predesigned menus, or menu templates, that contain frequently used commands. You can use these menus in your applications without modifying them (except to write code), or you can use them as a starting point, customizing them as you would a menu you originally designed yourself. Menu templates do not contain any event handler code.

The menu templates shipped with C++Builder are stored in the BIN subdirectory in a default installation. These files have a .DMT (C++Builder menu template) extension.

You can also save as a template any menu that you design using the Menu Designer. After saving a menu as a template, you can use it as you would any predesigned menu. If you decide you no longer want a particular menu template, you can delete it from the list.

To add a menu template to your application,

1	Right-click the Menu Designer and choose Insert From Template.

(If there are no templates, the Insert From Template option appears dimmed in the context menu.)

The Insert Template dialog box opens, displaying a list of available menu templates.

2	Select the menu template you want to insert, then press Enter or choose OK.

This inserts the menu into your form at the cursor’s location. For example, if your cursor is on a menu item in a list, the menu template is inserted above the selected item. If your cursor is on the menu bar, the menu template is inserted to the left of the cursor.

To delete a menu template,

1	Right-click the Menu Designer and choose Delete Templates.

(If there are no templates, the Delete Templates option appears dimmed in the context menu.)

The Delete Templates dialog box opens, displaying a list of available templates.

2	Select the menu template you want to delete, and press Del.

C++Builder deletes the template from the templates list and from your hard disk.


Saving a menu as a template

Topic groups	See also

Any menu you design can be saved as a template so you can use it again. You can use menu templates to provide a consistent look to your applications, or use them as a starting point which you then further customize.

The menu templates you save are stored in your BIN subdirectory as .DMT files.

To save a menu as a template,

1	Design the menu you want to be able to reuse.

This menu can contain as many items, commands, and submenus as you like; everything in the active Menu Designer window will be saved as one reusable menu.

2	Right-click in the Menu Designer and choose Save As Template.

The Save Template dialog box appears.

3	In the Template Description edit box, type a brief description for this menu, and then choose OK.

The Save Template dialog box closes, saving your menu design and returning you to the Menu Designer window.

Note:	The description you enter is displayed only in the Save Template, Insert Template, and Delete Templates dialog boxes. It is not related to the Name or Caption property for the menu.


Naming conventions for template menu items and event handlers

Topic groups	See also

When you save a menu as a template, C++Builder does not save its Name property, since every menu must have a unique name within the scope of its owner (the form). However, when you insert the menu as a template into a new form by using the Menu Designer, C++Builder then generates new names for it and all of its items.

For example, suppose you save a File menu as a template. In the original menu, you name it MyFile. If you insert it as a template into a new menu, C++Builder names it File1. If you insert it into a menu with an existing menu item named File1, C++Builder names it File2.

C++Builder also does not save any OnClick event handlers associated with a menu saved as a template, since there is no way to test whether the code would be applicable in the new form. When you generate a new event handler for the menu template item, C++Builder still generates the event handler name.

You can easily associate items in the menu template with existing OnClick event handlers in the form..


Manipulating menu items at runtime

Topic groups	See also

Sometimes you want to add menu items to an existing menu structure while the application is running, to provide more information or options to the user. You can insert a menu item by using the menu item’s Add or Insert method, or you can alternately hide and show the items in a menu by changing their Visible property. The Visible property determines whether the menu item is displayed in the menu. To dim a menu item without hiding it, use the Enabled property.

For specific code examples that use the menu item’s Visible and Enabled properties, see Disabling menu items.

In multiple document interface (MDI) and Object Linking and Embedding (OLE) applications, you can also merge menu items into an existing menu bar. See Merging menus for more information.


Merging menus

Topic groups	See also

For MDI applications, such as the text editor sample application, and for OLE client applications, your application’s main menu needs to be able to receive menu items either from another form or from the OLE server object. This is often called merging menus.

You prepare menus for merging by specifying values for two properties:

Menu, a property of the form

GroupIndex, a property of menu items in the menu


Specifying the active menu: Menu property

Topic groups	See also

The Menu property specifies the active menu for the form. Menu-merging operations apply only to the active menu. If the form contains more than one menu component, you can change the active menu at runtime by setting the Menu property in code. For example,

Form1->Menu = SecondMenu;


Determining the order of merged menu items: GroupIndex property

Topic groups	See also

The GroupIndex property determines the order in which the merging menu items appear in the shared menu bar. Merging menu items can replace those on the main menu bar, or can be inserted.

The default value for GroupIndex is 0. Several rules apply when specifying a value for GroupIndex:

Lower numbers appear first (farther left) in the menu.

For instance, set the GroupIndex property to 0 (zero) for a menu that you always want to appear leftmost, such as a File menu. Similarly, specify a high number (it needn’t be in sequence) for a menu that you always want to appear rightmost, such as a Help menu.

To replace items in the main menu, give items on the child menu the same GroupIndex value.

This can apply to groupings or to single items. For example, if your main form has an Edit menu item with a GroupIndex value of 1, you can replace it with one or more items from the child form's menu by giving them a GroupIndex value of 1 as well.

Giving multiple items in the child menu the same GroupIndex value keeps their order intact when they merge into the main menu.

To insert items without replacing items in the main menu, leave room in the numeric range of the main menu’s items and “plug in” numbers from the child form.

For example, number the items in the main menu 0 and 5, and insert items from the child menu by numbering them 1, 2, 3 and 4.


Importing resource files

Topic groups	See also

C++Builder supports menus built with other applications, so long as they are in the standard Windows resource (.RC) file format. You can import such menus directly into your C++Builder project, saving you the time and effort of rebuilding menus that you created elsewhere.

To load existing .RC menu files,

1	In the Menu Designer, place your cursor where you want the menu to appear.

The imported menu can be part of a menu you are designing, or an entire menu in itself.

2	Right-click and choose Insert From Resource.

The Insert Menu From Resource dialog box appears.

3	In the dialog box, select the resource file you want to load, and choose OK.

The menu appears in the Menu Designer window.

Note:	If your resource file contains more than one menu, you first need to save each menu as a separate resource file before importing it.


Designing toolbars and cool bars

Topic groups	See also

A toolbar is a panel, usually across the top of a form (under the menu bar), that holds buttons and other controls. Toolbars provide a visible way to present options to the user, and C++Builder makes it easy to add toolbars to your forms. A cool bar is a kind of toolbar that displays controls on movable, resizable bands.

You can add as many toolbars to a form as you want. If you have multiple panels aligned to the top of the form, they stack vertically in the order added.

You can put controls of any sort on a toolbar. In addition to buttons, you may want to put use color grids, scroll bars, labels, and so on.

There are several ways to add a toolbar to a form:

Place a panel (TPanel) on the form and add controls (typically speed buttons) to it.

Use a toolbar component (TToolBar) instead of TPanel, and add controls to it. TToolBar manages buttons and other controls, arranging them in rows and automatically adjusting their sizes and positions. If you use tool button (TToolButton) controls on the toolbar, TToolBar makes it easy to group the buttons functionally and provides other display options.

Use a cool bar (TCoolBar) component and add controls to it. The cool bar displays controls on independently movable and resizable bands.

How you implement your toolbar depends on your application. The advantage of using the Panel component is that you have total control over the look and feel of the toolbar.

By using the toolbar and cool bar components, you are ensuring that your application has the look and feel of a Windows application because you are using the native Windows controls. If these operating system controls change in the future, your application could change as well. Also, since the toolbar and cool bar rely on common components in Windows, your application requires the COMCTL32.DLL. Toolbars and cool bars are not supported in WinNT 3.51 applications.

The following sections describe how to

Adding a toolbar using a panel component

Adding a toolbar using the toolbar component

Adding a cool bar component

Responding to clicks

Adding hidden toolbars

Hiding and showing toolbars


Adding a toolbar using a panel component

Topic groups	See also

To add a toolbar to a form using the panel component,

1	Add a panel component to the form (from the Standard page of the Component palette).

2	Set the panel’s Align property to alTop. When aligned to the top of the form, the panel maintains its height, but matches its width to the full width of the form’s client area, even if the window changes size.

3	Add speed buttons or other controls to the panel.

Speed buttons are designed to work on toolbar panels. A speed button usually has no caption, only a small graphic (called aglyph), which represents the button’s function.

Speed buttons have three possible modes of operation. They can

Act like regular pushbuttons

Toggle on and off when clicked

Act like a set of radio buttons

To implement speed buttons on toolbars, do the following:

Adding a speed button to a panel

Assigning a speed button’s glyph

Setting the initial condition of a speed button

Creating a group of speed buttons

Allowing toggle buttons


Adding a speed button to a panel

Topic groups	See also

To add a speed button to a toolbar panel, place the speed button component (from the Additional page of the Component palette) on the panel.

The panel, rather than the form, “owns” the speed button, so moving or hiding the panel also moves or hides the speed button.

The default height of the panel is 41, and the default height of speed buttons is 25. If you set the Top property of each button to 8, they’ll be vertically centered. The default grid setting snaps the speed button to that vertical position for you.


Assigning a speed button's glyph
Assigning a speed button’s glyph

Topic groups	See also

Each speed button needs a graphic image called a glyph to indicate to the user what the button does. If you supply the speed button only one image, the button manipulates that image to indicate whether the button is pressed, unpressed, selected, or disabled. You can also supply separate, specific images for each state if you prefer.

You normally assign glyphs to speed buttons at design time, although you can assign different glyphs at runtime.

To assign a glyph to a speed button at design time,

1	Select the speed button.

2	In the Object Inspector, select the Glyph property.

3	Double-click the Value column beside Glyph to open the Picture Editor and select the desired bitmap.


Setting the initial condition of a speed button

Topic groups	See also

Speed buttons use their appearance to give the user clues as to their state and purpose. Because they have no caption, it’s important that you use the right visual cues to assist users.

The table below lists some actions you can set to change a speed button’s appearance:

To make a speed button:	Set the toolbar’s:
Appear pressed	GroupIndex property to a value other than zero and its Down property to true.
Appear disabled	Enabled property to false.
Have a left margin	Indent property to a value greater than 0.
If your application has a default drawing tool, ensure that its button on the toolbar is pressed when the application starts. To do so, set its GroupIndex property to a value other than zero and its Down property to true.


Creating a group of speed buttons

Topic groups	See also

A series of speed buttons often represents a set of mutually exclusive choices. In that case, you need to associate the buttons into a group, so that clicking any button in the group causes the others in the group to pop up.

To associate any number of speed buttons into a group, assign the same number to each speed button’s GroupIndex property.

The easiest way to do this is to select all the buttons you want in the group, and, with the whole group selected, set GroupIndex to a unique value.


Allowing toggle buttons

Topic groups	See also

Sometimes you want to be able to click a button in a group that’s already pressed and have it pop up, leaving no button in the group pressed. Such a button is called a toggle. Use AllowAllUp to create a grouped button that acts as a toggle: click it once, it’s down; click it again, it pops up.

To make a grouped speed button a toggle, set its AllowAllUp property to true.

Setting AllowAllUp to true for any speed button in a group automatically sets the same property value for all buttons in the group. This enables the group to act as a normal group, with only one button pressed at a time, but also allows every button to be up at the same time.


Adding a toolbar using the toolbar component

Topic groups	See also

The toolbar component (TToolBar) offers button management and display features that panel components do not. To add a toolbar to a form using the toolbar component,

1	Add a toolbar component to the form (from the Win32 page of the Component palette). The toolbar automatically aligns to the top of the form.

2	Add tool buttons or other controls to the bar.

Tool buttons are designed to work on toolbar components. Like speed buttons, tool buttons can

Act like regular pushbuttons

Toggle on and off when clicked

Act like a set of radio buttons

To implement tool buttons on a toolbar, do the following:

Adding a tool button

Assigning images to tool buttons

Setting tool button appearance and initial conditions

Creating groups of tool buttons

Allowing toggled tool buttons


Adding a tool button

Topic groups	See also

To add a tool button to a toolbar, right-click on the toolbar and choose New Button.

The toolbar “owns” the tool button, so moving or hiding the toolbar also moves or hides the button. In addition, all tool buttons on the toolbar automatically maintain the same height and width. You can drop other controls from the Component palette onto the toolbar, and they will automatically maintain a uniform height. Controls will also wrap around and start a new row when they do not fit horizontally on the toolbar.


Assigning images to tool buttons

Topic groups	See also

Each tool button has an ImageIndex property that determines what image appears on it at runtime. If you supply the tool button only one image, the button manipulates that image to indicate whether the button is disabled. To assign images to tool buttons at design time,

1	Select the toolbar on which the buttons appear.

2	In the Object Inspector, assign a TImageList object to the toolbar’s Images property. An image list is a collection of same-sized icons or bitmaps.

3	Select a tool button.

4	In the Object Inspector, assign an integer to the tool button’s ImageIndex property that corresponds to the image in the image list that you want to assign to the button.

You can also specify separate images to appear on the tool buttons when they are disabled and when they are under the mouse pointer. To do so, assign separate image lists to the toolbar’s DisabledImages and HotImages properties.


Setting tool button appearance and initial conditions

Topic groups	See also

The table belowlists some actions you can set to change a tool button’s appearance:

To make a tool button:	Set the toolbar’s:
Appear pressed	GroupIndex property to a nonzero value and its Down property to true.
Appear disabled	Enabled property to false.
Have a left margin	Indent property to a value greater than 0.
Appear to have “pop-up” borders, thus making the toolbar appear transparent	Flat property to true.
Note:	Using the Flat property of TToolBar requires version 4.70 or later of COMCTL32.DLL.

To force a new row of controls after a specific tool button, Select the tool button that you want to appear last in the row and set its Wrap property to true.

To turn off the auto-wrap feature of the toolbar, set the toolbar’s Wrapable property to false.


Creating groups of tool buttons

Topic groups	See also

To create a group of tool buttons, select the buttons you want to associate and set their Style property to tbsCheck; then set their Grouped property to true. Selecting a grouped tool button causes other buttons in the group to pop up, which is helpful to represent a set of mutually exclusive choices.

Any unbroken sequence of adjacent tool buttons with Style set to tbsCheck and Grouped set to true forms a single group. To break up a group of tool buttons, separate the buttons with any of the following:

A tool button whose Grouped property is false.

A tool button whose Style property is not set to tbsCheck. To create spaces or dividers on the toolbar, add a tool button whose Style is tbsSeparator or tbsDivider.

Another control besides a tool button.


Allowing toggled tool buttons

Topic groups	See also

Use AllowAllUp to create a grouped tool button that acts as a toggle: click it once, it is down; click it again, it pops up. To make a grouped tool button a toggle, set its AllowAllUp property to true.

As with speed buttons, setting AllowAllUp to true for any tool button in a group automatically sets the same property value for all buttons in the group.


Adding a cool bar component

Topic groups	See also

The cool bar component—also called a rebar—displays windowed controls on independently movable, resizable bands. The user can position the bands by dragging the resizing grips on the left side of each band.

To add a cool bar to a form,

1	Add a cool bar component to the form (from the Win32 page of the Component palette). The cool bar automatically aligns to the top of the form.

2	Add windowed controls from the Component palette to the bar.

Only components that descend from TWinControl are windowed controls. You can add graphic controls—such as labels or speed buttons—to the cool bar, but they will not appear on separate bands.

Note:	The cool bar component requires version 4.70 or later of COMCTL.DLL.


Setting the appearance of the cool bar

Topic groups

The cool bar component offers several useful configuration options. The table below lists some actions you can set to change a tool button’s appearance:

To make the cool bar:	Set the toolbar’s:
Resize automatically to accommodate the bands it contains	AutoSize property to true.
Bands maintain a uniform height	FixedSize property to true.
Reorient to vertical rather than horizontal	Vertical property to true. This changes the effect of the FixedSize property.
Prevent the Text properties of the bands from displaying at runtime	ShowText property to false. Each band in a cool bar has its own Text property.
Remove the border around the bar	BandBorderStyle to bsNone.
Keep users from changing the bands’ order at runtime. (The user can still move and resize the bands.)	FixedOrder to true.
Create a background image for the cool bar	Bitmap property to TBitmap object.
Choose a list of images to appear on the left of any band	Images property to TImageList object.
To assign images to individual bands, select the cool bar and double-click on the Bands property in the Object Inspector. Then select a band and assign a value to its ImageIndex property.


Responding to clicks

Topic groups	See also

When the user clicks a control, such as a button on a toolbar, the application generates an OnClick event. You handle these OnClick events by writing OnClick event handlers for your forms.


Writing an event handler for a button click

Topic groups

Button controls, including speed buttons and tool buttons, have OnClick events built into them.

To respond to the user’s click on a button, define a handler for the button’s OnClick event.

When you double-click on a button in the Form designer, C++Builder generates an OnClick event handler named after the control clicked. For example, the default OnClick event handler for a speed button named LineButton would be

void __fastcallTForm1::LineButtonClick(TObject *Sender)

{

}

Then, supply the action you want to occur when the user clicks that button.


Assigning a menu to a tool button

Topic groups	See also

If you are using a toolbar (TToolBar) with tool buttons (TToolButton), you can associate menu with a specific button:

1	Select the tool button.

2	In the Object Inspector, assign a pop-up menu (TPopupMenu) to the tool button’s DropDownMenu property.

If the menu’s AutoPopup property is set to true, it will appear automatically when the button is pressed.


Adding hidden toolbars

Topic groups	See also

Toolbars do not have to be visible all the time. In fact, it is often convenient to have a number of toolbars available, but show them only when the user wants to use them. Often you create a form that has several toolbars, but hide some or all of them.

To create a hidden toolbar,

1	Add a toolbar, cool bar, or panel component to the form.

2	Set the component’s Visible property to false.

Although the toolbar remains visible at design time so you can modify it, it remains hidden at runtime until the application specifically makes it visible.


Hiding and showing toolbars

Topic groups	See also

Often, you want an application to have multiple toolbars, but you do not want to clutter the form with them all at once. Or you may want to let users decide whether to display toolbars. As with all components, toolbars can be shown or hidden at runtime as needed.

To hide or show a toolbar at runtime, set its Visible property to false or true, respectively. Usually you do this in response to particular user events or changes in the operating mode of the application. To do this, you typically have a close button on each toolbar. When the user clicks that button, the application hides the corresponding toolbar.

You can also provide a means of toggling the toolbar. In the following example, a toolbar of pens is toggled from a button on the main toolbar. Since each click presses or releases the button, an OnClick event handler can show or hide the Pen toolbar depending on whether the button is up or down.

void __fastcallTForm1::PenButtonClick(TObject *Sender)

{

  PenBar->Visible = PenButton->Down;

}


Using action lists

Topic groups	See also

Action lists let you centralize the response to user commands (actions) for objects such as menus and buttons that respond to those commands. This section is an overview of actions and action lists, describing how to use them and how they interact with their clients and targets.

The following help topics are discussed in this section:

Action objects

Using Actions

Pre-defined action classes

Writing action components


Action objects

Topic groups	See also

Actions are user commands that operate on target objects. You create actions in the action list component editor. These actions are later connected to client controls via their action links. Following are descriptions of each type of component in the action/action list mechanism:

An action (TAction) is the implementation of an action, such as copying highlighted text, on a target, such as an edit control. An action is triggered by a client in response to a user command (such as a mouse click). Clients are typically menu items or buttons. The StdActns unit contains classes derived from TAction that implement the basic Edit and Window menu commands (actions) found in most Window applications.

An action list (TActionList) is a component that maintains a list of actions (TAction). Action lists are the design-time user interface for working with actions.

An action link (TActionLink) is an object that maintains the connection between actions and clients. Action links determine whether an action, or which action, is currently applicable for a given client.

A client of an action is typically a menu item or a button (TToolButton, TSpeedButton, TMenuItem, TButton, TCheckBox, TRadioButton, and so on). An action is initiated by a corresponding command in the client. Typically a client Click is associated with an action Execute.

An action target is usually a control, such as a rich edit, a memo, or a data control. The DBActns unit, for example, contains classes that implement actions specific to data set controls. Component writers can create their own actions specific to the needs of the controls they design and use, and then package those units to create more modular applications.

The following figure shows the relationship of these objects. In this diagram, Cut1 is the action, ActionList1 is the action list containing Cut1, SpeedButton1 is the client of Cut1, and Memo1 is the target. Unlike actions, action lists, action clients, and action targets, action links are non-visual objects. The action link in this diagram is therefore indicated by a white rectangle. The action link associates the SpeedButton1 client to the Cut1 action contained in ActionList1.

The VCL includes TAction, TActionList, and TActionLink type classes for working with Action lists. By unit, these are

ActnList: TAction, TActionLink, TActionList, TContainedAction, TCustomAction, and TCustomActionList

Classes: TBasicAction and TBasicActionLink

Controls: TControlActionLink and TWinControlActionLink

ComCtrls: TToolButtonActionLink

Menus.: TMenuActionLink

StdCtrls: TButtonActionLink

There are also two units, StdActns and DBActns, that contain auxiliary classes that implement specific, commonly used standard Windows and data set actions. These are described in Pre-defined action classes.. Many of the VCL controls include properties (such as Action) and methods (such as ExecuteAction) that enable them to be used as action clients and targets.


Using Actions

Topic groups	See also

You can add an action list to your forms or data modules from the standard page of the Component Palette. Double-click the action list to display the Action List editor, which lets you add, delete, and rearrange actions in much the same way you use the collection editor.

In the Object Inspector, set the properties for each action. The Name property identifies the action, and the other properties and events (Caption, Checked, Enabled, HelpContext, Hint, ImageIndex, ShortCut, and Visible) correspond to the properties of client controls. These are typically, but not necessarily, the same name as the client property. For example, an action’s Checked property corresponds to a TToolButton’s Down property.

How to use actions is discussed in the following help topics:

Centralizing code

Linking properties

Executing actions

Updating actions


Centralizing code

Topic groups	See also

A number of controls such as TToolButton, TSpeedButton, TMenuItem, and TButton have a published property called Action. When you set the Action property to one of the actions in your action list, the values of the corresponding properties in the action are copied to those of the control. All properties and events in common with the action object (except Name and Tag) are dynamically linked to the control. Thus, for example, instead of duplicating the code that disables buttons and menu items, you can centralize this code in an action object, and when the action is disabled, all corresponding buttons and menu items are disabled.


Linking properties

Topic groups	See also

The client’s action link is the mechanism through which its properties are associated with (linked to) the properties of an action. When an action changes, the action link is responsible for updating the client’s properties. For details about which properties a particular action link class handles, refer to the individual action link classes in the VCL reference.

You can selectively override the values of the properties controlled by an associated action object by setting the property’s value in the client component or control. This does not change the property in the action, so only the client is affected.


Executing actions

Topic groups	See also

When a client component or control is clicked, the OnExecute event occurs for it’s associated action. For example, the following code illustrates the OnExecute event handler for an action that toggles the visibility of a toolbar when the action is executed:

void __fastcallTForm1::Action1Execute(TObject *Sender)

{

// Toggle Toolbar1’s visibility

ToolBar1->Visible = !ToolBar1->Visible;

}

Note:	If you are using a tool button or a menu item, you must manually set the Images property of the corresponding toolbar or menu component to the Images property of the action list. This is true even though the ImageIndex property is dynamically linked to the client.

The following figure illustrates the dispatching sequence for the execution cycle of an action called Cut1. This diagram assumes the relationship of the components in the figure in Action objects, meaning that the Speedbutton1 client is linked to the Cut1 action via its action link. Speedbutton1’s Action property is therefore Cut1. Consequently, Speedbutton1’s Click method invokes Cut1’s Execute method.

Note:	In the description of this sequence, one method invoking another does not necessarily mean that the invocation is explicit in the code for that method.

Clicking on Speedbutton1 initiates the following execution cycle:

Speedbutton1’s Click method invokes Cut1::Execute.

The Cut1 action defers to its action list (ActionList1) for the processing of its Execute. This is done by calling the Action list’s ExecuteAction method, passing itself as a parameter.

ActionList1 calls its event handler (OnExecute) for ExecuteAction. (An action list’s ExecuteAction method applies to all actions contained by the action list.) This handler has a parameter Handled, that returns false by default. If the handler is assigned and handles the event, it should return true, and the processing sequence ends here. For example:

void __fastcallTForm1::ActionList1ExecuteAction(TBasicAction *Action, bool &Handled)

{

  // Prevent execution of actions contained by ActionList1

  Handled = true;

}

If execution is not handled, at this point, in the action list event handler, then processing continues:

The Cut1 action is routed to the Application object’s ExecuteAction method, which invokes the OnActionExecute event handler. (The application’s ExecuteAction method applies to all of the actions in that application.) The sequence is the same as for the action list ExecuteAction: The handler has a parameter Handled that returns false by default. If the handler is assigned and handles the event, it should return true, and the processing sequence ends here. For example:

void __fastcallTForm1::ApplicationExecuteAction(TBasicAction *Action, bool &Handled)

{

  // Prevent execution of all actions in Application

  Handled = true;

}

If execution is not handled in the application’s event handler, then Cut1 send the CM_ACTIONEXECUTE message to the application’s WndProc, passing itself as a parameter. The application then tries to find a target on which to execute the action (see the figure"Action targets”).


Updating actions

Topic groups	See also

When the application is idle, the OnUpdate event occurs for every action that is linked to a visible control or menu item that is showing. This provides an opportunity for applications to execute centralized code for enabling and disabling, checking and unchecking, and so on. For example, the following code illustrates the OnUpdate event handler for an action that is “checked” when the toolbar is visible:

void __fastcallTForm1::Action1Update(TObject *Sender)

{

// Indicate whether ToolBar1 is currently visible

((TAction *)Sender)->Checked = ToolBar1->Visible;

}

See also the RichEdit demo.

The dispatching cycle for updating actions follows the same sequence as the execution cycle in The figure in Executing actions.

Note:	Do not add time-intensive code to the OnUpdate event handler. This executes whenever the application is idle. If the event handler takes too much time, it will adversely affect performance of the entire application.


Pre-defined action classes

Topic groups	See also

Component writers can use the classes in the StdActns and DBActns units as examples for deriving their own action classes that implement behaviors specific to certain controls or components. The base classes for these specialized actions (TEditAction, TWindowAction) generally override HandlesTarget, UpdateTarget, and other methods to limit the target for the action to a specific class of objects. The descendant classes typically override ExecuteTarget to perform a specialized task.

The pre-defined action classes are grouped into the following categories:

Standard edit actions

Standard Window actions

DataSet actions


Standard edit actions

Topic groups	See also

The standard edit actions are designed to be used with an edit control target. TEditAction is the base class for descendants that each override the ExecuteTarget method to implement copy, cut, and paste tasks by using the Windows Clipboard.

TEditAction ensures that the target control is a TCustomEdit class (or descendant).

TEditCopy copies highlighted text to the Clipboard.

TEditCut cuts highlighted text from the target to the Clipboard.

TEditPaste pastes text from the Clipboard to the target and ensures that the Clipboard is enabled for the text format.


Standard Window actions

Topic groups	See also

The standard Window actions are designed to be used with forms as targets in an MDI application. TWindowAction is the base class for descendants that each override the ExecuteTarget method to implement arranging, cascading, closing, tiling, and minimizing MDI child forms.

TWindowAction ensures that the target control is a TForm class and checks whether the form has MDI child forms.

TWindowArrange arranges the icons of minimized MDI child forms.

TWindowCascade cascades the MDI child forms.

TWindowClose closes the active MDI child form.

TWindowMinimizeAll minimizes all of the MDI child forms.

TWindowTileHorizontal arranges MDI child forms so that they are all the same size, tiled horizontally.

TWindowTileVertical arranges MDI child forms so that they are all the same size, tiled vertically.


DataSet actions

Topic groups	See also

The standard dataset actions are designed to be used with a dataset component target. TDataSetAction is the base class for descendants that each override the ExecuteTarget and UpdateTarget methods to implement navigation and editing of the target.

The TDataSetAction introduces a DataSource property which ensures actions are performed on that dataset. If DataSource is NULL, the currently focused data-aware control is used..

TDataSetAction ensures that the target is a TDataSource class and has an associated data set.

TDataSetCancel cancels the edits to the current record, restores the record display to its condition prior to editing, and turns off Insert and Edit states if they are active.

TDataSetDelete deletes the current record and makes the next record the current record.

TDataSetEdit puts the dataset into Edit state so that the current record can be modified.

TDataSetFirst sets the current record to the first record in the dataset.

TDataSetInsert inserts a new record before the current record, and sets the dataset into Insert and Edit states.

TDataSetLast sets the current record to the last record in the dataset.

TDataSetNext sets the current record to the next record.

TDataSetPost writes changes in the current record to the dataset.

TDataSetPrior sets the current record to the previous record.

TDataSetRefresh refreshes the buffered data in the associated dataset.


Writing action components

Topic groups	See also

The pre-defined actions are examples of extending the VCL action classes. The following topics are useful if you are writing your own action classes:

How actions find their targets

Registering actions

Writing action list editors


How actions find their targets

Topic groups	See also

The figure in Executing actions illustrates the execution cycle for the standard VCL action classes. If execution is not handled by the action list, the application, or the default action event handlers, then the CM_ACTIONEXECUTE message is sent to the application’s WndProc. The following figure continues the execution sequence at this point. The pre-defined action classes as well as any action class that you create, use this path of execution:

Upon receiving the CM_ACTIONEXECUTE message the application first dispatches it to the Screen’s ActiveForm. If there is no active form, the application sends the message to it’s MainForm.

Form1 (in this example, the active form) first looks for the active control (Memo1) and calls that control’s ExecuteAction method passing Cut1 as a parameter.

Memo1 calls Cut1’s HandlesTarget method, passing itself to determine whether it is an appropriate target for the action. If Memo1 is not an appropriate target, HandlesTarget returns false and Memo1’s ExecuteAction handler returns false.

In this case, Memo1 is an appropriate target for Cut1, so HandlesTarget returns true. Memo1 then calls Cut1::ExecuteTarget passing itself as a parameter. Finally, since Cut1 is an instance of a TEditCut action, the action calls Memo1’s CutToClipoard method:

void __fastcallTEditCut::ExecuteTarget(TObject *Target)

{

  ((TCustomEdit *)Target)->CutToClipboard();

}

If the control were not an appropriate target, processing would continue as follows:

Form1 calls its ExecuteAction method. If Form1 is an appropriate target (for example, a form would be a target for the TWindowCascade action) then it calls Cut1’sExecuteTarget method, passing itself as a parameter.

If Form1 is not an appropriate target, it invokes ExecuteAction on every visible control it owns until a target is found.

Note:	If the action involved is a TCustomAction type, then the action is automatically disabled for you if, the action is not handled and, its DisableIfNoHandler property is true.


Registering actions

Topic groups	See also

You can register and unregister your own actions with the IDE by using the global routines in the ActnList unit:

extern PACKAGE void __fastcallRegisterActions(constAnsiString CategoryName, TMetaClass* const* AClasses, const intAClasses_Size, TMetaClass*Resource);

extern PACKAGE void __fastcallUnRegisterActions(TMetaClass* const * AClasses, const intAClasses_Size);

Use these routines the same way you would when registering components RegisterComponents). For example, the following code registers actions with the IDE in the MyAction unit:

namespace MyAction

{

  void __fastcallPACKAGE Register()

  {

     // code goes here to register any components and editors

      TMetaClass classes[2] = {__classid(TMyAction1), __classid(TMyAction2)};

      RegisterActions("MySpecialActions", classes, 1, NULL);

  }

}


Writing action list editors

Topic groups	See also

You may want to write your own component editor for action lists. If you do, you can assign your own procedures to the four global procedure variables in the ActnList unit:

extern PACKAGE Classes::TBasicAction* __fastcall (*CreateActionProc)(Classes::TComponent* AOwner, TMetaClass* ActionClass);

extern PACKAGE void __fastcall (*EnumRegisteredActionsProc)(TEnumActionProc Proc, void * Info);

extern PACKAGE void __fastcall (*RegisterActionsProc)(const AnsiString CategoryName, TMetaClass* const * AClasses, const int AClasses_Size, TMetaClass* Resource);

extern PACKAGE void __fastcall (*UnRegisterActionsProc)(TMetaClass* const * AClasses, const int AClasses_Size);

You only need to reassign these if you want to manage the registration, unregistration, creation, and enumeration procedures of actions differently from the default behavior. If you do, write your own handlers and assign them to these variables within the initialization section of your design-time unit.


Implementing drag-and-drop in controls

Topic groups	See also

Dragging and dropping items can be a handy way to enable users to manipulate objects in a form. You can let users drag an entire control, or let them drag items out of a control such as a list box or tree view into another control.

The elements to drag-and-drop operations:

Starting a drag operation

Accepting dragged items

Dropping items

Ending a drag operation

Customizing drag and drop with a drag object

Changing the drag mouse pointer


Starting a drag operation

Topic groups	See also

Every control has a property called DragMode that controls how the component responds when a user begins dragging the component at runtime. If DragMode is dmAutomatic, dragging begins automatically when the user presses a mouse button with the cursor on the control. Because dmAutomatic can interfere with normal mouse activity, you may want to set DragMode to dmManual (which is the default) and start the dragging by handling mouse-down events.

To start dragging a control manually, call the control’s BeginDrag method.

BeginDrag takes a boolean parameter called Immediate. If you pass true, dragging begins immediately, much as if DragMode were dmAutomatic. If you pass false, dragging does not begin until the user actually moves the mouse a short distance. Calling BeginDrag(false) allows the control to accept mouse clicks without beginning a drag operation.

You can also place conditions on whether to begin dragging, such as checking which button the user pressed, by testing the parameters of the mouse-down event before calling BeginDrag.

The following code, for example, handles a mouse-down event on a file list box by beginning dragging only if the left mouse button was pressed:

void __fastcallTFMForm::FileListBox1MouseDown(TObject *Sender,
  TMouseButton Button, TShiftState Shift, int X, int Y)

{

  if (Button == mbLeft)	// drag only if left button pressed

  {

    TFileListBox *pLB = (TFileListBox *)Sender; // cast to TFileListBox

    if(pLB->ItemAtPos(Point(X,Y), true) >= 0) // is there an item here?

      pLB->BeginDrag(false);                   // if so, drag it

  }

}

This code does not let you drop the item anywhere. Before you can drop items, you must have controls that accept drops.


Accepting dragged items

Topic groups	See also

When a user drags something over a control, that control receives an OnDragOver event, at which time it must indicate whether it can accept the item if the user drops it there. C++Builder changes the drag cursor to indicate whether the control can accept the dragged item.

To accept items dragged over a control, attach an event handler to the control’s OnDragOver event.

The drag-over event has a variable parameter called Accept that the event handler can set to true if it will accept the item.

Setting Accept to true specifies that if the user releases the mouse button at that point, thereby dropping the dragged item, the application can then send a drag-drop event to the same control. If Accept is false, the application does not drop the item on that control. This means that a control should never have to handle a drag-drop event for an item it does not know how to handle.

The drag-over event includes several parameters, including the source of the dragging and the current location of the mouse cursor. The event handler can use those parameters to determine whether to accept the drop. Most often, a control accepts or rejects a dragged item based on the type of the sender, but it can also accept items only from specific instances.

In the following example, a directory tree view accepts dragged items only if they come from a file list box:

void __fastcallTForm1::TreeView1DragOver(TObject *Sender, TObject *Source,

  int X, int Y, TDragState State, bool &Accept)

{

  if (Source->InheritsFrom(__classid(TFileListBox)))
    Accept = true;

}


Dropping items

Topic groups	See also

Once a control indicates that it can accept a dragged item, it should then also define some way to handle the item should it be dropped. If a user sees the mouse cursor change to indicate that a control will accept the item being dragged, it is reasonable for the user to then expect that dropping the item there will accomplish some task.

To handle dropped items, attach an event handler to the OnDragDrop event of the control accepting the dropped item.

Like the drag-over event, the drag-drop event indicates the source of the dragged item and the coordinates of the mouse cursor over the accepting control. These parameters enable the drag-drop handler to get any needed information from the source of the drag and determine how to handle it.

For example, a directory tree view accepting items dragged from a file list box can move the file from its current location to the directory dropped on:

void __fastcall TForm1::TreeView1DragDrop(TObject *Sender, TObject *Source,
int X, int Y){

  if (Source->InheritsFrom(__classid(TFileListBox)))

  {

    TTreeNode *pNode = TreeView1->GetNodeAt(X,Y); // pNode is drop target

    AnsiString NewFile = pNode->Text + AnsiString("/") +

      ExtractFileName(FileList->FileName); // build file name for drop target

    MoveFileEx(FileList->FileName.c_str(), NewFile.c_str(),

      MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED); // move the file

  }

}

The source is the component being dragged, while the event handler is associated with the component being passed over. The OnDragDrop event allows you to monitor the path a component takes while being dragged. For example, you might want to change the background color of the component as it is being passed over.


Ending a drag operation

Topic groups	See also

When a dragging operation ends, either by dropping the dragged item or by the user releasing the mouse button over a control that does not accept the dragged item, C++Builder sends an end-drag event back to the control the user dragged.

To enable a control to respond when items have been dragged from it, attach an event handler to the OnEndDrag event of the control.

The most important parameter in an OnEndDrag event is called Target, which indicates which control, if any, accepts the drop. If Target is null, it means no control accepts the dragged item. Otherwise, Target is the control that accepts the item. The OnEndDrag event also includes the x- and y-coordinates on the receiving control where the drop occurs.

In this example, a file list box handles an end-drag event by refreshing its file list, assuming that dragging a file from the list changes the contents of the current directory:

void __fastcallTFMForm::FileList1EndDrag(TObject *Sender, TObject *Target,   int X, int Y)

  if (Target)

    FileList1->Update();

};


Customizing drag and drop with a drag object

Topic groups	See also

You can use a TDragObject descendant to customize your object’s drag and drop behavior. By default, the drag-over and drag-drop events indicate the source of the dragged item and the coordinates of the mouse cursor over the accepting control. You can get additional state information by deriving a custom drag object from TDragObject and overriding its virtual methods as needed. By using a descendant of TDragObject, the source of the drag is the drag object itself; not the control as when using the TDragControl object.

Create the custom drag object in the OnStartDrag event. Use the public IsDragObject function within a target’s OnDragOver event when accepting a drag drop.

TDragObject allows more flexible drag and drop handling. Normally, the source parameter of the OnDragOver and OnDragDrop events is the control that starts the drag operation. If multiple controls of differing kinds need to start a drag of the same kind of data (e.g. a filename, text, a dollar amount, etc.), the source would need support for each kind of control. With a drag object, the target need know only how to handle a drag object as a source because each type of source control can create the same kind of drag object in its OnStartDrag event. The OnDragOver and OnDragDrop events can tell if the source is a drag object, as opposed to the control, by calling IsDragObject.

Drag objects can be dragged between multiple .DLLs as well as inside the main .EXE. This is useful if you are not using packages but still want drag operations to function from forms implemented in .EXEs to forms implemented in .DLLs.


Changing the drag mouse pointer

Topic groups	See also

You can change the look of the drag mouse pointer that C++Builder uses during a drag operation. To do this, set the component’s DragCursor property at design time. You can also create your cursor resource.


Implementing drag-and-dock in controls

Topic groups	See also

TControl and TWinControl allow you to implement docking support for your application controls. Descendants of TWinControl can act as docking sites. Descendants of TControl can act as child windows that are docked into docking sites. For example, to provide a docking site at the left edge of a form window, align a panel to the left edge of the form and make the panel a docking site. When dockable controls are dragged to the panel and released, they become child controls of the panel (client-aligned).

The elements of drag-and-dock operation:

Making a windowed control a docking site

Making a control a dockable child control

Controlling how child controls are docked in a docking site

Controlling how child controls are undocked in a docking site

Controlling how child controls respond to drag-and-dock operations


Making a windowed control a docking site

Topic groups	See also

To make a windowed control a docking site:

1	Set the DockSite property to true.

2	If the dock site object should not appear except when it contains a docked client, set its AutoSize property to true. When AutoSize is true, the dock site is sized to 0 until it accepts a child control for docking. Then it resizes to fit around the child control.


Making a control a dockable child control

Topic groups	See also

To make a control a dockable child control:

1	Set its DragKind property to dkDock. When DragKind is dkDock, dragging the control moves the control to a new docking site or undocks the control so that it becomes a floating window. When DragKind is dkDrag (the default), dragging the control starts a drag-and-drop operation which must be implemented using the OnDragOver, OnEndDrag, and OnDragDrop events.

2	Set its DragMode to dmAutomatic. When DragMode is dmAutomatic, dragging (for drag-and-drop or docking, depending on DragKind) is initiated automatically when the user starts dragging the control with the mouse. When DragMode is dmManual, you can still begin a drag-and-dock (or drag-and-drop) operation by calling the BeginDrag method.

3	Set its FloatingDockSiteClass property to indicate the TWinControl descendant that should host the control when it is undocked and left as a floating window. When the control is released and not over a docking site, a windowed control of this class is created dynamically, and becomes the parent of the dockable child. If the dockable child control is a descendant of TWinControl, it is not necessary to create a separate floating dock site to host the control, although you may want to specify a form in order to get a border and title bar. To omit a dynamic container window, set FloatingDockSiteClass to the same class as the control, and it will become a floating window with no parent.


Controlling how child controls are docked in a docking site

Topic groups	See also

A docking site automatically accepts child controls when they are released over the docking site. For most controls, the first child is docked to fill the client area, the second splits that into separate regions, and so on. Page controls dock children into new tab sheets (or merge in the tab sheets if the child is another page control).

Three events allow docking sites to further constrain how child controls are docked:

__property TGetSiteInfoEvent OnGetSiteInfo = {read=FOnGetSiteInfo, write=FOnGetSiteInfo};

typedef void __fastcall(__closure *TGetSiteInfoEvent)(System::TObject* Sender, TControl* DockClient, Windows::TRect &InfluenceRect, const Windows::TPoint &MousePos, bool &CanDock);

OnGetSiteInfo occurs on the docking site when the user drags a dockable child over the control. It allows the site to indicate whether it will accept the control specified by the DockClient parameter as a child, and if so, where the child must be to be considered for docking. When OnGetSiteInfo occurs, InfluenceRect is initialized to the screen coordinates of the docking site, and CanDock is intialized to true. A more limited docking region can be created by changing InfluenceRect and the child can be rejected by setting CanDock to false.

__property TDockOverEvent OnDockOver = {read=FOnDockOver, write=FOnDockOver};

typedef void __fastcall(__closure *TDockOverEvent)(System::TObject* Sender, TDragDockObject* Source, int X, int Y, TDragState State, bool &Accept);

OnDockOver occurs on the docking site when the user drags a dockable child over the control. It is analogous to the OnDragOver event in a drag-and-drop operation. Use it to signal that the child can be released for docking, by setting the Accept parameter. If the dockable control is rejected by the OnGetSiteInfo event handler (perhaps because it is the wrong type of control), OnDockOver does not occur.

__property TDockDropEvent OnDockDrop = {read=FOnDockDrop, write=FOnDockDrop};

typedef void __fastcall(__closure *TDockDropEvent)(System::TObject* Sender, TDragDockObject* Source, int X, int Y);

OnDockDrop occurs on the docking site when the user releases the dockable child over the control. It is analogous to the OnDragDrop event in a normal drag-and-drop operation. Use this event to perform any necessary accommodations to accepting the control as a child control. Access to the child control can be obtained using the Control property of the TDockObject specified by the Source parameter.


Controlling how child controls are undocked in a docking site

Topic groups	See also

A docking site automatically allows child controls to be undocked when they are dragged and have a DragMode property of dmAutomatic. Docking sites can respond when child controls are dragged off, and even prevent the undocking, in an OnUnDock event handler:

__property TUnDockEvent OnUnDock = {read=FOnUnDock, write=FOnUnDock};

typedef void __fastcall(__closure *TUnDockEvent)(System::TObject* Sender, TControl* Client, TWinControl* NewTarget, bool &Allow);

The Client parameter indicates the child control that is trying to undock, and the Allow parameter lets the docking site (Sender) reject the undocking. When implementing an OnUnDock event handler, it can be useful to know what other children (if any) are currently docked. This information is available in the read-only DockClients property, which is an indexed array of TControl. The number of dock clients is given by the read-only DockClientCount property.


Controlling how child controls respond to drag-and-dock operations

Topic groups	See also

Dockable child controls have two events that occur during drag-and-dock operations.

__property TStartDockEvent OnStartDock = {read=FOnStartDock, write=FOnStartDock};

typedef void __fastcall(__closure *TStartDockEvent)(System::TObject* Sender, TDragDockObject* &DragObject);

OnStartDock is analogous to the OnStartDrag event of a drag-and-drop operation. Similar to OnStartDrag, it allows the dockable child control to create a custom drag object.

__property TEndDragEvent OnEndDock = {read=FOnEndDock, write=FOnEndDock};

typedef void __fastcall(__closure *TEndDragEvent)(System::TObject* Sender, System::TObject* Target, int X, int Y);

OnEndDock is analogous to the OnEndDrag event of a drag-and-drop operation.


Working with text in controls

Topic groups

The VCL provides many methods and properties for you to easily manipulate text in a rich edit or memo component. The following topics explain how to add these features to a rich edit or memo component. Some features work with an edit component as well. The topics cover:

Setting text alignment

Adding scrollbars at runtime

Adding the Clipboard object

Selecting text

Selecting all text

Cutting, copying, and pasting text

Deleting selected text

Disabling menu items

Providing a pop-up menu

Handling the OnPopup event


Setting text alignment

Topic groups	See also

In a rich edit or memo component, users can align text to either the right or left margin or center the text between the two. Applications such as the rich text editor application (in the \EXAMPLES\APPS\RICHEDIT directory), use a check mark on the menu to indicate which option is in effect.

To set text alignment in an edit component, set the edit component’s Alignment property. Alignment takes effect only if the WordWrap property is true. If wordwrapping is turned off, there is no right margin to align to.

For example, the following code from the RichEdit example sets the alignment depending on which button was chosen:

   switch((int)RichEdit1->Paragraph->Alignment)

   { case 0: LeftAlign->Down   = true; break;

 case 1: RightAlign->Down  = true; break;

 case 2: CenterAlign->Down = true; break;

Note:	The simple TEdit object does not support alignment because Windows does not support it.


Adding scroll bars at runtime

Topic groups	See also

Rich edit and memocomponents can contain horizontal or vertical scroll bars, or both, as needed. When word-wrapping is enabled, the component needs only a vertical scroll bar. If the user turns off word-wrapping, the component might also need a horizontal scroll bar, since text is not limited by the right side of the editor.

To add scroll bars at runtime, do the following:

1	Determine whether the text might exceed the right margin.

In most cases, you check that the rich edit or memo component has wordwrapping enabled. You might also check whether any text lines actually exceed the width of the rich edit or memo component.

2	Set the rich edit or memo component’s ScrollBars property to include or exclude scroll bars.

The following example from the simple text editor example (EXAMPLES\DOC\TEXTEDIT) attaches an OnClick event handler to a Character|WordWrap menu item. In addition to toggling the Editor component’s WordWrap property, the OnClick event handler sets the ScrollBars property to a value appropriate to the current wordwrapping:

void __fastcallTEditForm::WordWrap1Click(TObject *Sender)

{

  Editor->WordWrap = !(Editor->WordWrap);   // toggle wordwrapping

  if (Editor->WordWrap)

    Editor->ScrollBars = ssVertical;        // wrapped requires only vertical

  else

    Editor->ScrollBars = ssBoth;            // unwrapped can need both

  WordWrap1->Checked = Editor->WordWrap;    // check menu item to match property

}

The rich edit and memo components handle their scroll bars in a slightly different way. The rich edit component can hide its scroll bars if the text fits inside the bounds of the component. The memo always shows scroll bars if they are enabled.


Adding the Clipboard object

Topic groups	See also

Most text handling applications provide users with a way to move selected text between documents, including documents in different applications. The Clipboard object in C++Builder encapsulates the Windows Clipboard and includes methods for cutting, copying, and pasting text (and other formats, including graphics). The Clipboard object is declared in the Clipbrd unit.

To add the Clipboard object to an application,

1	Select the unit that will use the Clipboard.

2	In the form’s .H file, add

#include <vcl\Clipbrd.hpp>


Selecting text

Topic groups	See also

Before you can send any text to the Clipboard, that text must be selected. Highlighting of selected text is built into the edit components. When the user selects text, it appears highlighted.

The table below lists properties commonly used to handle selected text.

Property	Description
SelText	Contains a string representing the selected text in the component.
SelLength	Contains the length of a selected string.
SelStart	Contains the starting position of a string.


Selecting all text

Topic groups

The SelectAll method selects the entire contents of the rich edit or memo component. This is especially useful when the component’s contents exceed the visible area of the component. In most other cases, users select text with either keystrokes or mouse dragging.

To select the entire contents of a rich edit or memo control, call the RichEdit1 control’s SelectAll method.

For example,

void __fastcallTMainForm::SelectAll(TObject *Sender)

{

  RichEdit1->SelectAll();     // select all text in RichEdit

}


Cutting, copying, and pasting text

Topic groups	See also

C++Builder applications that use the Clipbrd unit can cut, copy and paste text, graphics, and objects both internally and in other applications through the Windows Clipboard. The edit components that encapsulate the standard Windows text-handling controls all have methods built into them for interacting with the Clipboard.

To cut, copy, or paste text with the Clipboard, call the edit component’s CutToClipboard, CopyToClipboard, and PasteFromClipboard methods, respectively.

For example, the following code attaches event handlers to the OnClick events of the Edit|Cut, Edit|Copy, and Edit|Paste commands, respectively:

void __fastcallTMainForm::EditCutClick(TObject* /*Sender*/)

{    RichEdit1->CutToClipboard();

}

void __fastcallTMainForm::EditCopyClick(TObject* /*Sender*/)

{    RichEdit1->CopyToClipboard();

}

void __fastcall TMainForm::EditPasteClick(TObject* /*Sender*/)

{    RichEdit1->PasteFromClipboard();

}


Deleting selected text

Topic groups

Selected text is often used with the Clipboard, but you can also write code to delete the selected text in an edit component without cutting it to the Clipboard.

To delete the selected text from an edit component, call the editor’s ClearSelection method.

For example, if you have a Delete item on the Edit menu and a memo control named RichEdit1, your code would look something like this:

void __fastcallTMainForm::EditDeleteClick(TObject *Sender)

{

  RichEdit1->ClearSelection();

}


Disabling menu items

Topic groups	See also

Often in an application you want to disable menu commands that are not immediately applicable, but you do not want to remove the command from the menu altogether. For example, in a text editor, if there is no text currently selected, the Cut, Copy, and Delete items on the Edit menu should appear dimmed. Disabling the item lets the user know there is such a command, but that it does not currently apply.

An appropriate time to enable or disable items on a particular menu is when the user clicks the item at the top of the menu. That way, before displaying the items, your application can make the correct items available. (This event is also fired prior to evaluating menu shortcut keystrokes.)

To disable a menu item, set its Enabled property to false.

In the following code example, an event handler is attached to the OnClick event for the Edit item on a child form’s menu bar. It sets Enabled for the Cut, Copy, and Delete menu items on the Edit menu based on whether RichEdit1 has selected text. The Paste command is enabled or disabled based on whether any text exists on the Clipboard.

void __fastcallTMainForm::EditEditClick(TObject *Sender)

{

  // enable or disable the Paste menu item

  Paste1->Enabled = Clipboard()->HasFormat(CF_TEXT);

  bool HasSelection = (RichEdit1->SelLength > 0);  // true if text is selected

  Cut1->Enabled = HasSelection;  // enable menu items if HasSelection is true

  Copy1->Enabled = HasSelection;

  Delete1->Enabled = HasSelection;

}

The HasFormat method of the Clipboard returns a Boolean value based on whether the Clipboard contains objects, text, or images of a particular format. By calling HasFormat with the parameter CF_TEXT, you can determine whether the Clipboard contains any text, and enable or disable the Paste item as appropriate.


Providing a pop-up menu

Topic groups	See also

Pop-up, or local, menus are a common ease-of-use feature for any application. They enable users to minimize mouse movement by clicking the right mouse button in the application workspace to access a list of frequently used commands.

In a text editor application, for example, you can add a pop-up menu that repeats the Cut, Copy, and Paste editing commands. These pop-up menu items can use the same event handlers as the corresponding items on the Edit menu. You don’t need to create accelerator or shortcut keys for pop-up menus because the corresponding regular menu items generally already have shortcuts.

A form’s PopupMenu property specifies what pop-up menu to display when a user right-clicks any item on the form. Individual controls also have PopupMenu properties that can override the form’s property, allowing customized menus for particular controls.

To add a pop-up menu to a form,

1	Place a pop-up menu component on the form.

2	Use the Menu Designer to define the items for the pop-up menu.

3	Set the PopupMenu property of the form or control that displays the menu to the name of the pop-up menu component.

4	Attach handlers to the OnClick events of the pop-up menu items.


Handling the OnPopup event

Topic groups	See also

You may want to adjust pop-up menu items before displaying the menu, just as you may want to enable or disable items on a regular menu. With a regular menu, you can handle the OnClick event for the item at the top of the menu.

With a pop-up menu, however, there is no top-level menu bar, so to prepare the pop-up menu commands, you handle the event in the menu component itself. The pop-up menu component provides an event just for this purpose, called OnPopup.

To adjust menu items on a pop-up menu before displaying them,

1	Select the pop-up menu component.

2	Attach an event handler to its OnPopup event.

3	Write code in the event handler to enable, disable, hide, or show menu items.

In the following code, the EditEditClick event handler described previously in Disabling menu items is attached to the pop-up menu component’s OnPopup event. A line of code is added to EditEditClick for each item in the pop-up menu.

void __fastcallTMainForm::EditEditClick(TObject *Sender)

{

  // enable or disable the Paste menu item

  Paste1->Enabled = Clipboard()->HasFormat(CF_TEXT);

  Paste2->Enabled = Paste1->Enabled;            // add this line

  bool HasSelection = (RichEdit1->SelLength > 0);  // true if text is selected

  Cut1->Enabled = HasSelection;    // enable menu items if HasSelection is true

  Cut2->Enabled = HasSelection;    // add this line

  Copy1->Enabled = HasSelection;

  Copy2->Enabled = HasSelection;   // add this line

  Delete1->Enabled = HasSelection;

}


Adding graphics to controls

Topic groups	See also

Windows list-box, combo-box, and menu controls have a style available called “owner draw,” which means that instead of using Windows’ standard method of drawing text for each item in the control, the control’s owner (generally, the form) draws each item at runtime. The most common use for owner-draw controls is to provide graphics instead of, or in addition to, text for items. For information on using owner-draw to add images to menus, see .Adding images to menu items.

All owner-draw controls contain lists of items. By default, those lists are lists of strings, which Windows displays as text. You can associate an object with each item in a list to make it easy to use that object when drawing items.

In general, creating an owner-draw control in C++Builder involves these steps:

1	Setting the owner-draw style

2	Adding graphical objects to a string list

3	Drawing owner-drawn items


Setting the owner-draw style

Topic groups

Both list boxes and combo boxes have a property called Style. Style determines whether the control uses the default drawing (called the “standard” style) or owner drawing. Grids use a property called DefaultDrawing to enable or disable the default drawing.

List boxes and combo boxes have additional owner-draw styles, called fixed and variable, as the following tabledescribes. Owner-draw grids are always fixed: although the size of each row and column might vary, the size of each cell is determined before drawing the grid.

Owner-draw style	Meaning	Examples
Fixed	Each item is the same height, with that height determined by the ItemHeight property.	lbOwnerDrawFixed, csOwnerDrawFixed
Variable	Each item might have a different height, determined by the data at runtime.	lbOwnerDrawVariable, csOwnerDrawVariable


Adding graphical objects to a string list

Topic groups	See also

Every C++Builder string list has the ability to hold a list of objects in addition to its list of strings.

For example, in a file manager application, you may want to add bitmaps indicating the type of drive along with the letter of the drive. To do that, you need to add the bitmap images to the application, then copy those images into the proper places in the string list as described in the following sections.


Adding images to an application

Topic groups	See also

An image control is a nonvisual control that contains a graphical image, such as a bitmap. You use image controls to display graphical images on a form. You can also use them to hold hidden images that you’ll use in your application. For example, you can store bitmaps for owner-draw controls in hidden image controls, like this:

1	Add image controls to the main form.

2	Set their Name properties.

3	Set the Visible property for each image control to false.

4	Set the Picture property of each image to the desired bitmap using the Picture editor from the Object Inspector.

The image controls are invisible when you run the application.


Adding images to a string list

Topic groups	See also

Once you have graphical images in an application, you can associate them with the strings in a string list. You can either add the objects at the same time as the strings, or associate objects with existing strings. The preferred method is to add objects and strings at the same time, if all the needed data is available.

The following example shows how you might want to add images to a string list. This is part of a file manager application where, along with a letter for each valid drive, it adds a bitmap indicating each drive’s type. The OnCreate event handler looks like this:

void __fastcallTFMForm::FormCreate(TObject *Sender)

{

  int AddedIndex;

  char DriveName[4] = "A:\";

  for (char Drive = 'A'; Drive <= 'Z'; Drive++) // try all possible drives

  {

    DriveName[0] = Drive;

    switch(GetDriveType(DriveName))

    {

      case DRIVE_REMOVABLE:	// add a list item

        DriveName[1] = '\0'; // temporarily make drive letter into string

        AddedIndex = DriveList->Items->AddObject(DriveName,

           Floppy->Picture->Graphic);

        DriveName[1] = ':' // replace the colon

        break;

      case DRIVE_FIXED:	// add a list item

        DriveName[1] = '\0'; // temporarily make drive letter into string

        AddedIndex = DriveList->Items->AddObject(DriveName,

           Fixed->Picture->Graphic);

        DriveName[1] = ':' // replace the colon

        break;

      case DRIVE_REMOTE:	// add a list item

        DriveName[1] = '\0'; // temporarily make drive letter into string

        AddedIndex = DriveList->Items->AddObject(DriveName,

           Network->Picture->Graphic);

        DriveName[1] = ':' // replace the colon

        break;

    }

    if ((int)(Drive - 'A') == getdisk()) // current drive?

      DriveList->ItemIndex = AddedIndex; // then make that the current list item

  }

}


Drawing owner-drawn items

Topic groups

When you set a control’s style to owner draw, Windows no longer draws the control on the screen. Instead, it generates events for each visible item in the control. Your application handles the events to draw the items.

To draw the items in an owner-draw control, do the following for each visible item in the control. Use a single event handler for all items.

1	Size the item, if needed.

Items of the same size (for example, with a list box style of lsOwnerDrawFixed), do not require sizing.

2	Draw the item.


Sizing owner-draw items

Topic groups

Before giving your application the chance to draw each item in a variable owner-draw control, Windows generates a measure-item event. The measure-item event tells the application where the item appears on the control.

Windows determines the size the item (generally, it is just large enough to display the item’s text in the current font). Your application can handle the event and change the rectangle Windows chose. For example, if you plan to substitute a bitmap for the item’s text, change the rectangle to be the size of the bitmap. If you want a bitmap and text, adjust the rectangle to be big enough for both.

To change the size of an owner-draw item, attach an event handler to the measure-item event in the owner-draw control. Depending on the control, the name of the event can vary. List boxes and combo boxes use OnMeasureItem. Grids have no measure-item event.

The sizing event has two important parameters: the index number of the item and the size of that item. The size is variable: the application can make it either smaller or larger. The positions of subsequent items depend on the size of preceding items.

For example, in a variable owner-draw list box, if the application sets the height of the first item to five pixels, the second item starts at the sixth pixel down from the top, and so on. In list boxes and combo boxes, the only aspect of the item the application can alter is the height of the item. The width of the item is always the width of the control.

Note:	Owner-draw grids cannot change the sizes of their cells as they draw. The size of each row and column is set before drawing by the ColWidths and RowHeights properties.

The following code, attached to the OnMeasureItem event of an owner-draw list box, increases the height of each list item to accommodate its associated bitmap:

void __fastcall TForm1::ListBox1MeasureItem(TWinControl *Control, int Index,

  int&Height)      // note that Height is passed by reference

{

  int BitmapHeight = ((TBitmap *)ListBox1->Items->Objects[Index])->Height + 2;

  // make sure list item has enough room for bitmap (plus 2)

  if (BitmapHeight > Height)

    Height = BitmapHeight;

}

Note:	You must typecast the items from the Objects property in the string list. Objects is a property of type TObject so that it can hold any kind of object. When you retrieve objects from the array, you need to typecast them back to the actual type of the items.


Drawing each owner-draw item

Topic groups

When an application needs to draw or redraw an owner-draw control, Windows generates draw-item events for each visible item in the control.

To draw each item in an owner-draw control, attach an event handler to the draw-item event for that control.

The names of events for owner drawing always start with OnDraw, such as OnDrawItem or OnDrawCell.

The draw-item event contains parameters indicating the index of the item to draw, the rectangle in which to draw, and usually some information about the state of the item (such as whether the item has focus). The application handles each event by rendering the appropriate item in the given rectangle.

For example, the following code shows how to draw items in a list box that has bitmaps associated with each string. It attaches this handler to the OnDrawItem event for the list box:

void __fastcall TForm1::ListBox1DrawItem(TWinControl *Control, int Index,

  TRect &Rect, TOwnerDrawState State)

  TBitmap *Bitmap = (TBitmap *)ListBox1->Items->Objects[Index];

  ListBox1->Canvas->Draw(R.Left, R.Top + 2, Bitmap); // draw the bitmap

  ListBox1->Canvas->TextOut(R.Left + Bitmap->Width + 2, R.Top + 2,

    ListBox1->Items->Strings[Index]);        // and write the text to its right

}


Working with graphics and multimedia

Topic groups

Graphics and multimedia elements can add polish to your applications. C++Builder offers a variety of ways to introduce these features into your application. To add graphical elements, you can insert pre-drawn pictures at design time, create them using graphical controls at design time, or draw them dynamically at runtime. To add multimedia capabilities, C++Builder includes special components that can play audio and video clips.

This following topics describe how to enhance your applications by introducing graphics or multimedia elements:

Overview of graphics programming

Working with multimedia


Overview of graphics programming

Topic groups	See also

The VCL graphics components encapsulate the Windows Graphics Device Interface (GDI), making it very easy to add graphics to your Windows programming.

To draw graphics in a C++Builder application, you draw on an object’s canvas, rather than directly on the object. The canvas is a property of the object, and is itself an object. A main advantage of the canvas object is that it handles resources effectively and it takes care of device context, so your programs can use the same methods regardless of whether you are drawing on the screen, to a printer, or on bitmaps or metafiles. Canvases are available only at runtime, so you do all your work with canvases by writing code.

Note:	Since TCanvas is a wrapper resource manager around the Windows device context, you can also use all Windows GDI functions on the canvas. The Handle property of the canvas is the device context Handle.

How graphic images appear in your application depends on the type of object whose canvas you draw on. If you are drawing directly onto the canvas of a control, the picture is displayed immediately. However, if you draw on an offscreen image such as a TBitmap canvas, the image is not displayed until a control copies from the bitmap onto the control’s canvas. That is, when drawing bitmaps and assigning them to an image control, the image appears only when the control has an opportunity to process its OnPaint message.

When working with graphics, you often encounter the terms drawing and painting:

Drawing is the creation of a single, specific graphic element, such as a line or a shape, with code. In your code, you tell an object to draw a specific graphic in a specific place on its canvas by calling a drawing method of the canvas.

Painting is the creation of the entire appearance of an object. Painting usually involves drawing. That is, in response to OnPaint events, an object generally draws some graphics. An edit box, for example, paints itself by drawing a rectangle and then drawing some text inside. A shape control, on the other hand, paints itself by drawing a single graphic.

The following topics describe how to use the VCL graphics components to simplify your coding.

Refreshing the screen

Types of graphic objects

Common properties and methods of canvases

Handling multiple drawing objects in an application

Drawing on a bitmap

Loading and saving graphics files

Using the Clipboard with graphics

Rubber banding example


Refreshing the screen

Topic groups	See also

At certain times, Windows determines that objects onscreen need to refresh their appearance, so it generates WM_PAINT messages, which the VCL routes to OnPaint events. The VCL calls any OnPaint event handler that you have written for that object when you use the Refresh method. The default name generated for the OnPaint event handler in a form is FormPaint. You may want to use the Refresh method at times to refresh a component or form. For example, you might call Refresh in the form’s OnResize event handler to redisplay any graphics or if you want to paint a background on a form.

While some operating systems automatically handle the redrawing of the client area of a window that has been invalidated, Windows does not. In the Windows operating system anything drawn on the screen is permanent. When a form or control is temporarily obscured, for example during window dragging, the form or control must repaint the obscured area when it is re-exposed. For more information about the WM_PAINT message, see the Windows online Help.

If you use the TImage control, the painting and refreshing of the graphic contained in the TImage is handled automatically by the VCL. Drawing on a TImage creates a persistent image. Consequently, you do not need to do anything to redraw the contained image. In contrast, TPaintBox’s canvas maps directly onto the screen device, so that anything drawn to the PaintBox’s canvas is transitory. This is true of nearly all controls, including the form itself. Therefore, if you draw or paint on a TPaintBox in its constructor, you will need to add that code to your OnPaint event handler in order for image to be repainted each time the client area is invalidated.


Types of graphic objects

Topic groups	See also

The VCL provides the following graphic objects. These objects have methods to draw on the canvas, which are described in Using Canvas methods to draw graphic objects and to load and save to graphics files, as described in Loading and saving graphics files

Object	Description
Picture	Used to hold any graphic image. To add additional graphic file formats, use the Picture Register method. Use this to handle arbitrary files such as displaying images in an image control.
Bitmap	A powerful graphics object used to create, manipulate (scale, scroll, rotate, and paint), and store images as files on a disk. Creating copies of a bitmap is fast since the handle is copied, not the image.
Clipboard	Represents the container for any text or graphics that are cut, copied, or pasted from or to an application. With the clipboard, you can get and retrieve data according to the appropriate format; handle reference counting, and opening and closing the Clipboard; manage and manipulate formats for objects in the Clipboard.
Icon	Represents the value loaded from a Windows icon file (::ICO file).
Metafile	Contains a metafile, which records the operations required to construct an image, rather than contain the actual bitmap pixels of the image. Metafiles are extremely scalable without the loss of image detail and often require much less memory than bitmaps, particularly for high-resolution devices, such as printers. However, metafiles do not draw as fast as bitmaps. Use a metafile when versatility or precision is more important than performance.


Common Properties and Methods of Canvas

Topic groups	See also

The following table lists the commonly used properties of the Canvas object.

Properties	Descriptions
Font	Specifies the font to use when writing text on the image. Set the properties of the TFont object to specify the font face, color, size, and style of the font.
Brush	Determines the color and pattern the canvas uses for filling graphical shapes and backgrounds. Set the properties of the TBrush object to specify the color and pattern or bitmap to use when filling in spaces on the canvas.
Pen	Specifies the kind of pen the canvas uses for drawing lines and outlining shapes. Set the properties of the TPen object to specify the color, style, width, and mode of the pen.
PenPos	Specifies the current drawing position of the pen.
Pixels	Specifies the color of the area of pixels within the current ClipRect.
These properties are described in more detail in Using the properties of the Canvas object.

Here is a list of several methods you can use:

Method	Descriptions
Arc	Draws an arc on the image along the perimeter of the ellipse bounded by the specified rectangle.
Chord	Draws a closed figure represented by the intersection of a line and an ellipse.
CopyRect	Copies part of an image from another canvas into the canvas.
Draw	Renders the graphic object specified by the Graphic parameter on the canvas at the location given by the coordinates (X, Y).
Ellipse	Draws the ellipse defined by a bounding rectangle on the canvas.
FillRect	Fills the specified rectangle on the canvas using the current brush.
FloodFill	Fills an area of the canvas using the current brush.
FrameRect	Draws a rectangle using the Brush of the canvas to draw the border.
LineTo	Draws a line on the canvas from PenPos to the point specified by X and Y, and sets the pen position to (X, Y).
MoveTo	Changes the current drawing position to the point (X,Y).
Pie	Draws a pie-shaped the section of the ellipse bounded by the rectangle (X1, Y1) and (X2, Y2) on the canvas.
Polygon	Draws a series of lines on the canvas connecting the points passed in and closing the shape by drawing a line from the last point to the first point.
PolyLine	Draws a series of lines on the canvas with the current pen, connecting each of the points passed to it in Points.
Rectangle	Draws a rectangle on the canvas with its upper left corner at the point (X1, Y1) and its lower right corner at the point (X2, Y2). Use Rectangle to draw a box using Pen and fill it using Brush.
RoundRect	Draws a rectangle with rounded corners on the canvas.
StretchDraw	Draws a graphic on the canvas so that the image fits in the specified rectangle. The graphic image may need to change its magnitude or aspect ratio to fit.
TextHeight, TextWidth	Returns the height and width, respectively, of a string in the current font. Height includes leading between lines.
TextOut	Writes a string on the canvas, starting at the point (X,Y), and then updates the PenPos to the end of the string.
TextRect	Writes a string inside a region; any portions of the string that fall outside the region do not appear.
These methods are described in more detail in Using Canvas methods to draw graphic objects.


Using the properties of the Canvas object

Topic groups	See also

With the Canvas object, you can set the properties of a pen for drawing lines, a brush for filling shapes, a font for writing text, and an array of pixels to represent the image.

This section describes

Using pens

Using brushes

Reading and setting pixels


Using pens

Topic groups	See also

The Pen propertyof a canvas controls the way lines appear, including lines drawn as the outlines of shapes. Drawing a straight line is really just changing a group of pixels that lie between two points.

The pen itself has four properties you can change: Color, Width, Style, and Mode.

Color property: Changes the pen color

Width property: Changes the pen width

Style property: Changes the pen style

Mode property: Changes the pen mode

The values of these properties determine how the pen changes the pixels in the line. By default, every pen starts out black, with a width of 1 pixel, a solid style, and a mode called copy that overwrites anything already on the canvas.


Changing the pen color

Topic groups	See also

You can set the color of a pen as you would any other Color property at runtime. A pen’s color determines the color of the lines the pen draws, including lines drawn as the boundaries of shapes, as well as other lines and polylines. To change the pen color, assign a value to the Color property of the pen.

To let the user choose a new color for the pen, put a color grid on the pen’s toolbar. A color grid can set both foreground and background colors. For a non-grid pen style, you must consider the background color, which is drawn in the gaps between line segments. Background color comes from the Brush color property.

Since the user chooses a new color by clicking the grid, this code changes the pen’s color in response to the OnClick event:

void __fastcallTForm1::PenColorClick(TObject *Sender)

{

  Canvas->Pen->Color = PenColor->ForegroundColor;

}


Changing the pen width

Topic groups	See also

A pen’s width determines the thickness, in pixels, of the lines it draws.

Note:	When the thickness is greater than 1, Windows 95 always draw solid lines, no matter what the value of the pen’s Style property.

To change the pen width, assign a numeric value to the pen’s Width property.

Suppose you have a scroll bar on the pen’s toolbar to set width values for the pen. And suppose you want to update the label next to the scroll bar to provide feedback to the user. Using the scroll bar’s position to determine the pen width, you update the pen width every time the position changes.

This is how to handle the scroll bar’s OnChange event:

void __fastcallTForm1::PenWidthChange(TObject *Sender)

{

  Canvas->Pen->Width = PenWidth->Position;         // set the pen width directly

  PenSize->Caption = IntToStr(PenWidth->Position); // convert to string

}


Changing the pen style

Topic groups	See also

A pen’s Style property allows you to set solid lines, dashed lines, dotted lines, and so on.

Note:	Windows 95 does not support dashed or dotted line styles for pens wider than one pixel and makes all larger pens solid, no matter what style you specify.

The task of setting the properties of pen is an ideal case for having different controls share same event handler to handle events. To determine which control actually got the event, you check the Sender parameter.

To create one click-event handler for six pen-style buttons on a pen’s toolbar, do the following:

1	Select all six pen-style buttons and select the Object Inspector|Events|OnClick event and in the Handler column, type SetPenStyle.

C++Builder generates an empty click-event handler called SetPenStyle and attaches it to the OnClick events of all six buttons.

2	Fill in the click-event handler by setting the pen’s style depending on the value of Sender, which is the control that sent the click event:

void __fastcallTForm1::SetPenStyle(TObject *Sender)

{

  if (Sender == SolidPen)

    Canvas->Pen->Style = psSolid;

  else if (Sender == DashPen)

    Canvas->Pen->Style = psDash;

  else if (Sender == DotPen)

    Canvas->Pen->Style = psDot;

  else if (Sender == DashDotPen)

    Canvas->Pen->Style = psDashDot;

  else if (Sender == DashDotDotPen)

    Canvas->Pen->Style = psDashDotDot;

‘  else if (Sender == ClearPen)

    Canvas->Pen->Style = psClear;

}

The above event handler code could be further reduced by putting the pen style constants into the Tag properties of the pen style buttons. Then this event code would be something like:

void __fastcallTForm1::SetPenStyle(TObject *Sender)

{

  if (Sender->InheritsFrom (__classid(TSpeedButton))

    Canvas->Pen->Style = (TPenStyle) ((TSpeedButton *)Sender)->Tag;

}


Changing the pen mode

Topic groups	See also

A pen’s Mode property lets you specify various ways to combine the pen’s color with the color on the canvas. For example, the pen could always be black, be an inverse of the canvas background color, inverse of the pen color, and so on.


Getting the pen position

Topic groups	See also

The current drawing position—the position from which the pen begins drawing its next line—is called the pen position. The canvas stores its pen position in its PenPos property. Pen position affects the drawing of lines only; for shapes and text, you specify all the coordinates you need.

To set the pen position, call the MoveTo method of the canvas. For example, the following code moves the pen position to the upper left corner of the canvas:

Canvas->MoveTo(0, 0);

Note:	Drawing a line with the LineTo method also moves the current position to the endpoint of the line.


Using brushes

Topic groups	See also

The Brush property of a canvas controls the way you fill areas, including the interior of shapes. Filling an area with a brush is a way of changing a large number of adjacent pixels in a specified way.

The brush has three properties you can manipulate:

Color property: Changes the fill color

Style property: Changes the brush style

Bitmap property: Uses a bitmap as a brush pattern

The values of these properties determine the way the canvas fills shapes or other areas. By default, every brush starts out white, with a solid style and no pattern bitmap.


Changing the brush color

Topic groups	See also

A brush’s color determines what color the canvas uses to fill shapes. To change the fill color, assign a value to the brush’s Color property. Brush is used for background color in text and line drawing so you typically set the background color property.

You can set the brush color just as you do the pen color, in response to a click on a color grid on the brush’s toolbar :

void __fastcallTForm1::BrushColorClick(TObject *Sender)

{

  Canvas->Brush->Color = BrushColor->BackgroundColor;

}


Changing the brush style

Topic groups	See also

A brush style determines what pattern the canvas uses to fill shapes. It lets you specify various ways to combine the brush’s color with any colors already on the canvas. The predefined styles include solid color, no color, and various line and hatch patterns.

To change the style of a brush, set its Style property to one of the predefined values: bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, or bsDiagCross.

This example sets brush styles by sharing a click-event handler for a set of eight brush-style buttons. All eight buttons are selected, the Object Inspector|Events|OnClick is set, and the OnClick handler is named SetBrushStyle. Here is the handler code:

void __fastcallTForm1::SetBrushStyle(TObject *Sender)

{

  if (Sender == SolidBrush)

    Canvas->Brush->Style = bsSolid;

  else if (Sender == ClearBrush)

    Canvas->Brush->Style = bsClear;

  else if (Sender == HorizontalBrush)

    Canvas->Brush->Style = bsHorizontal;

  else if (Sender == VerticalBrush)

    Canvas->Brush->Style = bsVertical;

  else if (Sender == FDiagonalBrush)

    Canvas->Brush->Style = bsFDiagonal;

  else if (Sender == BDiagonalBrush)

    Canvas->Brush->Style = bsBDiagonal;

  else if (Sender == CrossBrush)

    Canvas->Brush->Style = bsCross;

  else if (Sender == DiagCrossBrush)

    Canvas->Brush->Style = bsDiagCross;

}

The above event handler code could be further reduced by putting the brush style constants into the Tag properties of the brush style buttons. Then this event code would be something like:

void __fastcallTForm1::SetBrushStyle(TObject *Sender)

{

   if (Sender->InheritsFrom (__classid(TSpeedButton))

    Canvas->Brush>Style = (TBrushStyle) ((TSpeedButton *)Sender)->Tag;

}


Setting the Brush Bitmap property

Topic groups	See also

A brush’s Bitmap property lets you specify a bitmap image for the brush to use as a pattern for filling shapes and other areas.

The following example loads a bitmap from a file and assigns it to the Brush of the Canvas of Form1:

BrushBmp->LoadFromFile("MyBitmap.bmp");

  Form1->Canvas->Brush->Bitmap = BrushBmp;

  Form1->Canvas->FillRect(Rect(0,0,100,100));

Note:	The brush does not assume ownership of a bitmap object assigned to its Bitmap property. You must ensure that the Bitmap object remain valid for the lifetime of the Brush, and you must free the Bitmap object yourself afterwards.


Reading and setting pixels

Topic groups	See also

You will notice that every canvas has an indexedPixels property that represents the individual colored points that make up the image on the canvas. You rarely need to access Pixels directly, it is available only for convenience to perform small actions such as finding or setting a pixel’s color.

Note:	Setting and getting individual pixels is thousands of times slower than performing graphics operations on regions. Do not use the Pixel array property to access the image pixels of a general array. For high-performance access to image pixels, see the TBitmap.ScanLine property.


Using Canvas methods to draw graphic objects

Topic groups	See also

This section shows how to use some common methods to draw graphic objects. It covers:

Drawing lines and polylines

Drawing shapes

Drawing rounded rectangles

Drawing polygons


Drawing lines and polylines

Topic groups	See also

A canvas can draw straight lines and polylines. A straight line is just a line of pixels connecting two points. A polyline is a series of straight lines, connected end-to-end. The canvas draws all lines using its pen.


Drawing lines

Topic groups	See also

To draw a straight line on a canvas, use the LineTo method of the canvas.

LineTo draws a line from the current pen position to the point you specify and makes the endpoint of the line the current position. The canvas draws the line using its pen.

For example, the following method draws crossed diagonal lines across a form whenever the form is painted:

void __fastcallTForm1::FormPaint(TObject *Sender)

{

  Canvas->MoveTo(0,0);

  Canvas->LineTo(ClientWidth, ClientHeight);

  Canvas->MoveTo(0, ClientHeight);

  Canvas->LineTo(ClientWidth, 0);

}


Drawing polylines

Topic groups	See also	Example

In addition to individual lines, the canvas can also draw polylines, which are groups of any number of connected line segments.

To draw a polyline on a canvas, call the Polyline method of the canvas.

The parameter passed to the PolyLine method is an array of points. You can think of a polyline as performing a MoveTo on the first point and LineTo on each successive point. For drawing multiple lines, Polyline is faster than using the MoveTo methodand theLineTo method because it eliminates a lot of call overhead.


Example: Drawing polylines

The following method draws a rhombus in a form:

void __fastcall TForm1::FormPaint(TObject *Sender)

{

  POINT vertices[5];

  vertices[0] = Point(0, 0);

  vertices[1] = Point(50, 0);

  vertices[2] = Point(75, 50);

  vertices[3] = Point(25, 50);

  vertices[4] = Point(0, 0);

  Canvas->Polyline(vertices, 4);

}

Note that the last parameter to Polyline is the index of the last point, not the number of points.


Drawing shapes

Topic groups	See also

Canvases have methods for drawing different kinds of shapes. The canvas draws the outline of a shape with its pen, then fills the interior with its brush. The line that forms the border for the shape is controlled by the current Pen object.

This section covers:

Drawing rectangles and ellipses

Drawing rounded rectangles

Drawing polygons


Drawing rectangles and ellipses

Topic groups	See also	Example

To draw a rectangle or ellipse on a canvas, call the canvas’s Rectangle method or Ellipse method, passing the coordinates of a bounding rectangle.

The Rectangle method draws the bounding rectangle; Ellipse draws an ellipse that touches all sides of the rectangle.


Example: Drawing rectangles and ellipses

The following methoddraws a rectangle filling a form’s upper left quadrant, then draws an ellipse in the same area:

void __fastcallTForm1::FormPaint(TObject *Sender)

{

  Canvas->Rectangle(0, 0, ClientWidth/2, ClientHeight/2);

  Canvas->Ellipse(0, 0, ClientWidth/2, ClientHeight/2);

}


Drawing rounded rectangles

Topic groups	See also	Example

To draw a rounded rectangle on a canvas, call the canvas’s RoundRect method.

The first four parameters passed to RoundRect are a bounding rectangle, just as for theRectangle method or theEllipse method. RoundRect takes two more parameters that indicate how to draw the rounded corners.


Example: Drawing rounded rectangles

The following method draws a rounded rectangle in a form’s upper left quadrant, rounding the corners as sections of a circle with a diameter of 10 pixels:

void __fastcallTForm1::FormPaint(TObject *Sender)

{

  Canvas->RoundRect(0, 0, ClientWidth/2, ClientHeight/2, 10, 10);

}


Drawing polygons

Topic groups	See also

To draw a polygon with any number of sides on a canvas, call the Polygon method of the canvas.

Polygon takes an array of points as its only parameter and connects the points with the pen, then connects the last point to the first to close the polygon. After drawing the lines, Polygon uses the brush to fill the area inside the polygon.


Example: Drawing polygons

The following code draws a right triangle in the lower left half of a form:

void __fastcallTForm1::FormPaint(TObject *Sender)

{

  POINT vertices[3];

  vertices[0] = Point(0, 0);

  vertices[1] = Point(0, ClientHeight);

  vertices[2] = Point(ClientWidth,ClientHeight);

  Canvas->Polygon(vertices,2);

}


Handling multiple drawing objects in your application

Topic groups	See also

Various drawing methods (rectangle, shape, line, and so on) are typically available on the toolbar and button panel. Applications can respond to clicks on speed buttons to set the desired drawing objects. This section describes how to:

Keep track of which drawing tool to use

Changing the tool with speed buttons

Using drawing tools


Keeping track of which drawing tool to use

Topic groups	See also

A graphics program needs to keep track of what kind of drawing tool (such as a line, rectangle, ellipse, or rounded rectangle) a user might want to use at any given time. Typically, you would use the C++ enumerated type to list the available tools. Since an enumerated type is also a type declaration, you can use C++’s type-checking to ensure that you assign only those specific values.

For example, the following code declares an enumerated type for each drawing tool available in a graphics application:

enum TDrawingTool {dtLine, dtRectangle, dtEllipse, dtRoundRect};

A variable of type TDrawingTool can be assigned only one of the constants dtLine, dtRectangle, dtEllipse, or dtRoundRect.

By convention, type identifiers begin with the letter T, and groups of similar constants (such as those making up an enumerated type) begin with a 2-letter prefix (such as dt for “drawing tool”).

In the following code, a field added to a form keeps track of the form’s drawing tool:

enum TDrawingTool {dtLine, dtRectangle, dtEllipse, dtRoundRect};

class TForm1 : public TForm

{

__published:  // IDE-managed Components

  void __fastcallFormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y);

  void __fastcall FormMouseMove(TObject *Sender, TShiftState Shift, int X,

  int Y);

  void __fastcall FormMouseUp(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y);

private:	// User declarations

public:	// User declarations

  __fastcallTForm1(TComponent* Owner);

  bool Drawing;  //field to track whether button was pressed
  POINT Origin, MovePt;  // fields to store points

  TDrawingTool DrawingTool;  // field to hold current tool

};


Changing the tool with speed buttons

Topic groups	See also

Each drawing tool needs an associated OnClick event handler. Suppose your application had a toolbar button for each of four drawing tools: line, rectangle, ellipse, and rounded rectangle. You would attach the following event handlers to the OnClick events of the four drawing-tool buttons, setting DrawingTool to the appropriate value for each:

void __fastcallTForm1::LineButtonClick(TObject *Sender)  // LineButton

{

  DrawingTool = dtLine;

}

void __fastcallTForm1::RectangleButtonClick(TObject *Sender) // RectangleButton

{

  DrawingTool = dtRectangle;

}

void __fastcallTForm1::EllipseButtonClick(TObject *Sender)  // EllipseButton

{

  DrawingTool = dtEllipse;

}

void __fastcallTForm1::RoundedRectButtonClick(TObject *Sender) // RoundRectBtn

{

  DrawingTool = dtRoundRect;

}


Using drawing tools

Topic groups	See also

Now that you can tell what tool to use, you must indicate how to draw the different shapes. The only methods that perform any drawing are the mouse-move and mouse-up handlers, and the only drawing code draws lines, no matter what tool is selected.

To use different drawing tools, your code needs to specify how to draw, based on the selected tool. You add this instruction to each tool’s event handler.

This section describes

Drawing shapes

Sharing code among event handlers


Drawing shapes

Topic groups	See also

Drawing shapes is just as easy as drawing lines: Each one takes a single statement; you just need the coordinates.

Here’s a rewrite of the OnMouseUp event handler that draws shapes for all four tools:

void __fastcallTForm1::FormMouseUp(TObject *Sender)

{

  switch (DrawingTool)

  {

    case dtLine:

      Canvas->MoveTo(Origin.x, Origin.y);

      Canvas->LineTo(X, Y);

      break;

    casedtRectangle:

      Canvas->Rectangle(Origin.x, Origin.y, X, Y);

      break;

    casedtEllipse:

      Canvas->Ellipse(Origin.x, Origin.y, X, Y);

      break;

    casedtRoundRect:

      Canvas->Rectangle(Origin.x, Origin.y, X, Y, (Origin.x - X)/2,

                        (Origin.y - Y)/2);

      break;

  }

  Drawing = false;

}

Of course, you also need to update the OnMouseMove handler to draw shapes:

void __fastcallTForm1::FormMouseMove(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Drawing)

  {

    Canvas->Pen->Mode = pmNotXor;        // use XOR mode to draw/erase

  switch (DrawingTool)

  {

    case dtLine:

      Canvas->MoveTo(Origin.x, Origin.y);

      Canvas->LineTo(MovePt.x, MovePt.y);

      Canvas->MoveTo(Origin.x, Origin.y);

      Canvas->LineTo(X, Y);

      break;

    casedtRectangle:

      Canvas->Rectangle(Origin.x, Origin.y, MovePt.x, MovePt.y);

      Canvas->Rectangle(Origin.x, Origin.y, X, Y);

      break;

    casedtEllipse:

      Canvas->Ellipse(Origin.x, Origin.y, MovePt.x, MovePt.y);

      Canvas->Ellipse(Origin.x, Origin.y, X, Y);

      break;

    casedtRoundRect:

      Canvas->Rectangle(Origin.x, Origin.y, MovePt.x, MovePt.y,

                        (Origin.x - MovePt.x)/2,(Origin.y - MovePt.y)/2);

      Canvas->Rectangle(Origin.x, Origin.y, X, Y,

                        (Origin.x - X)/2, (Origin.y - Y)/2);

      break;

  }

  MovePt = Point(X, Y);

  Canvas->Pen->Mode = pmCopy;

}

Typically, all the repetitious code that is in the above example would be in a separate routine. The next section shows all the shape-drawing code in a single routine that all mouse-event handlers can call.


Sharing code among event handlers

Topic groups	See also	Example

Any time you find that many your event handlers use the same code, you can make your application more efficient by moving the repeated code into a routine that all event handlers can share.

To add a method to a form,

1	Add the method declaration to the form object.

You can add the declaration in either the public or private parts at the end of the form object’s declaration. If the code is just sharing the details of handling some events, it’s probably safest to make the shared method private.

2	Write the method implementation in the .cpp file for the form’s unit.

The header for the method implementation must match the declaration exactly, with the same parameters in the same order.


Example: Sharing code among event handlers

The following code adds a method to the form called DrawShape and calls it from each of the handlers. First, the declaration of DrawShape is added to the form object’s declaration:

enum TDrawingTool {dtLine, dtRectangle, dtEllipse, dtRoundRect};

class TForm1 : public TForm

{

__published:  // IDE-managed Components

  void __fastcallFormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y);

  void __fastcall FormMouseMove(TObject *Sender, TShiftState Shift, int X,

  int Y);

  void __fastcall FormMouseUp(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y);

private:	// User declarations

  void __fastcallDrawShape(POINT TopLeft, POINT BottomRight, TPenMode AMode);

public:	// User declarations

  __fastcallTForm1(TComponent* Owner);

  bool Drawing;  //field to track whether button was pressed
  POINT Origin, MovePt;  // fields to store points

  TDrawingTool DrawingTool;  // field to hold current tool

};

Then, the implementation of DrawShape is written in the: .cpp file for the unit:

void __fastcallTForm1::DrawShape(POINT TopLeft, POINT BottomRight,

  TPenMode AMode)

{

  Canvas->Pen->Mode = AMode;

  switch (DrawingTool)

  {

    case dtLine:

      Canvas->MoveTo(TopLeft.x, TopLeft.y);

      Canvas->LineTo(BottomRight.x, BottomRight.y);

      break;

    casedtRectangle:

      Canvas->Rectangle(TopLeft.x, TopLeft.y, BottomRight.x, BottomRight.y);

      break;

    casedtEllipse:

      Canvas->Ellipse(TopLeft.x, TopLeft.y, BottomRight.x, BottomRight.y);

      break;

    casedtRoundRect:

      Canvas->Rectangle(TopLeft.x, TopLeft.y, BottomRight.x, BottomRight.y,

                  (TopLeft.x - BottomRight.x)/2,(TopLeft.y - BottomRight.y)/2);

      break;

  }

}

The other event handlers are modified to call DrawShape.

void __fastcallTForm1::FormMouseUp(TObject *Sender)

{

  DrawShape(Origin, Point(X,Y), pmCopy); // draw the final shape

  Drawing = false;

}

void __fastcallTForm1::FormMouseMove(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Drawing)

  {

    DrawShape(Origin, MovePt, pmNotXor); // erase previous shape

    MovePt = Point(X, Y);

    DrawShape(Origin, MovePt, pmNotXor); // draw current shape

  }

}


Drawing on a graphic

Topic groups	See also

You don’t need any components to manipulate your application’s graphic objects. You can construct, draw on, save, and destroy graphic objects without ever drawing anything on screen. In fact, your applications rarely draw directly on a form. More often, an application operates on graphics and then uses a VCL image control component to display the graphic on a form.

Once you move the application’s drawing to the graphic in the image control, it is easy to add printing, Clipboard, and loading and saving operations for any graphic objects. graphic objects can be bitmap files, metafiles, icons or whatever other graphics classes that have been installed such as JPEG graphics.

Note:	Because you are drawing on an offscreen image such as a TBitmap canvas, the image is not displayed until a control copies from a bitmap onto the control’s canvas. That is, when drawing bitmaps and assigning them to an image control, the image appears only when the control has an opportunity to process its paint message. Contrastly, if you are drawing directly onto the canvas property of a control, the picture object is displayed immediately.


Making scrollable graphics

Topic groups	See also

The graphic need not be the same size as the form: it can be either smaller or larger. By adding a scroll box control to the form and placing the graphic image inside it, you can display grphics that are much larger than the form or even larger than the screen. To add a scrollable graphic first you add a TScrollbox component and then you add the image control.


Adding an image control

Topic groups	See also

An image control is a container component that allows you to display your bitmap objects. You use an image control to hold a bitmap that is not necessarily displayed all the time, or which an application needs to use to generate other pictures.

Note:	Adding graphics to controls shows how to use graphics in controls.


Placing the control

Topic groups	See also

You can place an image control anywhere on a form. If you take advantage of the image control’s ability to size itself to its picture, you need to set the top left corner only. If the image control is a nonvisible holder for a bitmap, you can place it anywhere, just as you would a nonvisual component.

If you drop the image control on a scroll box already aligned to the form’s client area, this assures that the scroll box adds any scroll bars necessary to access offscreen portions of the image’s picture. Then set the image control’s properties.


Setting the initial bitmap size

Topic groups	See also

When you place an image control, it is simply a container. However, you can set the image control’s Picture property at design time to contain a static graphic. The control can also load its picture from a file at runtime, as described in .

To create a blank bitmap when the application starts,

1	Attach a handler to the OnCreate event for the form that contains the image.

2	Create a bitmap object, and assign it to the image control’s Picture->Graphic property.

In this example, the image is in the application’s main form, Form1, so the code attaches a handler to Form1’s OnCreate event:

void __fastcallTForm1::FormCreate(TObject *Sender)

{

  TBitmap *Bitmap = new TBitmap();   // create the bitmap object

  Bitmap->Width = 200;               // assign the initial width...

  Bitmap->Height = 200;              // ...and the initial height

  Image->Picture->Graphic = Bitmap;  // assign the bitmap to the image control

}

Assigning the bitmap to the picture’s Graphic property gives ownership of the bitmap to the picture object. The picture object destroys the bitmap when it finishes with it, so you should not destroy the bitmap object. You can assign a different bitmap to the pictureat which point the picture disposes of the old bitmap and assumes ownership of the new one.

If you run the application now, you see that client area of the form has a white region, representing the bitmap. If you size the window so that the client area cannot display the entire image, you’ll see that the scroll box automatically shows scroll bars to allow display of the rest of the image. But if you try to draw on the image, you don’t get any graphics, because the application is still drawing on the form, which is now behind the image and the scroll box.


Drawing on the bitmap

Topic groups	See also

To draw on a bitmap, use the image control’s canvas and attach the mouse-event handlers to the appropriate events in the image control. Typically you would use region operations (fills, rectangles, polylines, and so on). These are fast and efficient methods of drawing.

An efficient way to draw images when you need to access individual pixels is to use the bitmap ScanLine property. For general-purpose usage, you can set up the bitmap pixel format to 24 bits and then treat the pointer returned from ScanLine as an array of RGB. Otherwise, you will need to know the native format of the ScanLine property. This example shows how to use ScanLine to get pixels one line at a time.

void __fastcallTForm1::Button1Click(TObject *Sender)

{

  Graphics::TBitmap *pBitmap = new Graphics::TBitmap();

// This example shows drawing directly to the Bitmap

  Byte *ptr;

  try

  {

    pBitmap->LoadFromFile("C:\Program Files\Borland\CBuilder\Images\Splash\256color\factory.bmp ");

   for (int y = 0; y < pBitmap->Height; y++)

    {

      ptr = pBitmap->ScanLine[y];

      for (int x = 0; x < pBitmap->Width; x++)

        ptr[x] = (Byte)y;

    }

    Canvas->Draw(0,0,pBitmap);

  }

  catch (...)

  {

    ShowMessage("Could not load or alter bitmap");

  }

  delete pBitmap;

}


Loading and saving graphics files

Topic groups	See also

Graphic images that exist only for the duration of one running of an application are of very limited value. Often, you either want to use the same picture every time, or you want to save a created picture for later use. The VCL’s image control makes it easy to load pictures from a file and save them again.

The VCL components you use to load, save, and replace graphic images support many graphic formats including bitmap files, metafiles, glyphs, and so on. They also support installable graphic classes.

The way to load and save graphics files is the similar to any other files and is described in these topics:

Loading a picture from a file

Saving a picture to a file

Replacing the picture


Loading a picture from a file

Topic groups	See also

Your application should provide the ability to load a picture from a file if your application needs to modify the picture or if you want to store the picture outside the application so a person or another application can modify the picture.

To load a graphics file into an image control, call the LoadFromFile method of the image control’s Picture object.

The following code gets a file name from an open-file dialog box, and then loads that file into an image control named Image:

void __fastcallTForm1::Open1Click(TObject *Sender)

{

  if (OpenDialog1->Execute())

  {

    CurrentFile = OpenDialog1->FileName;

    Image->Picture->LoadFromFile(CurrentFile);

  }

}


Saving a picture to a file

Topic groups	See also

The VCL picture object can load and save graphics in several formats, and you can create and register your own graphic-file formats so that picture objects can load and store them as well.

To save the contents of an image control in a file, call the SaveToFile method of the image control’s Picture object.

The SaveToFile method requires the name of a file in which to save. If the picture is newly created, it might not have a file name, or a user might want to save an existing picture in a different file. In either case, the application needs to get a file name from the user before saving, as shown in the next section.

The following pair of event handlers, attached to the File|Save and File|Save As menu items, respectively, handle the resaving of named files, saving of unnamed files, and saving existing files under new names.

void __fastcallTForm1::Save1Click(TObject *Sender)

{

  if (!CurrentFile.IsEmpty())

    Image->Picture->SaveToFile(CurrentFile);   // save if already named

else SaveAs1Click(Sender);                     // otherwise get a name

}

void __fastcallTForm1::Saveas1Click(TObject *Sender)

{

  if (SaveDialog1->Execute())              // get a file name

  {

    CurrentFile = SaveDialog1->FileName;  // save user-specified name

    Save1Click(Sender);                   // then save normally

  }

}


Replacing the picture

Topic groups	See also

You can replace the picture in an image control at any time. If you assign a new graphic to a picture that already has a graphic, the new graphic replaces the existing one.

To replace the picture in an image control, assign a new graphic to the image control’s Picture object.

Creating the new graphic is the same process you used to create the initial graphic , but you should also provide a way for the user to choose a size other than the default size used for the initial graphic. An easy way to provide that option is to present a dialog box.

With such a dialog box in your project, add an include statement for BMPDlg.hpp in the .cpp file for your main form. You can then attach an event handler to the File|New menu item’s OnClick event. Here’s an example:

void __fastcall TForm1::New1Click(TObject *Sender)

{

     Graphics::TBitmap *Bitmap;

  // make sure focus is on width field

  NewBMPForm->ActiveControl = NewBMPForm->WidthEdit;

  // initialize to current dimensions as default ...

     NewBMPForm->WidthEdit->Text = IntToStr(Image->Picture->Graphic->Width);

     NewBMPForm->HeightEdit->Text = IntToStr(Image->Picture->Graphic->Height);

  if (NewBMPForm->ShowModal() != IDCANCEL){        // if user does not cancel dialog...

        Bitmap = new Graphics::TBitmap();             // create a new bitmap object

     // use specified dimensions

     Bitmap->Width = StrToInt(NewBMPForm->WidthEdit->Text);

        Bitmap->Height = StrToInt(NewBMPForm->HeightEdit->Text);

        Image->Picture->Graphic = Bitmap;            // replace graphic with new bitmap

        CurrentFile = EmptyStr;                      //indicate unnamed file

     }

}

Note:	Assigning a new bitmap to the picture object’s Graphic property causes the picture object to destroy the existing bitmap and take ownership of the new one. The VCL handles the details of freeing the resources associated with the previous bitmap automatically.


Using the Clipboard with graphics

Topic groups	See also

You can use the Windows Clipboard to copy and paste graphics within your applications or to exchange graphics with other applications. The VCL’s Clipboard object makes it easy to handle different kinds of information, including graphics.

Before you can use the Clipboard object in your application, you must add an include statement for Clipbrd.hpp to any .cpp file that needs to access Clipboard data.


Copying graphics to the Clipboard

Topic groups	See also

You can copy any picture, including the contents of image controls, to the Clipboard. Once on the Clipboard, the picture is available to all Windows applications.

To copy a picture to the Clipboard, assign the picture to the Clipboard object using the Assign method.

This code shows how to copy the picture from an image control named Image to the Clipboard in response to a click on an Edit|Copy menu item:

void __fastcallTForm1::Copy1Click(TObject *Sender)

{

  Clipboard()->Assign(Image->Picture);

}


Cutting graphics to the Clipboard

Topic groups	See also

Cutting a graphic to the Clipboard is exactly like copying it, but you also erase the graphic from the source.

To cut a graphic from a picture to the Clipboard, first copy it to the Clipboard, then erase the original.

In most cases, the only issue with cutting is how to show that the original image is erased. Setting the area to white is a common solution, as shown in the following code that attaches an event handler to the OnClick event of the Edit|Cut menu item:

void __fastcallTForm1::Cut1Click(TObject *Sender)

{

  TRect ARect;

  Copy1Click(Sender);          // copy picture to Clipboard

  Image->Canvas->CopyMode = cmWhiteness; // copy everything as white

  ARect = Rect(0, 0, Image->Width, Image->Height); // get dimensions of image

  Image->Canvas->CopyRect(ARect, Image->Canvas, ARect); // copy bitmap over self

  Image->Canvas->CopyMode = cmSrcCopy; // restore default mode

}


Pasting graphics from the Clipboard

Topic groups	See also

If the Windows Clipboard contains a bitmapped graphic, you can paste it into any image object, including image controls and the surface of a form.

To paste a graphic from the Clipboard,

1	Call the Clipboard’s HasFormat method to see whether the Clipboard contains a graphic.

HasFormat is a Boolean function. It returns true if the Clipboard contains an item of the type specified in the parameter. To test for graphics, you pass CF_BITMAP.

2	Assign the Clipboard to the destination.

This code shows how to paste a picture from the Clipboard into an image control in response to a click on an Edit|Paste menu item:

void __fastcallTForm1::Paste1Click(TObject *Sender)

{

  Graphics::TBitmap *Bitmap;

  if (Clipboard()->HasFormat(CF_BITMAP)){

Image->Picture->Bitmap->ASsign(Clipboard);Canvas->Draw(0, 0, Bitmap);

  }

}

The graphic on the Clipboard could come from this application, or it could have been copied from another application, such as Windows Paintbrush. You do not need to check the clipboard format in this case because the paste menu should be disabled when the clipboard does not contain a supported format.


Rubber banding example

Topic groups	See also

This section walks you through the details of implementing the “rubber banding” effect in an graphics application that tracks mouse movements as the user draws a graphic at runtime. The example code in this section is taken from a sample application located in the EXAMPLES\DOC\GRAPHEX directory. The application draws lines and shapes on a window’s canvas in response to clicks and drags: pressing a mouse button starts drawing, and releasing the button ends the drawing.

To start with, the example code shows how to draw on the surface of the main form. Later examples demonstrate drawing on a bitmap.

This section covers:

Responding to the mouse

Adding a field to a form object to track mouse actions

Refining line drawing


Responding to the mouse

Topic groups	See also

Your application can respond to the mouse actions: mouse-button down, mouse moved, and mouse-button up. It can also respond to a click (a complete press-and-release, all in one place) that can be generated by some kinds of keystrokes (such as pressing Enter in a modal dialog box).

This section covers:

What’s in a mouse event

Responding to a mouse-down action

Responding to a mouse-up action

Responding to a mouse move


What's in a mouse event
What’s in a mouse event

Topic groups	See also

The VCL has three mouse events: OnMouseDown event, OnMouseMove event, and OnMouseUp event.

When a VCL application detects a mouse action, it calls whatever event handler you’ve defined for the corresponding event, passing five parameters. Use the information in those parameters to customize your responses to the events. The five parameters are as follows:

Parameter	Meaning
Sender	The object that detected the mouse action
Button	Indicates which mouse button was involved: mbLeft, mbMiddle, or mbRight
Shift	Indicates the state of the Alt, Ctrl, and Shift keys at the time of the mouse action
X, Y	The coordinates where the event occurred
Most of the time, you need the coordinates returned in a mouse-event handler, but sometimes you also need to check Button to determine which mouse button caused the event.

Note:	C++Builder uses the same criteria as Microsoft Windows in determining which mouse button has been pressed. Thus, if you have switched the default “primary” and “secondary” mouse buttons (so that the right mouse button is now the primary button), clicking the primary (right) button will record mbLeft as the value of the Button parameter.


Responding to a mouse-down action

Topic groups	See also	Example

Whenever the user presses a button on the mouse, an OnMouseDown event goes to the object the pointer is over. The object can then respond to the event.

To respond to a mouse-down action, attach an event handler to the OnMouseDown event.

The VCL generates an empty handler for a mouse-down event on the form:

void __fastcallTForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

}

Here’s code that displays some text at the point where the mouse button is pressed. It uses the X and Y parameters sent to the method, and calls the TextOut method of the canvas to display text there:


Example: Responding to a mouse-down action

The following code displays the string 'Here!' at the location on a form clicked with the mouse:

void __fastcallTForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Canvas->TextOut(X, Y, "Here!");	// write text at (X, Y)

}

When the application runs, you can press the mouse button down with the mouse cursor on the form and have the string, “Here!” appear at the point clicked. This code sets the current drawing position to the coordinates where the user presses the button:

void __fastcallTForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Canvas->MoveTo(X, Y);	// set pen position

}

Pressing the mouse button now sets the pen position, setting the line’s starting point. To draw a line to the point where the user releases the button, you need to respond to a mouse-up event.


Responding to a mouse-up action

Topic groups	See also	Example

An OnMouseUp event occurs whenever the user releases a mouse button. The event usually goes to the object the mouse cursor is over when the user presses the button, which is not necessarily the same object the cursor is over when the button is released. This enables you, for example, to draw a line as if it extended beyond the border of the form.

To respond to mouse-up actions, define a handler for the OnMouseUp event.


Example: Responding to a mouse-up action

Here’s a simple OnMouseUp event handler that draws a line to the point of the mouse-button release:

void __fastcallTForm1::FormMouseUp(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Canvas->LineTo(X, Y);	// draw line from PenPos to (X, Y)

}

This code lets a user draw lines by clicking, dragging, and releasing. In this case, the user cannot see the line until the mouse button is released.


Responding to a mouse move

Topic groups	See also

An OnMouseMove event occurs periodically when the user moves the mouse. The event goes to the object that was under the mouse pointer when the user pressed the button. This allows you to give the user some intermediate feedback by drawing temporary lines while the mouse moves.

To respond to mouse movements, define an event handler for the OnMouseMove event. This example uses mouse-move events to draw intermediate shapes on a form while the user holds down the mouse button, thus providing some feedback to the user. The OnMouseMove event handler draws a line on a form to the location of the OnMouseMove event:

void __fastcallTForm1::FormMouseMove(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Canvas->LineTo(X, Y);	// draw line to current position

}

With this code, moving the mouse over the form causes drawing to follow the mouse, even before the mouse button is pressed.

Mouse-move events occur even when you haven’t pressed the mouse button.

If you want to track whether there is a mouse button pressed, you need to add an object field to the form object.


Adding a field to a form object to track mouse actions

Topic groups	See also	Example

To track whether a mouse button was pressed, you must add an object field to the form object. When you add a component to a form, C++Builder adds a field that represents that component to the form object, so that you can refer to the component by the name of its field. You can also add your own fields to forms by editing the type declaration in the form unit’s header file.

In the following example, the form needs to track whether the user has pressed a mouse button. To do that, it adds a Boolean field and sets its value when the user presses the mouse button.

To add a field to an object, edit the object’s type definition, specifying the field identifier and type after the public directive at the bottom of the declaration.

C++Builder “owns” any declarations before the public directive: that’s where it puts the fields that represent controls and the methods that respond to events.


Example: Adding a field to a form object to track mouse actions

The following code gives a form a field called Drawing of type bool, in the form object’s declaration. It also adds two fields to store points Origin and MovePt of type POINT.

class TForm1 : public TForm

{

__published:  // IDE-managed Components

  void __fastcallFormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y);

  void __fastcall FormMouseMove(TObject *Sender, TShiftState Shift, int X,

  int Y);

  void __fastcall FormMouseUp(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y);

private:	// User declarations

public:	// User declarations

  __fastcallTForm1(TComponent* Owner);

  bool Drawing;  //field to track whether button was pressed
   POINT Origin, MovePt;  // fields to store points

};

When you have a Drawing field to track whether to draw, set it to true when the user presses the mouse button, and false when the user releases it:

void __fastcallTForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Drawing = true;            // set the Drawing flag

  Canvas->MoveTo(X, Y);      // set pen position

}

void __fastcallTForm1::FormMouseUp(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Canvas->LineTo(X, Y);      // draw line from PenPos to (X, Y)

  Drawing = false;           // clear the Drawing flag

}

Then you can modify the OnMouseMove event handler to draw only when Drawing is true:

void __fastcallTForm1::FormMouseMove(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Drawing)

    Canvas->LineTo(X, Y);	// only draw if mouse is down

}

This results in drawing only between the mouse-down and mouse-up events, but you still get a scribbled line that tracks the mouse movements instead of a straight line.

The problem is that each time you move the mouse, the mouse-move event handler calls LineTo, which moves the pen position, so by the time you release the button, you’ve lost the point where the straight line was supposed to start.


Refining line drawing

Topic groups	See also

With fields in place to track various points, you can refine an application’s line drawing.


Tracking the origin point

Topic groups	See also

When drawing lines, track the point where the line starts with the Origin field.

Origin must be set to the point where the mouse-down event occurs, so the mouse-up event handler can use Origin to place the beginning of the line, as in this code:

void __fastcallTForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Drawing = true;            // set the Drawing flag

  Canvas->MoveTo(X, Y);      // set pen position

  Origin = Point(X, Y);      // record where the line starts

}

void __fastcallTForm1::FormMouseUp(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Canvas->MoveTo(Origin.x, Origin.y);  // move pen to starting point

  Canvas->LineTo(X, Y);                // draw line from PenPos to (X, Y)

  Drawing = false;                     // clear the Drawing flag

}

Those changes get the application to draw the final line again, but they do not draw any intermediate actions--the application does not yet support “rubber banding.”


Tracking movement

Topic groups	See also

The problem with this example as the OnMouseMove event handler is currently written is that it draws the line to the current mouse position from the lastmouse position, not from the original position.You can correct this by moving the drawing position to the origin point, then drawing to the current point:

void __fastcallTForm1::FormMouseMove(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Drawing)

  {

    Canvas->MoveTo(Origin.x, Origin.y);  // move pen to starting point

    Canvas->LineTo(X, Y);

  }

}

The above tracks the current mouse position, but the intermediate lines do not go away, so you can hardly see the final line. The example needs to erase each line before drawing the next one, by keeping track of where the previous one was. The MovePt field allows you to do this.

MovePt must be set to the endpoint of each intermediate line, so you can use MovePt and Origin to erase that line the next time a line is drawn:

void __fastcallTForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  Drawing = true;            // set the Drawing flag

  Canvas->MoveTo(X, Y);      // set pen position

  Origin = Point(X, Y);      // record where the line starts

  MovePt = Point(X, Y);      // record last endpoint

}

void __fastcallTForm1::FormMouseMove(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Drawing)

  {

    Canvas->Pen->Mode = pmNotXor;        // use XOR mode to draw/erase

    Canvas->MoveTo(Origin.x, Origin.y);  // move pen to starting point

    Canvas->LineTo(MovePt.x, MovePt.y);  // erase old line

    Canvas->MoveTo(Origin.x, Origin.y);  // move pen to starting point again

    Canvas->LineTo(X, Y);                // draw new line

  }

  MovePt = Point(X, Y);      // record new endpoint

  Canvas->Pen->Mode = pmCopy;

}

Now you get a “rubber band” effect when you draw the line. By changing the pen’s mode to pmNotXor, you have it combine your line with the background pixels. When you go to erase the line, you’re actually setting the pixels back to the way they were. By changing the pen mode back to pmCopy (its default value) after drawing the lines, you ensure that the pen is ready to do its final drawing when you release the mouse button.


Working with multimedia

Topic groups	See also

C++Builder allows you to add multimedia components to your applications. To do this, you can use either the TAnimate component on the Win32 page or the TMediaplayer component on the System page of the Component palette. Use the animate component when you want to add silent video clips to your application. Use the media player component when you want to add audio and/or video clips to an application.

The following topics are discussed in this section:

Adding silent video clips to an application

Adding audio and/or video clips to an application


Adding silent video clips to an application

Topic groups	See also

The animation control in C++ Builder allows you to add silent video clips to your application.

To add a silent video clip to an application:

1	Double-click the animate icon on the Win32 page of the Component palette. This automatically puts an animation control on the form window in which you want to display the video clip.

2	Using the Object Inspector, select the Name property and enter a newname for your animation control. You will use this name when you call the animation control. (Follow the standard rules for naming C++ identifiers).

Always work directly with the Object Inspector when setting design time properties and creating event handlers.

3	 Do one of the following:

 Select the Common AVI property and choose one of the AVIs available from the drop down list; or

Select the FileName property and click the ellipsis (...) button, choose an AVI file from any available local or network directories and click Open in the Open AVI dialog; or

Select the resource of an AVI using the ResName or ResID properties. Use ResHandle to indicate the module that contains the resource identified by ResName or ResID.

This loads the AVI file into memory. If you want to display the first frame of the AVI clip on-screen until it is played using the Active property or the Play method, then set the Open property to true.

4	Set the Repetitions property to the number of times you want to the AVI clip to play. If this value is 0, then the sequence is repeated until theStop method is called.

5	Make any other changes to the animation control settings. For example, if you want to change the first frame displayed when animation control opens, then set the StartFrameproperty to the desired frame value.

6	Set the Active property to true using the drop down list or write an event handler to run the AVI clip when a specific event takes place at runtime. For example, to activate the AVI clip when a button object is clicked, write the button’s OnClick event specifying that. You may also call the Play method to specify when to play the AVI.

Note:	If you make any changes to the form or any of the components on the form after setting Active to true, the Active property becomes false and you have to reset it to true. Do this either just before runtime or at runtime.

For more information on using the animation control, see the topic called Example of adding silent video clips.


Example of adding silent video clips

Topic groups	See also

Suppose you want to display an animated logo as the first screen that appears when your application starts. After the logo finishes playing the screen disappears.

To run this example, create a new project and save the Unit1.cpp file as Frmlogo.cpp and save the Project1.bpr file as Logo.bpr. Then:

1	Double-click the animate icon from the Win32 page of the Component palette.

2	Using the Object Inspector, set its Name property to Logo1.

3	Select its FileName property, click the ellipsis (...) button, choose the cool.avi file from your ..\Examples\Coolstuf directory. Then click Open in the Open AVI dialog.

This loads the cool.avi file into memory.

4	Position the animation control box on the form by clicking and dragging it to the top right hand side of the form.

5	Set its Repetitions property to 5.

6	Click the form to bring focus to it and set its Name property to LogoForm1 and its Caption property to Logo Window. Now decrease the height of the form to right- center the animation control on it.

7	Double-click the form’s OnActivate event and write the following code to run the AVI clip when the form is in focus at runtime:

Logo1->Active = true;

8	Double-click the Label icon on the Standard page of the Component palette. Select its Caption property and enter Welcome to Cool Images 4.0. Now select its Font property, click the ellipsis (...) button and choose Font Style: Bold, Size: 18, Color: Navy from the Font dialog and click OK. Click and drag the label control to center it on the form.

9	 Click the animation control to bring focus back to it. Double-click its OnStop event and write the following code to close the form when the AVI file stops:

LogoForm1->Close();

10	Select Run|Run to execute the animated logo window.


Adding audio and/or video clips to an application

Topic groups	See also

The media player component in C++ Builder allows you to add audio and/or video clips to your application. It opens a media device and plays, stops, pauses, records, etc., the audio and/or video clips used by the media device. The media device may be hardware or software.

 To add an audio and/or video clip to an application:

1	Double-click the media player icon on the System page of the Component palette. This automatically put a media player control on the form window in which you want the media feature.

2	Using the Object Inspector, select the Nameproperty and enter a new name for your media player control. You will use this when you call the media player control. (Follow the standard rules for naming C++ identifiers.)

Always work directly with the Object Inspector when setting design time properties and creating event handlers.

3	 Select the DeviceType property and choose the appropriate device type to open using the AutoOpen property or the Open method. (If DeviceType is dtAutoSelect the device type is selected based on the file extension of the media file specified by the FileName property.) For more information on device types and their functions, see the table below.

4	 If the device stores its media in a file, specify the name of the media file using the FileName property. Select the FileName property, click the ellipsis (...) button, and choose a media file from any available local or network directories and click Open in the Open dialog. Otherwise, insert the hardware the media is stored in (disk, cassette, and so on) for the selected media device, at runtime.

5	Set theAutoOpen property to true. This way the media player automatically opens the specified device when the form containing the media player control is created at runtime. If AutoOpen is false, the device must be opened with a call to theOpen method.

6	Set theAutoEnable property to true to automatically enable or disable the media player buttons as required at runtime; or, double-click theEnabledButtons property to set each button to true or false depending on which ones you want to enable or disable.

The multimedia device is played, paused, stopped, and so on when the user clicks the corresponding button on the mediaplayer component. The device can also be controlled by the methods that correspond to the buttons (Play, Pause, Stop, Next, Previous, and so on).

7	Position the media player control bar on the form by either clicking and dragging it to the appropriate place on the form or by selecting the Align property and choosing the appropriate align position from the drop down list.

If you want the media player to be invisible at runtime, set theVisible property to false and control the device by calling the appropriate methods (Play, Pause, Stop, Next, Previous, Step, Back, Start Recording,Eject).

8	Make any other changes to themedia player control settings. For example, if the media requires a display window, set the Display property to the control that displays the media. If the device uses multiple tracks, set theTracks property to the desired track.

Device Type	Software/Hardware used	Plays	Uses Tracks	Uses a Display Window
dtAVIVideo	AVI Video Player for Windows	AVI Video files	No	Yes
dtCDAudio	CD Audio Player for Windows or a CD Audio Player	CD Audio Disks	Yes	No
dtDAT	Digital Audio Tape Player	Digital Audio Tapes	Yes	No
dtDigitalVideo	Digital Video Player for Windows	AVI, MPG, MOV files	No	Yes
dtMMMovie	MM Movie Player	MM film	No	Yes
dtOverlay	Overlay device	Analog Video	No	Yes
dtScanner	Image Scanner	N/A for Play (scans images on Record)	No	No
dtSequencer	MIDI Sequencer for Windows	MIDI files	Yes	No
dtVCR	Video Cassette Recorder	Video Cassettes	No	Yes
dtWaveAudio	Wave Audio Player for Windows	WAV files	No	No
For more information on using the media player control, see the topic called Example of adding audio and/or video clips.


Example of adding audio and/or video clips

Topic groups	See also

This example runs an AVI video clip of a multimedia advertisement forC++Builder. To run this example, create a new project and save the Unit1.cpp file to FrmAd.cpp and save the Project1.bpr file to MmediaAd.bpr. Then:

1	Double-click the media player icon on the System page of the Component palette.

2	Using the Object Inspector, set the Name propertyof the media player toVideoPlayer1.

3	Select its DeviceType property and choose dtAVIVideo from the drop down list.

4	Select its FileName property, click the ellipsis (...) button,  choose the file from your ..\Examples\Coolstuf directory. Click Open in the Open dialog.

5	Set its AutoOpen property to true and its Visible property to false.

6	Double-click the Animate icon from the Win32 page of the Component palette. Set its AutoSize property to false, its Height property to175 and Width property to 200. Click and drag the animation control to the top left corner of the form.

7	Click the media player to bring back focus to it. Select its Display property and choose Animate1 from the drop down list.

8	Click the form to bring focus to it and select its Name property and enter C++_Ad. Now resize the form to the size of the animation control.

9	Double-click the form’s OnActivate event and write the following code to run the AVI video when the form is in focus:

Videoplayer1->Play();

10	Choose Run|Run to execute the AVI video.


Using threads: Overview
Using threads

Topic groups	See also

The VCL provides several objects that make writing multi-threaded applications easier. Multi-threaded applications are applications that include several simultaneous paths of execution. While using multiple threads requires careful thought, it can enhance your programs by

Avoiding bottlenecks. With only one thread, a program must stop all execution when waiting for slow processes such as accessing files on disk, communicating with other machines, or displaying multimedia content. The CPU sits idle until the process completes. With multiple threads, your application can continue execution in separate threads while one thread waits for the results of a slow process.

Organizing program behavior. Often, a program’s behavior can be organized into several parallel processes that function independently. Use threads to launch a single section of code simultaneously for each of these parallel cases. Use threads to assign priorities to various program tasks so that you can give more CPU time to more critical tasks.

Multiprocessing. If the system running your program has multiple processors, you can improve performance by dividing the work into several threads and letting them run simultaneously on separate processors.

Note:	The NT operating system implements true multi-processing when it is supported by the underlying hardware. Windows 95 only simulates multiprocessing, even if the underlying hardware supports multiprocessing.

The following topics discuss support for threads in C++Builder:

Defining thread objects

Coordinating threads

Executing thread objects

Using threads in distributed applications

Debugging multi-threaded applications


Defining thread objects

Topic groups	See also

For most applications, you can use a thread object to represent an execution thread in your application. Thread objects simplify writing multi-threaded applications by encapsulating the most commonly needed uses of threads.

Note:	Thread objects do not allow you to control the security attributes or stack size of your threads. If you need to control these, you must use the Windows API CreateThread or theBeginThread function. Even when using Windows Thread API calls or BeginThread, you can still benefit from some of the thread synchronization objects and methods described in Coordinating threads.

To use a thread object in your application, you must create a new descendant of TThread. To create a descendant of TThread, choose File|New from the main menu. In the new objects dialog box, select Thread Object. You are prompted to provide a class name for your new thread object. After you provide the name, C++Builder creates a new .CPP and header file to implement the thread.

Note:	Unlike most dialog boxes in the IDE that require a class name, the New Thread Object dialog does not automatically prepend a ‘T’ to the front of the class name you provide.

The automatically generated.CPPunit file contains the skeleton code for your new thread object. If you named your thread TMyThread, it would look like the following:

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

#include <vcl\vcl.h>

#pragma hdrstop

#include "Unit2.h"

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

__fastcall TMyThread::TMyThread(bool CreateSuspended): TThread(CreateSuspended)

{

}

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

void __fastcall TMyThread::Execute()

{

  // ---- Place thread code here ----

}

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

In the automatically generated .CPP file, you

Initialize the thread by filling in the constructor.

Write the thread function by filling in the Execute method.

Optionally, Write clean-up code


Initializing the thread

Topic groups	See also

Use the constructor to initialize your new thread class. This is where you can assign a default priority for your thread and indicate whether it should be freed automatically when it finishes executing.

Assigning a default priority

Priority indicates how much preference the thread gets when the operating system schedules CPU time among all the threads in your application. Use a high priority thread to handle time critical tasks, and a low priority thread to perform other tasks. To indicate the priority of your thread object, set the! Priority property. Priority values fall along a seven point scale, as described in the following table:

Value	Priority
tpIdle	The thread executes only when the system is idle. Windows won't interrupt other threads to execute a thread with tpIdle priority.
tpLowest	The thread's priority is two points below normal.
tpLower	The thread's priority is one point below normal.
tpNormal	The thread has normal priority.
tpHigher	The thread's priority is one point above normal.
tpHighest	The thread's priority is two points above normal.
tpTimeCritical	The thread gets highest priority.
Warning:	Boosting the thread priority of a CPU intensive operation may "starve" other threads in the application. Only apply priority boosts to threads that spend most of their time waiting for external events.

The following code shows the constructor of a low-priority thread that performs background tasks which should not interfere with the rest of the application’s performance:

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

__fastcall TMyThread::TMyThread(bool CreateSuspended): TThread(CreateSuspended)

{

  Priority = tpIdle;

}

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

Indicating when threads are freed

Often, applications execute a particular thread only once. When this is the case, it is easiest to let the thread object free itself. To do this, set the FreeOnTerminate property to true.

There are times, however, when your thread object represents a task that the application performs several times, in response to an event such as a user action or external message. When your application needs multiple instances of the same thread object (to run the thread multiple times), you can improve performance by caching threads for reuse rather than destroying them after they run and creating new ones every time. To do this, set the FreeOnTerminate property to false.


Writing the thread function

Topic groups	See also

The Execute method is your thread function. You can think of it as a program that is launched by your application, except that it shares the same process space. Writing the thread function is a little trickier than writing a separate program because you must make sure that you don’t overwrite memory that is used by other threads in your application. On the other hand, because the thread shares the same process space with other threads, you can use the shared memory to communicate between threads.

When implementing the Execute method, you can manage these issues by

Using the main VCL thread.

Using thread-local variables.

Avoiding simultaneous access.

Waiting for other threads.

Checking for termination by other threads.


Using the main VCL thread

Topic groups	See also

When you use objects from the VCL object hierarchy, their properties and methods are not guaranteed to be thread-safe. That is, accessing properties or executing methods may perform some actions that use memory which is not protected from the actions of other threads. Because of this, a main VCL thread is set aside for access of VCL objects. This is the thread that handles all Windows messages received by components in your application.

If all objects access their properties and execute their methods within this single thread, you need not worry about your objects interfering with each other. To use the main VCL thread, create a separate routine that performs the required actions. Call this separate routine from within your thread’s Synchronize method. For example:

void __fastcallTMyThread::PushTheButton(void)

{

  Button1->Click();

}

void __fastcallTMyThread::Execute()

{

  ...

  Synchronize((TThreadMethod)PushTheButton);

  ...

}

Synchronize waits for the main VCL thread to enter the message loop and then executes the passed method.

Note:	Because Synchronize uses the message loop, it does not work in console applications. You must use other mechanisms, such as critical sections, to protect access to VCL objects in console applications.

You do not always need to use the main VCL thread. Some objects are thread-aware. Omitting the use of the Synchronize method when you know an object’s methods are thread-safe will improve performance because you don’t need to wait for the VCL thread to enter its message loop. You do not need to use the Synchronize method in the following situations:

Data access components are thread-safe as long as each thread has its own database session component. The one exception to this is when you are using Access drivers. Access drivers are built using the Microsoft ADO library, which is not thread-safe.

When using data access components, you must still wrap all calls that involve data-aware controls in the Synchronize method. Thus, for example, you need to synchronize calls that link a data control to a dataset by setting the DataSet property of the data source object, but you don’t need to synchronize to access the data in a field of the dataset.

For more information about using database sessions with threads, see Managing multiple sessions.

Graphics objects are thread-safe. You do not need to use the main VCL thread to access TFont, TPen, TBrush, TBitmap, TMetafile, or TIcon. Canvas objects can be used outside the Synchronize method by locking them.

While list objects are not thread-safe, you can use a thread-safe version, TThreadList, instead of TList.


Using thread-local variables

Topic groups	See also

 The thread function and any of the routines it calls have their own local variables, just like any other C++ routines. These routines also can access any global variables. In fact, global variables provide a powerful mechanism for communicating between threads.

Sometimes, however, you may want to use variables that are global to all the routines running in your thread, but not shared with other instances of the same thread class. You can do this by declaring thread-local variables. Make a variable thread-local by adding the __thread modifier to the variable declaration. For example,

int __thread x;

declares an integer type variable that is private to each thread in the application, but global within each thread.

The __thread modifier can only be used for global (file-scope) and static variables. Pointer and Function variables can’t be thread variables. Types that use copy-on-write semantics, such as AnsiStrings don’t work as thread variables either. A program element that requires run-time initialization or run-time finalization cannot be declared to be a __thread type.

The following declarations require runtime initialization and are therefore illegal.

int f( );

int __thread x = f( );   // illegal

Instantiation of a class with a user-defined constructor or destructor requires runtime initialization and is therefore illegal:

class X  {

   X( );

   ~X( );

};

X __thread myclass;   // illegal


Checking for termination by other threads

Topic groups	See also

Your thread object begins running when the Execute method is called (see Executing thread objects) and continues until Execute finishes. This reflects the model that the thread performs a specific task, and then stops when it is finished. Sometimes, however, an application needs a thread to execute until some external criterion is satisfied.

You can allow other threads to signal that it is time for your thread to finish executing by checking the Terminated property. When another thread tries to terminate your thread, it calls the Terminate method. Terminate sets your thread’s Terminated property to true. It is up to your Execute method to implement the Terminate method by checking and responding to the Terminated property. The following example shows one way to do this:

void __fastcall TMyThread::Execute()

{

  while (!Terminated)

    PerformSomeTask();

}


Writing clean-up code

Topic groups	See also

You can centralize the code that cleans up when your thread finishes executing. Just before a thread shuts down, an OnTerminate event occurs. Put any clean-up code in the OnTerminate event handler to ensure that it is always executed, no matter what execution path the Execute method follows.

The OnTerminate event handler is not run as part of your thread. Instead, it is run in the context of the main VCL thread of your application. This has two implications:

You can’t use any thread-local variables in an OnTerminate event handler (unless you want the main VCL thread values).

You can safely access any components and VCL objects from the OnTerminate event handler without worrying about clashing with other threads.


Coordinating threads

Topic groups	See also

When writing the code that runs when your thread is executed, you must consider the behavior of other threads that may be executing simultaneously. In particular, care must be taken to avoid two threads trying to use the same global object or variable at the same time. In addition, the code in one thread can depend on the results of tasks performed by other threads.

Whether using thread objects or generating threads using the Windows API CreateThread or BeginThread, the following topics describe techniques for coordinating threads:

Avoiding simultaneous access.

Waiting for other threads.

Using the main VCL thread.

When global memory does not need to be shared by multiple threads, consider using thread-local variables instead of global variables. By using thread-local variables, your thread does not need to wait for or lock out any other threads.


Avoiding simultaneous access

Topic groups	See also

To avoid clashing with other threads when accessing global objects or variables, you may need to block the execution of other threads until your thread code has finished an operation. Be careful not to block other execution threads unnecessarily. Doing so can cause performance to degrade seriously and negate most of the advantages of using multiple threads.

The VCL includes support for three techniques that prevent other threads from accessing the same memory as your thread:

Locking objects.

Using critical sections.

Using a multi-read exclusive-write synchronizer.


Locking objects

Topic groups	See also

Some objects have built-in locking that prevents the execution of other threads from using that object instance.

For example, canvas objects (TCanvas and descendants) have a Lock method that prevents other threads from accessing the canvas until the Unlock method is called.

The VCL also includes a thread-safe list object, TThreadList. Calling TThreadList::LockList returns the list object while also blocking other execution threads from using the list until the UnlockList method is called. Calls to TCanvas::Lock or TThreadList::LockList can be safely nested. The lock is not released until the last locking call is matched with a corresponding unlock call in the same thread.


Using critical sections

Topic groups	See also

If objects do not provide built-in locking, you can use a critical section. Critical sections work like gates that allow only a single thread to enter at a time. To use a critical section, create a global instance of TCriticalSection. TCriticalSection has two methods, Acquire(which blocks other threads from executing the section) and Release(which removes the block).

Each critical section is associated with the global memory you want to protect. Every thread that accesses that global memory should first use the Acquire method to ensure that no other thread is using it. When finished, threads call the Release method so that other threads can access the global memory by calling Acquire.

Warning:	Critical sections only work if every thread uses them to access the associated global memory. Threads that ignore the critical section and access the global memory without calling Acquire can introduce problems of simultaneous access.

For example, consider an application that has a global critical section variable, pLockXY, that blocks access to global variables X and Y. Any thread that uses X or Y must surround that use with calls to the critical section such as the following:

pLockXY->Acquire(); // lock out other threads

try

{

  Y = sin(X);

}

__finally

{

  pLockXY->Release();

}


Using the multi-read exclusive-write synchronizer

Topic groups	See also

When you use critical sections to protect global memory, only one thread can use the memory at a time. This can be more protection than you need, especially if you have an object or variable that must be read often but to which you very seldom write. There is no danger in multiple threads reading the same memory simultaneously, as long as no thread is writing to it.

When you have some global memory that is read often, but to which threads occasionally write, you can protect it using TMultiReadExclusiveWriteSynchronizer. This object acts like a critical section, but one which allows multiple threads to read the memory it protects as long as no thread is writing to it. Threads must have exclusive access to write to memory protected by TMultiReadExclusiveWriteSynchronizer.

To use a multi-read exclusive-write synchronizer, create a global instance of TMultiReadExclusiveWriteSynchronizer that is associated with the global memory you want to protect. Every thread that reads from this memory must first call the BeginRead method. BeginRead ensures that no other thread is currently writing to the memory. When a thread finishes reading the protected memory, it calls the EndRead method. Any thread that writes to the protected memory must call BeginWrite first. BeginWrite ensures that no other thread is currently reading or writing to the memory. When a thread finishes writing to the protected memory, it calls the EndWrite method, so that threads waiting to read the memory can begin.

Warning:	Like critical sections, the multi-read exclusive-write synchronizer only works if every thread uses it to access the associated global memory. Threads that ignore the synchronizer and access the global memory without calling BeginRead or BeginWrite introduce problems of simultaneous access.


Waiting for other threads

Topic groups	See also

If your thread must wait for another thread to finish some task, you can tell your thread to temporarily suspend execution. You can either

Wait for another thread to completely finish executing, or

Wait for a task to be completed.


Waiting for a thread to finish executing

Topic groups	See also

To wait for another thread to finish executing, use the WaitFor method of that other thread. WaitFor doesn’t return until the other thread terminates, either by finishing its own Execute method or by terminating due to an exception. For example, the following code waits until another thread fills a thread list object before accessing the objects in the list:

if (pListFillingThread->WaitFor())

{

  for (TList *pList = ThreadList1->LockList(), int i = 0; i < pList->Count; i++)

    ProcessItem(pList->Items[i]);

  ThreadList1->UnlockList();

}

In the previous example, the list items were only accessed when the WaitFor method indicated that the list was successfully filled. This return value must be assigned by the Execute method of the thread that was waited for. However, because threads that call WaitFor want to know the result of thread execution, not code that calls Execute, the Execute method does not return any value. Instead, the Execute method sets theReturnValue property. ReturnValue is then returned by the WaitFor method when it is called by other threads. Return values are integers. Your application determines their meaning.


Waiting for a task to be completed

Topic groups	See also

Sometimes, you need to wait for a thread to finish some operation rather than waiting for a particular thread to complete execution. To do this, use an event object. Event objects (TEvent) should be created with global scope so that they can act like signals that are visible to all threads.

When a thread completes an operation that other threads depend on, it calls TEvent::SetEvent. SetEvent turns on the signal, so any other thread that checks will know that the operation has completed. To turn off the signal, use the ResetEvent method.

For example, consider a situation where you must wait for several threads to complete their execution rather than a single thread. Because you don’t know which thread will finish last, you can’t simply use the WaitFor method of one of the threads. Instead, you can have each thread increment a counter when it is finished, and have the last thread signal that they are all done by setting an event.

The following code shows the end of the OnTerminate event handler for all of the threads that must complete. CounterGuard is a global critical section object that prevents multiple threads from using the counter at the same time. Counter is a global variable that counts the number of threads that have completed.

void __fastcallTDataModule::TaskThreadTerminate(TObject *Sender)

{

...

  CounterGuard->Acquire(); // lock the counter

  if (--Counter == 0)    // decrement the global counter

    Event1->SetEvent(); // signal if this is the last thread

  CounterGuard->Release(); // release the lock on the counter

}

The main thread initializes the Counter variable, launches the task threads, and waits for the signal that they are all done by calling the WaitFormethod. WaitFor waits for a specified time period for the signal to be set, and returns one of the values from the following table:

Value	Meaning
wrSignaled	The signal of the event was set.
wrTimeout	The specified time elapsed without the signal being set.
wrAbandoned	The event object was destroyed before the timeout period elapsed.
wrError	An error occurred while waiting.
The following shows how the main thread launches the task threads and then resumes when they have all completed:

Event1->ResetEvent(); // clear the event before launching the threads

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

  new  TaskThread(false); // create and launch task threads

if (Event1->WaitFor(20000) != wrSignaled)

  throw Exception;

// now continue with the main thread, All task threads have finished

Note:	If you do not want to stop waiting for an event after a specified time period, pass the WaitFor method a parameter value of INFINITE. Be careful when using INFINITE, because your thread will hang if the anticipated signal is never received.


Executing thread objects

Topic groups	See also

Once you have implemented a thread class by giving it an Execute method, you can use it in your application to launch the code in the Execute method. To use a thread, first create an instance of the thread class. You can create a thread instance that starts running immediately, or you can create your thread in a suspended state so that it only begins when you call the Resume method. To create a thread so that it starts up immediately, set the constructor’s CreateSuspended parameter to false. For example, the following line creates a thread and starts its execution:

TMyThread *SecondProcess = new TMyThread(false); // create and run the thread

Warning:	Do not create too many threads in your application. The overhead in managing multiple threads can impact performance. The recommended limit is 16 threads per process on single processor systems. This limit assumes that most of those threads are waiting for external events. If all threads are active, you will want to use fewer.

You can create multiple instances of the same thread type to execute parallel code. For example, you can launch a new instance of a thread in response to some user action, allowing each thread to perform the expected response.

The following topics discuss how to use the threads in your application:

Overriding the default priority.

Starting and stopping threads

Caching threads


Overriding the default priority

Topic groups	See also

When the amount of CPU time the thread should receive is implicit in the thread’s task, its priority is set in the constructor. This is described in Initializing the thread. However, if the thread priority varies depending on when the thread is executed, create the thread in a suspended state, set the priority, and then start the thread running:

TMyThread *SecondProcess = new TMyThread(true); // create but don’t run

SecondProcess->Priority = tpLower; // set the priority lower than normal

SecondProcess->Resume(); // now run the thread


Starting and stopping threads

Topic groups	See also

A thread can be started and stopped any number of times before it finishes executing. To stop a thread temporarily, call its Suspend method. When it is safe for the thread to resume, call its Resume method. Suspend increases an internal counter, so you can nest calls to Suspend and Resume. The thread does not resume execution until all suspensions have been matched by a call to Resume.

You can request that a thread end execution prematurely by calling the Terminate method. Terminate sets the thread’s Terminated property to true. If you have implemented the Execute method properly, it checks the Terminated property periodically, and stops execution when Terminated is true.


Caching threads

Topic groups	See also

When your application needs multiple instances of the same thread object (to run the thread multiple times), you can improve performance by caching threads for reuse rather than destroying them after they run and creating new ones every time. To cache threads, you must maintain a list of threads that have been created. This list can be maintained by an object that uses the threads, or you can use a global variable to store the thread cache.

When a new thread is needed, a cached thread is used, or a new thread is created (as in the following GetThread function):

TThreadList *pCache;

...

TThread *GetThread(void)

{

  TList *pList = pCache->LockList();

  TThread *NewThread;

  if (pList->Count) // cache is not empty

  {

    NewThread = (TThread *)pList->Items[0];

    pList->Delete(0); // remove from cache

  }

else

    NewThread = (TThread *)new TMyThread(true); // create but don’t run

  pCache->UnlockList();

  return NewThread;

}

When a thread finishes executing, it is added to the cache:

void __fastcallTMyThread::Terminate(TObject *Sender) // this is the OnTerminate handler

{

  pCache->Add(&this); // add pointer to this thread to the cache

}

Finally, when the application finishes executing (or the object that owns the thread cache is destroyed), the threads in the cache must be freed, as in the following application OnDeactivate handler:

void __fastcall TDataModule1::ApplicationDeactivate(TObject *Sender)

{

  TList *pList = pCache->LockList();

  for (int i = pList->Count - 1; i >= 0; i--)

  {

    delete pList->Items[i];

    pList->Delete(i);

  }

  pCache->UnlockList();

}


Using threads in distributed applications

Topic groups	See also

Distributed applications introduce additional challenges for writing multi-threaded applications. When considering how to coordinate threads, you must also keep in mind how other processes affect the threads in your application.

Usually, handling distributed threading issues is the responsibility of the server application. When writing servers, you must consider how requests from clients are serviced.

If each client request has its own thread, you must ensure that different client threads do not interfere with each other. In addition to the usual issues that arise when coordinating multiple threads, you may need to ensure that each client has a consistent view of your application. For example, you can’t use thread variables to store information that must persist over multiple client requests if each time the client calls your application it uses a different thread. When clients change the values of object properties or global variables, they are influencing not only their own view of that object or variable, but the view of any other clients.

The following topics describe some of the issues for using threads with

Message-based servers.

Distributed objects.


Using threads in message-based servers

Topic groups	See also

Message-based servers receive client request messages, perform some action in response to that message, and return messages to the client. Examples include internet server applications and simple services that you can write using sockets.

Usually, when writing message-based servers, each client message gets its own thread. When client messages are received, the application spawns a thread to handle the message. This thread runs until it sends a response to the client, and then terminates. You must be careful when using global objects and variables, but it is fairly easy to control how threads are created and run because client messages are all received and dispatched by the main application thread.


Using threads with distributed objects

Topic groups	See also

When writing servers for distributed objects, the threading issues are complicated. Unlike message-based servers, where there is a point in the code where messages are received and dispatched, clients call into server objects by calling any of their methods or by accessing any of their properties. Because of this, there is no easy way for server applications to spawn separate threads for each client request.

Writing applications (.EXEs)

When writing an .EXE that implements an object or objects for remote clients, client requests come in as threads. How this works depends on whether clients access your object using COM or CORBA.

Under COM, client requests come in as part of the application’s message loop. This means that any code which executes after the application’s main message loop starts up must be prepared to protect access to objects and global memory from other threads.

Under CORBA, multiple clients may access your application at the same time.Therefore, you must protect both global data and instance data. You can use thread variables, however, if you do not share threads over clients by thread pooling.

Writing Libraries

When an Active Library implements the distributed object, threading is usually controlled by the technology (COM, DCOM, or MTS) that supports distributed object calls. When you first create your server library with the appropriate wizard, you are prompted to specify a threading model that dictates how client requests are assigned threads. These models include the following:

Single-threaded model. Client requests are serialized by the calling mechanism. Your .DLL does not need to be concerned with threading issues because it receives one client request at a time.

Single-threaded apartment model. (Also called Apartment model.) Each object instantiated by a client is accessed by one thread at a time. You must protect against multiple threads accessing global memory, but instance data (such as object properties) is thread-safe. Further, each client always accesses the object instance using the same thread, so that you can use thread variables.

Activity model. (Called both Apartment-threaded and Free-threaded under MTS.) Each object instance is accessed by one thread at a time, but clients do not always use the same thread for every call. Instance data is safe, but you must guard global memory, and thread variables will not be consistent across client calls.

Multi-threaded apartment model. (Also called Free-threading.) Each object instance may be called by multiple threads simultaneously. You must protect instance data as well as global memory. Thread variables are not consistent across client calls.

Single/Multi-threaded apartment model. (Also called Both.) This is the same as the Multi-threaded apartment model, except that all callbacks supplied by clients are guaranteed to execute in the same thread. This means you do not need protect values supplied as parameters to callback functions.

COM-based systems use the application’s message loop to synchronize threads in all but the Multi-threaded apartment model (which is only available under DCOM). Because of this, you must ensure that any lengthy call made through a COM interface calls the application object’s ProcessMessages method. Failure to do so prevents other clients from gaining access to your application, effectively making your library single-threaded.


Debugging multi-threaded applications

Topic groups	See also

When debugging multi-threaded applications, it can be confusing trying to keep track of the status of all the threads that are executing simultaneously, or even to determine which thread is executing when you stop at a breakpoint. You can use the Thread Status box to help you keep track of and manipulate all the threads in your application. To display the Thread status box, choose View|Threads from the main menu.

When a debug event occurs (breakpoint, exception, paused), the thread status view indicates the status of each thread. Right-click the Thread Status box to access commands that locate the corresponding source location or make a different thread current. When a thread is marked as current, the next step or run operation is relative to that thread.

The Thread Status box lists all your application’s execution threads by their thread ID. If you are using thread objects, the thread ID is the value of the ThreadID property. If you are not using thread objects, the thread ID for each thread is returned by the call to CreateThread or BeginThread.


Overview: Exception handling
Exception handling

Topic groups	See also

C++Builder supports C++ exception handling, C-based structured exception handling, and VCL exception handling.

The following topics describe these different types of exception handling:

C++ exception handling

Structured exceptions under Win32

VCL exception handling

Note that the examples provided for C++ exception handling and structured exception handling can be compiled and run successfully from the command line using bcc32.exe rather than from the IDE. You would use C++ exception handling if your application calls standard C++ routines and objects.

VCL exception handling can occur from within the IDE. In fact, although C++Builder supports using C++ and C-based structured exception handling, C++Builder and the VCL make it possible for you to develop applications that include built-in exception handling routines that throw exceptions automatically when something goes wrong.


C++ exception handling

Topic groups	See also

Exceptions are exceptional conditions that require special handling and can include errors that occur at runtime, such as divide by zero, and the exhaustion of free store. Exception handling provides a standard way of dealing with errors, discovering both anticipated and unanticipated problems, and enables developers to recognize, track down, and fix bugs.

An understanding of C++ exception handling includes

ANSI requirements for exception handling

Exception handling syntax

Exception declarations

Throwing an exception

Handling an exception

Exception specifications

Constructors and destructors in exception handling

Unhandled exceptions

Setting exception handling options


ANSI requirements for exception handling

Topic groups	See also

C++Builder exception handling is consistent with the proposed ANSI/ISO C++ working paper specification. Throwing an exception allows you to gather information at the throw point that could be useful for diagnosing its cause.

You can use an exception handler to specify actions to take before terminating the program. Only synchronous exceptions (where the cause of failure is generated from within the program) are handled. An event (generated from outside the program) such as pressing Ctrl+C is not considered to be an exception.

The C++ language specifies that all exceptions should be thrown within a try-block. This block is followed by one or more catch blocks that identify and handle the errors generated in the try-block.


Exception handling syntax

Topic groups	See also

Exception handling requires the use of three keywords: try, catch, and throw. Programs prepare to catch exceptions by trying statements that might generate a special condition. When a C++ program throws an exception, you can transfer or throw control to another part of the program called the exception handler that handles that type of exception. The handler is said to catch the exception.

A program throws an exception by executing a throw statement. The throw statement generally occurs within a function:

throw “overflow”;

As in the example, the statement throws an object that describes the type of exception, in this case, an arithmetic overflow. Another part of the program can catch the thrown exception object and handle it accordingly.

To use exception handling, surround the code with a try/catch construct. The syntax for a try/catch construct is as follows:

try-block:

try compound-statement handler-list

handler-list:

handler handler-listopt

handler:

catch (exception-declaration) compound-statement

exception declaration:

type-specifier-list declarator

type-specifier-list abstract-declarator

type-specifier-list

...

throw-expression:

throw assignment-expressionopt

Note:	The try, catch, and throw keywords are not allowed in C programs.

A try-block specified by try must be followed immediately by the handler specified by catch. The try-block is a statement that specifies the flow of control as the program executes. If an exception is thrown in the try-block, program control is transferred to the appropriate exception handler.

The handler is a block of code designed to handle the exception. The C++ language requires at least one handler immediately after a try-block. The program should include a handler for each exception that the program can generate.


Exception declarations

Topic groups	See also

Although C++ allows an exception to be of any type, it is useful to make exceptions objects. An exception object is treated like any other object. The exception carries information from the point where the exception is thrown to the point where the exception is caught. This is information that the application user will want to know when the program encounters an anomaly at runtime.


Throwing an exception

Topic groups	See also

A block of code in which an exception can occur must be prefixed by the keyword try and enclosed by braces. This indicates that the program is prepared to test for exceptions. If an exception occurs, the program flow is interrupted and the following occur:

The program searches for a matching handler

If a handler is found, the stack is unwound to that point

Program control is transferred to the handler

If no handler is found, you can call set_terminate() to provide a termination handler; otherwise, the program calls the terminate function

If no exceptions are thrown, the program executes normally.

When an exception occurs, the throw expression initializes a temporary object of type T (to match the type of argument arg) used in throw(T arg). Other copies can be generated as required by the compiler. Consequently, it can be useful to define a copy constructor for the exception object when you have a class that contains subobjects. (You would not need to define the copy constructor for a bitwise copy.)

Examples

You can see various ways to throw exceptions by reviewing the following examples.

Example 1

Example 2

Example 3

Example 4

Note:	The examples provided can be compiled and run successfully from the command line using bcc32.exe rather than from the IDE.


Example 1

Topic groups	See also

The following example passes an Out object to a handler.

/* Program results:

duck

*/

#include <stdio.h>

bool pass;

class Out{};

void festival(bool firsttime){ if(firsttime) throw Out(); }

int main()

{

  try         { pass = true; festival(true); }

  catch(Out& e){ pass = false;             }

  return pass ? (puts("luck"),0) : (puts("duck"),1);

}


Example 2

Topic groups	See also

The following example simply throws the last exception again. An exception must currently exist.

/* Program results:

got out of test

*/

#include <stdio.h>

bool pass;

class Out{};

void festival(bool firsttime){ if(firsttime) throw Out(); }

void test()

{

  try         { festival(true);         }

  catch(Out& e){ pass = false; throw; }

}

int main()

{

  try         { test();      }

  catch(Out& e){ pass = true; }

  return pass ? (puts("got out of test"),0) : (puts("still have test"),1);

}

The following example calls the terminate function if no exception exists:

/* Program results:

*** Nobody threw an exception ***

*/

#include <except.h>

#include <process.h>

#include <stdio.h>

bool pass;

class Out{};

void my_terminate(){ puts("*** Nobody threw an exception ***"); exit(1); }

void festival(bool firsttime){ if(firsttime) throw Out(); }

void test()

{

  try         { festival(false); }

  catch(Out& e){ pass = false; }

  throw;  // can't rethrow an exception that never happened!

}

int main()

{

  set_terminate(my_terminate);

  try         { test();      }

  catch(Out& e){ pass = true; }

  return pass ? (puts("got out of test"),0) : (puts("still have test"),1);

}


Example 3

Topic groups	See also

The following example specifies a list of exceptions that festival and test can throw. No other exceptions can propagate from festival.

/* Program results:

test handled the exception

*/

#include <stdio.h>

bool pass;

class Out{};

void festival(bool firsttime) throw(Out) // festival only throws Out exceptions.

{

  if(firsttime) throw Out();

}

void test() throw() // test throws no exceptions

{

  try         { festival(true); }

  catch(Out& e){ pass = true; }

}

int main()

{

  pass = false;

  test();

  return pass ? (puts("test handled the exception"),0) :

                (puts("no exception happened")     ,1);

}

If festival generates an exception other than Out, it is considered an unexpected exception and program control is transferred to the unexpected function as shown in example 4.


Example 4

Topic groups	See also

The following example shows that test should not throw any exceptions. If any function (for example, operator new) in the body of test throws an exception, the exception should be caught and handled within the body of test. Otherwise, the exception is a violation of the exception specification for test. You can call set_unexpected() to set a different handler; otherwise, the unexpected function is called.

/* Program results:

*** test failed ***

*/

#include <except.h>

#include <process.h>

#include <stdio.h>

bool pass;

class Out{};

void my_unexpected(){ puts("*** test failed ***"); exit(1); }

void festival(bool firsttime) throw(Out) // festival only throws Out exceptions.

{

  if(firsttime) throw Out();

}

void test() throw() // test throws no exceptions

{

  try         { festival(true);        }

  catch(Out& e){ pass = true; throw; } // rethrow Out exception - error

}

int main()

{

  set_unexpected(my_unexpected);

  pass = false;

  test();

  return pass ? (puts("test handled the exception"),0) :

                (puts("no exception happened")     ,1);

}

When an exception occurs, the throw expression initializes a temporary object of type T (to match the type of argument arg) used in throw(T arg). Other copies can be generated by the compiler. Consequently, it can be useful to define a copy constructor for the exception object as shown in the following example:

/* Program results:

throwing a festival

made a festival

copied a festival

destructed a festival

caught a festival

destructed a festival

*/

#include <stdio.h>

class festival

{

  public:

  festival()            { puts("made a festival");       }

  festival(const festival&){ puts("copied a festival");     }

 ~festival()            { puts("destructed a festival"); }

};

int main()

{

  try          { puts("throwing a festival"); throw(festival()); }

  catch(festival&){ puts("caught a festival"  );               }

  return 0;

}


Handling an exception

Topic groups	See also

The exception handler is specified by the catch keyword which is placed immediately after the try-block. The keyword catch can also occur immediately after another catch block.

Every exception thrown by a program must be caught and processed by the exception handler. The handler catches an exception when its type matches (or can be converted to) the type in the catch statement. Once a type match is made, program control is transferred to the handler and the stack is unwound. The handler specifies what actions to take to deal with the program anomaly.

After the handler is executed, the program continues at the point after the last handler for the current try-block. No other handlers are evaluated for the current exception. A goto statement can be used to transfer program control out of a handler.

If the program fails to provide an exception handler for a thrown exception, the program terminates.

Examples

The following examples demonstrate using exception handlers:

Example 1

Example 2

Example 3

Note:	The examples provided can be compiled and run successfully from the command line using bcc32.exe rather than from the IDE.


Example 1

Topic groups	See also

/* Program results:

threw a Spring Festival

threw a Harvest Festival

*/

#include <stdio.h>

class festival{};

class Harvest : public festival{};

class Spring: public festival{};

void ToHaveFun(int i)

{

  if(i==1) throw(Harvest()  );

  else     throw(Spring());

}

int main()

{

  try                     { ToHaveFun(0);                   }

  catch(const Harvest&)  { puts("threw a Harvest Festival"); }

  catch(const Spring&){ puts("threw a Spring Festival"    ); }

  try                     { ToHaveFun(1);                   }

  catch(const Harvest&)  { puts("threw a Harvest Festival"); }

  catch(const Spring&){ puts("threw a Spring Festival"    ); }

  return 0;

}


Example 2

Topic groups	See also

The following example shows that when you catch an exception and that exception is part of a class hierarchy, you need to start with the most derived class.

/* Program results:

threw a festival

threw a harvest festival

threw a spring festival

threw a festival (what kind??!!)

threw a festival (what kind?!!!) */

#include <stdio.h>

class festival{};

class harvest  : public festival{};

class spring: public festival{};

void ToHaveFun(int i)

{

  if     (i==1) throw(harvest()  );

  else if(i==2) throw(spring());

  else          throw(festival()     );

}

int main()

{

  /* These catch statements are in a sensible order:*/

  try                     { ToHaveFun(0);                   }

  catch(const harvest&  ){ puts("threw a harvest festival"); }

  catch(const spring&){ puts("threw a spring festival"    ); }

  catch(const festival&     ){ puts("threw a festival"         ); }

  try                     { ToHaveFun(1);                   }

  catch(const harvest&  ){ puts("threw a harvest festival"); }

  catch(const spring&){ puts("threw a spring festival"    ); }

  catch(const festival&     ){ puts("threw a festival"         ); }

  try                     { ToHaveFun(2);                   }

  catch(const harvest&  ){ puts("threw a harvest festival"); }

  catch(const spring&){ puts("threw a spring festival"    ); }

  catch(const festival&     ){ puts("threw a festival"         ); }

  /* But, if you catch the base class Object *first*, you don't get

     a chance to see what type actually got thrown:

  */

  try                     { ToHaveFun(1);                          }

  catch(const festival&     ){ puts("threw a festival (what kind??!!)"); }

  catch(const harvest&  ){ puts("threw a harvest festival"       ); }

  catch(const spring&){ puts("threw a spring festival"           ); }

  try                     { ToHaveFun(2);                          }

  catch(const festival&     ){ puts("threw a festival (what kind?!!!)"); }

  catch(const harvest&  ){ puts("threw a harvest festival"       ); }

  catch(const spring&){ puts("threw a spring festival"           ); }

  return 0;

}


Example 3

Topic groups	See also

In the following example, the catch ( ... ) statement handles any exception, regardless of type. This statement is the only handler in the try-block.

/* Program results:

test handled the exception

*/

#include <stdio.h>

bool pass;

class Out{};

void festival(bool firsttime) throw(Out) // festival only throws Out exceptions.

{

  if(firsttime) throw Out();

}

void test() throw() // test throws no exceptions

{

  try         { festival(true); }

  catch(Out& e){ pass = true; }

}

int main()

{

  pass = false;

  test();

  return pass ? (puts("test handled the exception"),0) :

                (puts("no exception happened")     ,1);

}


Exception specifications

Topic groups	See also

C++ provides a feature called exception specification that lets you list within a declaration what exceptions a function might throw. This exception specification is used as a suffix of the function declaration and has the following syntax:

exception-specification:

throw (type-id-listopt)

type-id-list:

type-id

type-id-list, type-id

The function suffix is not part of the function’s type. Consequently, a pointer to a function is not affected by the function’s exception specification. Such a pointer checks only the function’s return and argument types. Therefore, the following is legal:

void f2(void) throw();      // Should not throw exceptions

void f3(void) throw (BETA); // Should only throw BETA objects

void (* fptr)();            // Pointer to a function returning void

fptr = f2;

fptr = f3;

Be careful when overriding virtual functions. Because the exception specification is not considered part of the function type, you can violate the program design.

Example

In the following example, the derived class BETA::vfunc is defined so that it does not throw any exceptions—a departure from the original function declaration.

class ALPHA {

public:

  struct ALPHA_ERR {};

  virtual void vfunc(void) throw (ALPHA_ERR) {} // Exception specification

};

class BETA : public ALPHA {

  void vfunc(void) throw() {} // Exception specification is changed

};

The following examples are functions with exception specifications.

void f1();                // The function can throw any exception

void f2() throw();        // Should not throw any exceptions

void f3() throw( A, B* ); // Can throw exceptions publicly derived from A,

                          // or a pointer to publicly derived B

The definition and all declarations of such a function must have an exception specification containing the same set of type-ids. If a function throws an exception not listed in its specification, the program will call unexpected.


Constructors and destructors in exception handling

Topic groups	See also

Class constructors can throw exceptions if they cannot successfully construct an object. When you throw objects by value and an exception is thrown, the copy constructor is called for the exception. The copy constructor initializes a temporary object at the throw point. The program may also generate other copies.

If a constructor throws an exception, that object’s destructor is not necessarily called. Destructors are called only for the base classes and for those objects that were fully constructed inside the classes since entering the try-block.

The process of calling destructors for objects constructed on the path from a try-block to a throw expression is called stack unwinding. If a destructor causes an exception to be raised during stack unwinding and does not handle it, terminate is called.

Destructors are called by default, but you can switch off the default by using the -xd- compiler option.


Unhandled exceptions

Topic groups	See also

If an exception is thrown and no event handler is found, the program calls the terminate function. This example shows what can happen when the program encounters an unhandled exception.

/* Program results:

*** Nobody caught the exception ***

*/

#include <except.h>

#include <process.h>

#include <stdio.h>

bool pass;

class Out{};

void my_terminate(){ puts("*** Nobody caught the exception ***"); abort(); }

void festival(bool firsttime){ if(firsttime) throw Out(); }

void test()

{

  festival(true);

}

int main()

{

  set_terminate(my_terminate);

  test(); // test throws exception, but no handler.

  return pass ? (puts("got out of test"),0) : (puts("still in test"),1);

}


Setting exception handling options

Topic groups	See also

Following are the exception handling options in the C++Builder compiler.

Command-line switch	Description
-x	Enable C++ exception handling (On by default)
-xd	Enable destructor cleanup. Calls destructors for all automatically declared objects between the scope of the catch and throw statements when an exception is thrown. (Advanced option–on by default)
-xp	Enable exception location information. Makes available runtime identification of exceptions by providing line numbers in the source code at the exception location. This lets the program query the file and line number where a C++ exception occurred. (Advanced option)


Structured exceptions under Win32

Topic groups	See also

Win32 supports C-based structured exception handling that is similar to C++ exceptions. There are some key differences, however, that require careful use when they are mixed with C++ code that is exception aware.

Understanding C-based structured exception handling includes the following:

Using structured exceptions in C and C++ code

Syntax of structured exceptions

Handling structured exceptions

Exception filters

Mixing C++ with structured exceptions

DefiningExceptions

Raising exceptions

Termination blocks


Using structured exceptions in C and C++ code

Topic groups	See also

Keep the following in mind when using structured exception handling in C++Builder applications:

C-structured exceptions can be used in C++ programs.

C++ exceptions cannot be used in a C program because C++ exceptions require that their handler be specified by the catch keyword, and catch is not allowed in a C program.

An exception generated by a call to the RaiseException function is handled by a try/__except (C++) or __try/__except (C) block. (You can also use try/__finally or __try/__finally blocks. See Syntax of structured exceptions.) All handlers of try/catch blocks are ignored when RaiseException is called.

Exceptions that are not handled by the application don't result in a call to terminate(), but are instead passed to the operating system (in general, the end result is termination of the process).

Exception handlers do not receive a copy of the exception object, unless they request it.

You can use the following C exception helper functions in C or C++ programs:

GetExceptionCode

GetExceptionInformation

SetUnhandledExceptionFilter

UnhandledExceptionFilter

C++Builder does not restrict the use of UnhandledExceptionFilter function to the except filter of __try/__except or try/__except blocks. However, program behavior is undefined when this function is called outside of a __try/__except or try/__except block.


Syntax of structured exceptions

Topic groups	See also

In a C program, the ANSI-compatible keywords used to implement structured exceptions are__except, __finally, and __try.

Note:	The __try keyword can only appear in C programs. If you want to write portable code, do not use structured exception handling in your C++ programs.

try-except exception handling syntax

For try-except exception handling, the syntax is as follows:

try-block:

 __try compound-statement (in a C module)

 trycompound-statement (in a C++ module)

handler:

 __except (expression) compound-statement

try-finally termination syntax

For try-finally termination, the syntax is as follows:

try-block:

 __try compound-statement (in a C module)

 try compound-statement (in a C++ module)

termination:

 __finally compound-statement


Handling structured exceptions

Topic groups	See also

Structured exceptions can be handled using an extension of C++ exception handling:

try {

        foo();

    }

    __except(__expr__) {

        // handler here

    }

__expr__ is an expression that evaluates to one of three values:

Value	Description
EXCEPTION_CONTINUE_SEARCH (0)	The handler is not entered, and the OS continues searching for an exception handler.
EXCEPTION_CONTINUE_EXECUTION (-1)	Continue execution at the point of the exception.
EXCEPTION_EXECUTE_HANDLER (1)	Enter the exception handler. If the code was compiled with destructor cleanup enabled (-xd, on by default), all destructors for local objects created between the point of the exception and the exception handler are called when the stack is unwound. Stack unwinding is completed before entering the handler.
Win32 provides two functions that can be used to query information about the active exception: GetExceptionCode() and GetExceptionInformation(). If you want to call a function as part of the “filter” expression above, these functions must be called from within the context of the __except() directly:

#include <Windows.h>
#include <excpt.h>

int filter_func(EXCEPTION_POINTERS *);

...

EXCEPTION_POINTERS *xp = 0;

    try {

        foo();

    }

    __except(filter_func(xp = GetExceptionInformation())) {

        //...

    }

Or, if you prefer using the comma operator to assignments nested in function calls, see the following example:

__except((xp = GetExceptionInformation()), filter_func(xp))


Exception filters

Topic groups	See also

A filter expression can invoke a filter function but the filter function cannot call GetExceptionInformation. You can pass the return value of GetExceptionInformation as a parameter to a filter function.

To pass the EXCEPTION_POINTERS information to an exception handler, the filter expression or filter function must copy the pointer or data from GetExceptionInformation to a location where the handler can later access it.

In the case of nested try-except statements, each statement's filter expression is evaluated until it locates EXCEPTION_EXECUTE_HANDLER or EXCEPTION_CONTINUE_EXECUTION. A filter expression can invoke GetExceptionInformation to get exception information.

As long as GetExceptionInformation or GetExceptionCode is called directly in the expression provided to __except, you can use a function to determine what to do with an exception rather than trying to create a complex C++ expression. Almost all of the information needed to handle an exception can be extracted from the result of GetExceptionInformation(). GetExceptionInformation() returns a pointer to an EXCEPTION_POINTERS structure:

struct EXCEPTION_POINTERS {

        EXCEPTION_RECORD *ExceptionRecord;

        CONTEXT *Context;

    };

EXCEPTION_RECORD contains the machine-independent state:

struct EXCEPTION_RECORD {

        DWORD ExceptionCode;

        DWORD ExceptionFlags;

        struct EXCEPTION_RECORD *ExceptionRecord;

        void *ExceptionAddress;

        DWORD NumberParameters;

        DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];

    };

Typically, the filter function looks at the information in the ExceptionRecord to decide how to respond. Sometimes more specific information is needed (especially if the action to take is EXCEPTION_CONTINUE_EXECUTION: if nothing is done, the code that caused the exception would be executed again). For this situation, the other field of the EXCEPTION_POINTERS structure provides the processor state at the time of the exception. If this structure is modified and the filter returns EXCEPTION_CONTINUE_EXCEPTION, it is used to set the state of the thread before continuing with execution. For example:

static int xfilter(EXCEPTION_POINTERS *xp)

    {

        int rc;

        EXCEPTION_RECORD *xr = xp->ExceptionRecord;

        CONTEXT *xc = xp->Context;

        switch (xr->ExceptionCode) {

            case EXCEPTION_BREAKPOINT:

                // whoops, someone left an embedded breakpoint.

                // just step over it (1 byte on x86)

                ++xc->Eip;

                rc = EXCEPTION_CONTINUE_EXECUTION;

                break;

            case EXCEPTION_ACCESS_VIOLATION:

                rc = EXCEPTION_EXECUTE_HANDLER;

                break;

            default:

                // give up

                rc = EXCEPTION_CONTINUE_SEARCH;

                break;

        };

        return rc;

    }

    ...

    EXCEPTION_POINTERS *xp;

    try {

        func();

    }

    __except(xfilter(xp = GetExceptionInformation())) {

        abort();

    }


Mixing C++ with structured exceptions

Topic groups	See also

You need to be aware of a few issues when using structured exceptions in C++ programs. First, although C++Builder implements C++ exceptions with Win32 structured exceptions, C++ exceptions are transparent to an __except block.

A try block can be followed by either exactly one except block or at least one catch block. Attempting to mix the two causes a compiler error. Code that needs to handle both types of exceptions should simply be nested inside two try blocks:

try {

        EXCEPTION_POINTERS *xp;

        try {

            func();

        }

        __except(xfilter(xp = GetExceptionInformation())) {

            //...

        }

    }

    catch (...) {

        //...

    }

A function's throw() specification does not affect the behavior of a program with regard to a Win32 exception. Also, an unhandled exception is eventually handled by the operating system (if a debugger doesn't handle it first), unlike a C++ program that calls terminate().

Any module compiled with the -xd compiler option (on by default) will invoke destructors for all objects with auto storage. Stack unwinding occurs from the point where the exception is thrown to the point where the exception is caught.

Example


C-based exceptions in C++ program example

Topic groups

/* Program results:

Another exception:

Caught a C-based exception.

Caught C++ exception[Hardware error: Divide by 0]

C++ allows __finally too!

*/

#include <stdio.h>

#include <string.h>

#include <windows.h>

class Exception

{

  public:

  Exception(char* s = "Unknown"){ what = strdup(s);      }

  Exception(const Exception& e ){ what = strdup(e.what); }

 ~Exception()                   { delete[] what;         }

  char* msg() const             { return what;           }

private:

  char* what;

};

int main()

{

  float e, f, g;

  try

  {

    try

    {

      f = 1.0;

      g = 0.0;

      try

      {

        puts("Another exception:");

        e = f / g;

      }

      __except(EXCEPTION_EXECUTE_HANDLER)

      {

        puts("Caught a C-based exception.");

        throw(Exception("Hardware error: Divide by 0"));

      }

    }

    catch(const Exception& e)

    {

      printf("Caught C++ Exception: %s :\n", e.msg());

    }

  }

  __finally

  {

    puts("C++ allows __finally too!");

  }

return e;

}


Defining exceptions

Topic groups	See also

Raising a Win32 exception that is handled within the same program does not generally make much sense: C++ exceptions can do the job better, remain significantly more portable, and use a simpler syntax. Win32 exceptions do have the advantage, however, that they can be handled by components that may not have been compiled with the same C++ compiler.

The first step is to define the exception. An exception is a 32-bit integer with the following format (starting at bit 0):

Bit	Meaning
31-30	11 = error (normal) 00 = success, 01 = informational 10 = warning
29	1 = user-defined
28	Reserved
27-0	User-defined
In addition to defining the exception code, you need to decide whether or not to include additional information with the exception (accessible to the filter/handler from the exception record). There is no conventional method for encoding additional parameters in the exception code.


Raising exceptions

Topic groups	See also

A Win32 exception is raised with a call to RaiseException(), which is declared as follows

void RaiseException(DWORD ec, DWORD ef, DWORD na, const DWORD *a);

where:

ec	Exception code
ef	Exception flags, either 0 or EXCEPTION_NONCONTINUABLE  (If the exception is marked as not continuable and a filter tries to continue it, EXCEPTION_NONCONTINUABLE_EXCEPTION is raised.)
na	Number of elements in the arguments array
a	Pointer to first element in the argument array–the meaning of these arguments depends on the particular exception


Termination blocks

Topic groups	See also

The structured exception handling model supports a “termination block” which is executed whether a guarded block is exited normally or via an exception. The C++Builder compiler supports this in C with the following syntax:

__try {

        func();

    }

    __finally {

        // this happens whether func() raises an exception or not

    }

Termination blocks are supported by a C++ extension where you can handle cleanup in the __finally block:

try {

        func();

    }

    __finally {

        // this happens whether func() raises an exception or not

    }

The following example illustrates termination blocks:

/* Program results:

An exception:

Caught an exception.

The __finally is executed too!

No exception:

No exception happened, but __finally still executes!

*/

#include <stdio.h>

#include <windows.h>

int main()

{

  float e, f, g;

  try

  {

    f = 1.0;

    g = 0.0;

    try

    {

      puts("An exception:");

      e = f / g;

    }

    __except(EXCEPTION_EXECUTE_HANDLER)

    {

      puts("Caught an exception.");

    }

  }

  __finally

  {

    puts("The __finally is executed too!");

  }

  try

  {

    f = 1.0;

    g = 2.0;

    try

    {

      puts("No exception:");

      e = f / g;

    }

    __except(EXCEPTION_EXECUTE_HANDLER)

    {

      puts("Caught an exception.");

    }

  }

  __finally

  {

    puts("No exception happened, but __finally still executes!");

  }

return e;

}

C++ code can also handle a “termination block” by creating local objects with destructors that are called when the scope is exited. Since C++Builder structured exceptions support destructor cleanup, this will work regardless of the type of exception raised.

Note:	One special case concerns what happens when an exception is raised and never handled by the program. For a C++ exception, the C++Builder compiler calls destructors for local objects (not required by the language definition), whereas with an unhandled Win32 exception, destructor cleanup does not happen.


VCL exception handling

Topic groups	See also

When using VCL components in your applications, you need to understand the VCL exception handling mechanism. That is because exceptions are built into many classes and they are thrown automatically when something unexpected occurs. If you do not handle the exception, the VCL will handle it in a default manner. Typically, a message displays describing the type of error that occurred.

When you are programming and you encounter an exception that displays a message indicating the type of exception that was thrown, you can look up the exception class in the VCL Reference. The information provided will often help you to determine where the error occurred and its cause. A limited number of these classes is described in VCL exception classes.

An understanding of VCL exceptions includes:

Differences between C++ and VCL exception handling

Handling operating system exceptions

Handling VCL exceptions

Portability considerations


Differences between C++ and VCL exception handling

Topic groups	See also

Following are some noteworthy differences between C++ and VCL exception handling.

Exceptions thrown from constructors:

C++ destructors are called for members and base classes that are fully constructed.

VCL base class destructors are called even if the object or base class isn’t fully constructed.

Catching and throwing exceptions:

C++ exceptions can be caught by reference, pointer, or value. VCL exceptions, which are exceptions derived from TObject, can only be caught by reference or pointer. An attempt to catch TObject exceptions by value results in a compile-time error. Hardware or operating system exceptions, such as EAccessViolation, should be caught by reference.

VCL exceptions are caught by reference.

You cannot use throw to reraise an exception that was caught within VCL code.


Handling operating system exceptions

Topic groups	See also

C++Builder allows you to handle exceptions thrown by the operating system. Operating system exceptions include access violations, integer math errors, floating-point math errors, stack overflow, and Ctrl+C interrupts. These are handled in the C++ RTL and converted to VCL exception class objects before being dispatched to your application. You can then write C++ code that looks like this:

try

{

  char * p = 0;

  *p = 0;

}

// You should always catch by reference.

catch (const EAccessViolation &e)

{

  printf("You can't do that!\n");

}

The classes C++Builder uses are the same as those that Delphi uses and are only available to C++Builder VCL applications. They are derived from TObject and require the VCL underpinnings.

Here are some characteristics of C++Builder exception handling:

You are not responsible for freeing the exception object.

Operating system exceptions should be caught by reference.

You cannot rethrow an operating system exception once the catch frame has been exited and have it be caught by intervening VCL catch frames.

You cannot rethrow an operating system exception once the catch frame has been exited and have it be caught by intervening operating system catch frames.

The last two points can be stated roughly as this: Once an operating system exception is caught as a C++ exception, it cannot be rethrown as if it were an operating system exception or a VCL exception unless you are in the catching stack frame.


Handling VCL exceptions

Topic groups	See also

C++Builder broadens the semantics for handling software exceptions thrown from the VCL or, equivalently, exceptions thrown from C++ where the exception class being thrown is derived from TObject. In such a case, a couple of rules are derived from the fact that VCL-style classes can only be allocated on the heap.

VCL-style exception classes may only be caught by pointer, if it is a software exception, or by reference (reference is preferred).

A VCL-style exception should be thrown with “by value” syntax.


VCL exception classes

Topic groups	See also

C++Builder includes a large set of built-in exception classes for automatically handling divide-by-zero errors, file I/O errors, invalid typecasts, and many other exception conditions. All VCL exception classes descend from one root object called Exception. Exception encapsulates the fundamental properties and methods for all exceptions and provides a consistent interface for applications to handle exceptions.

You can pass exceptions to a catch block that takes a parameter of type Exception. Use the following syntax to catch VCL exceptions:

catch (const exception_class &exception_variable)

You specify the exception class that you want to catch and provide a variable by which to refer to the exception.

Following is an example of how to throw a VCL exception:

void __fastcall TForm1::ThrowException(TObject *Sender)

{

  try

  {

    throw Exception(“VCL component”);

  }

  catch(const Exception &E)

  {

    ShowMessage(AnsiString(E.ClassName())+ E.Message);

  }

}

The throw statement in the previous example creates an instance of the Exception class and calls its constructor. All exceptions descended from Exception have a message that can be displayed, passed through constructors, and retrieved through the Message property.

Selected VCL exception classes are described below.

Exception class	Description
EAbort	Stops a sequence of events without displaying an error message dialog box.
EAccessViolation	Checks for invalid memory access errors.
EBitsError	Prevents invalid attempts to access a Boolean array.
EComponentError	Signals an invalid attempt to register or rename a component.
EConvertError	Indicates string or object conversion errors.
EDatabaseError	Specifies a database access error.
EDBEditError	Catches data incompatible with a specified mask.
EDivByZero	Catches integer divide-by-zero errors.
EExternalException	Signifies an unrecognized exception code.
EInOutError	Represents a file I/O error.
EIntOverflow	Specifies integer calculations whose results are too large for the allocated register.
EInvalidCast	Checks for illegal typecasting.
EInvalidGraphic	Indicates an attempt to work with an unrecognized graphic file format.
EInvalidOperation	Occurs when invalid operations are attempted on a component.
EInvalidPointer	Results from invalid pointer operations.
EMenuError	Involves a problem with menu item.
EOleCtrlError	Detects problems with linking to ActiveX controls.
EOleError	Specifies OLE automation errors.
EPrinterError	Signals a printing error.
EPropertyError	Occurs on unsuccessful attempts to set the value of a property.
ERangeError	Indicates an integer value that is too large for the declared type to which it is assigned.
ERegistryException	Specifies registry errors.
EStackOverflow	Occurs when the stack grows into the final guard page.
EZeroDivide	Catches floating-point divide-by-zero errors.
As you can see from the selected list above, the built-in VCL exception classes handle much of the exception handling for you and can simplify your code. There are other times when you will need to create your own exception classes to handle unique situations. You can declare a new exception class making it a descendant of type Exception creating as many constructors as you need (or copy the constructors from an existing class in SYSUTILS.HPP).


Portability considerations

Topic groups	See also

Several Runtime Libraries (RTLs) are delivered with C++Builder. Most of them pertain to C++Builder applications, but one of them (CW32MT.LIB) is the normal multi-threaded RTL that does not make any references to the VCL. This RTL is provided for support of legacy applications which may be part of a project but should not depend on the VCL. This RTL does not have support for catching operating system exceptions because those exception objects are derived from TObject and would require parts of the VCL to be linked into your application.

To get the full benefits of C++Builder, use the CP32MT.LIB library. This is the multi-threaded runtime library that provides memory management and exception handling with the VCL.


Working with packages and components: Overview
About packages

Topic groups	See also

A package is a special dynamic-link library used by C++Builder applications, the IDE, or both. Runtime packages provide functionality when a user runs an application. Design-time packages are used to install components in the IDE and to create special property editors for custom components. A single package can function at both design time and runtime, and design-time packages frequently work by calling runtime packages. To distinguish them from other DLLs, package libraries are stored in files that end with the .BPL (Borland package library) extension.

Like other runtime libraries, packages contain code that can be shared among applications. For example, the most frequently used C++Builder components reside in a package called VCL40. Each time you create an application, you can specify that it uses VCL40. When you compile an application created this way, the application’s executable image contains only the code and data unique to it; the common code is in VCL40.BPL. A computer with several package-enabled applications installed on it needs only a single copy of VCL40.BPL, which is shared by all the applications and the IDE itself.

C++Builder ships with several precompiled runtime packages, including VCL40, that encapsulate VCL components. C++Builder also uses design-time packages to manipulate components in the IDE.

You can build applications with or without packages. However, if you want to add custom components to the IDE, you must install them as design-time packages.

You can create your own runtime packages to share among applications. If you write C++Builder components, you can compile your components into design-time packages before installing them.

Package topics:

Why use packages?

Packages and standard DLLs

Runtime packages

Using runtime packages in an application

Deciding which runtime packages to use

Custom packages

Design-time packages

Installing component packages

Creating and editing packages

Creating a package

Editing an existing package

Package source files and makefiles

   Packaging components

Understanding the structure of a package

     Naming packages

     The Requires list

       Avoiding circular package references

       Handling duplicate package references

     The Contains list

       Avoiding redundant source code uses

Compiling packages

   Package-specific compiler directives

     Weak packaging

   Using the command-line compiler and linker

   Package files created by a successful compilation

Deploying packages

Deploying applications that use packages

Distributing packages to other developers

Package collection files


Why use packages?

Topic groups	See also

Design-time packages simplify the tasks of distributing and installing custom components. Runtime packages, which are optional, offer several advantages over conventional programming. By compiling reused code into a runtime library, you can share it among applications. For example, all of your applications—including C++Builder itself—can access standard components through packages. Since the applications don’t have separate copies of the component library bound into their executables, the executables are much smaller—saving both system resources and hard disk storage. Moreover, packages allow faster compilation because only code unique to the application is compiled with each build.

Packages and standard DLLs


Packages and standard DLLs

Topic groups	See also

Create a package when you want to make a custom component that’s available through the IDE. Create a standard DLL when you want to build a library that can be called from any Windows application, regardless of the development tool used to build the application.

Note:	Packages share their global data with other modules in an application.


Runtime packages

Topic groups	See also

Runtime packages are deployed with C++Builder applications. They provide functionality when a user runs the application.

To run an application that uses packages, a computer must have both the application’s .EXE file and all the packages (.BPL files) that the application uses. The .BPL files must be on the system path for an application to use them. When you deploy an application, you must make sure that users have correct versions of any required .BPLs.

Using runtime packages in an application

Deciding which runtime packages to use

Custom packages


Using packages in an application
Using runtime packages in an application

Topic groups	See also

To use packages in an application,

1	Load or create a project in the IDE.

2	Choose Project|Options.

3	Choose the Packages tab.

4	Select the “Build with Runtime Packages” check box, and enter one or more package names in the edit box underneath. (Runtime packages associated with installed design-time packages are already listed in the edit box.) To add a package to an existing list, click the Add button and enter the name of the new package in the Add Runtime Package dialog. To browse from a list of available packages, click the Add button, then click the Browse button next to the Package Name edit box in the Add Runtime Package dialog.

If you edit the Search Path edit box in the Add Runtime Package dialog, you will be changing C++Builder’s global Library Path.

You do not need to include file extensions with package names. If you type directly into the Runtime Packages edit box, be sure to separate multiple names with semicolons. For example:

VCL40;VCLDB40;VCLDBX40

Packages listed in the Runtime Packages edit box are automatically linked to your application when you compile. Duplicate package names are ignored, and if the edit box is empty the application is compiled without packages.

Runtime packages are selected for the current project only. To make the current choices into automatic defaults for new projects, select the “Defaults” check box at the bottom of the dialog.

An application built with packages still must include header files for the packaged units that it uses. For example, an application that uses database controls needs the

#include "vcldb.h"

statement, even if it uses the VCLDB40 package. In generated source files, C++Builder creates these #include statements automatically.

Deciding which runtime packages to use


Dynamically loading packages

Topic groups	See also

To load a package at runtime, call the LoadPackage function. For example, the following code could be executed when a file is chosen in a file-selection dialog.

if (OpenDialog1->Execute())

  PackageList->Items->AddObject(FileName, Pointer(LoadPackage(Filename)));

To unload a package dynamically, call UnloadPackage. Be careful to destroy any instances of classes defined in the package and to unregister classes that were registered by it.


Deciding which runtime packages to use

Topic groups	See also

C++Builder ships with several precompiled runtime packages, including VCL40, which supply basic language and component support.

The VCL40 package contains the most commonly used components, system functions, and Windows interface elements. It does not include database or Windows 3.1 components, which are available in separate packages. The following table lists some runtime packages shipped with C++Builder and the units they contain.

Package	Units
VCL40.BPL	Ax, Buttons, Classes, Clipbrd, Comctrls, Commctrl, Commdlg, Comobj, Comstrs, Consts, Controls, Ddeml, Dialogs, Dlgs, Dsgnintf, Dsgnwnds, Editintf, Exptintf, Extctrls, Extdlgs, Fileintf, Forms, Graphics, Grids, Imm, IniFiles, Isapi, Isapi2, Istreams, Libhelp, Libintf, Lzexpand, Mapi, Mask, Math, Menu, Messages, Mmsystem, Nsapi, Ole2I, Oleconst, Olectnrs, Olectrls, Oledlg, Penwin, Printers, Proxies, Registry, Regstr, Richedit, Shellapi, Shlobj, Stdctrls, Stdvcl, Sysutils, Tlhelp32, Toolintf, Toolwin, Typinfo, Vclcom, Virtintf, Windows, Wininet, Winsock, Winspool, Winsvc
VCLX40.BPL	Checklst, Colorgrd, Ddeman, Filectrl, Mplayer, Outline, Tabnotbk, Tabs
VCLDB40.BPL	Bde, Bdeconst, Bdeprov, Db, Dbcgrids, Dbclient, Dbcommon, Dbconsts, Dbctrls, Dbgrids, Dbinpreq, Dblogdlg, Dbpwdlg, Dbtables, Dsintf, Provider, SMintf
VCLDBX40.BPL	Dblookup, Report
DSS40.BPL	Mxarrays, Mxbutton, Mxcommon, Mxconsts, Mxdb, Mxdcube, Mxdssqry, Mxgraph, Mxgrid, Mxpivsrc, Mxqedcom, Mxqparse, Mxqryedt, Mxstore, Mxtables, Mxqvb
QRPT40.BPL	Qr2const, Qrabout, Qralias, Qrctrls, Qrdatasu, Qrexpbld, Qrextra, Qrprev, Qrprgres, Qrprntr, Qrqred32, Quickrpt
TEE40.BPL	Arrowcha, Bubblech, Chart, Ganttch, Series, Teeconst, Teefunci, Teengine, Teeprocs, Teeshape
TEEDB40.BPL	Dbchart, Qrtee
TEEUI40.BPL	Areaedit, Arrowedi, Axisincr, Axmaxmin, Baredit, Brushdlg, Bubbledi, Custedit, Dbeditch, Editchar, Flineedi, Ganttedi, Ieditcha, Pendlg, Pieedit, Shapeedi, Teeabout, Teegally, Teelisb, Teeprevi, Teexport
VCLSMP40.BPL	Sampreg, Smpconst
To create a client/server database application that uses packages, you need at least two runtime packages: VCL40 and VCLDB40. If you want to use Outline components in your application, you also need VCLX40. To use these packages, choose Project|Options, select the Packages tab, and enter the following list in the Runtime Packages edit box.

VCL40;VCLDB40;VCLX40

Actually, you don’t have to include VCL40, because VCL40 is referenced in the Requires list of VCLDB40. Your application will compile just the same whether or not VCL40 is included in the Runtime Packages edit box.


Custom packages

Topic groups	See also

A custom package is either a BPL you code and compile yourself, or a precompiled package from a third-party vendor. To use a custom runtime package with an application, choose Project|Options and add the name of the package to the Runtime Packages edit box on the Packages page. For example, suppose you have a statistical package called STATS.BPL. To use it in an application, the line you enter in the Runtime Packages edit box might look like this:

VCL40;VCLDB40;STATS

If you create your own packages, you can add them to the list as needed.


Design-time packages

Topic groups	See also

Design-time packages are used to install components on the IDE’s Component palette and to create special property editors for custom components.

C++Builder ships with the following design-time component packages preinstalled in the IDE.

Package	Component palette pages
DCLSTD40.BPL	Standard, Additional, System, Win32, Dialogs
DCLTEE40.BPL	Additional (TChart component)
DCLDB40.BPL	Data Access, Data Controls
DCLMID40.BPL	Data Access (MIDAS)
DCL31W40.BPL	Win 3.1
DCLNET40.BPL NMFAST40.BPL	Internet
BCBSMP40.BPL	Samples
DCLOCX40.BPL	ActiveX
DCLQRT40.BPL	QReport
DCLDSS40.BPL	Decision Cube
IBSMP40.BPL	Samples (IBEventAlerter component)
DCLINT40.BPL	(International Tools—Resource DLL wizard)
RCEXPERT.BPL	(Resource Expert)
DBWEBXPRT.BPL	(Web Wizard)
MFCOWLWIZARD.BPL	(MFC/OWL Wizard)
These design-time packages work by calling runtime packages, which they reference in their Requires list. For example, DCLSTD40 references VCL40. DCLSTD40 itself contains additional functionality that makes most of the standard components available on the Component palette.

In addition to preinstalled packages, you can install your own component packages, or component packages from third-party developers, in the IDE. The DCLUSR40 design-time package is provided as a default container for new components.

Installing component packages


Installing component packages

Topic groups	See also

In C++Builder all components are installed in the IDE as packages. If you’ve written your own components, create and compile a package that contains them. Your component source code must follow the model described in Overview of component creation. If you are adding multiple units to a single package, each with components in them, you must make a single Register function for all components in a namespace that has the name of the package.

To install or uninstall your own components, or components from a third-party vendor, follow these steps:

1	If you are installing a new package, copy or move the package files to a local directory. If the package is shipped with .BPL, .BPI, .LIB, .OBJ, and header files be sure to copy all of them.

The directory where you store the .BPI and header files—and the .LIB or .OBJ files, if they are included with the distribution—must be in the C++Builder Library Path.

2	Choose Component|Install Packages from the IDE menu, or choose Project|Options and click the Packages tab.

3	A list of available packages appears under “Design packages”.

To install a package in the IDE, select the check box next to it.

To uninstall a package, deselect its check box.

To see a list of components included in an installed package, select the package and click Components.

To add a package to the list, click Add and browse in the Add Design Package dialog for the directory where the .BPL file resides (see step 1). Select a .BPL file and click Open.

To remove a package from the list, select the package and click Remove.

4	Click OK.

The components in the package are installed on the Component palette pages specified in the components’ RegisterComponents procedure, with the names they were assigned in the same procedure.

New projects are created with all available packages installed, unless you change the default settings. To make the current installation choices into the automatic default for new projects, check the Default check box at the bottom of the dialog box.

To remove components from the Component palette without uninstalling a package, select Component|Configure Palette, or select Tools|Environment Options and click the Palette tab. The Palette options tab lists each installed component along with the name of the Component palette page where it appears. Selecting any component and clicking Hide removes the component from the palette.


Creating and editing packages

Topic groups	See also

Creating a package involves specifying

A name for the package.

A list of other packages to be required by, or linked to, the new package.

A list of unit files to be contained by, or bound into, the package when it is compiled. The package is essentially a wrapper for these source-code units, which contain the functionality of the compiled .BPL. The Contains list is where you put the source-code units for custom components that you want to compile into a package.

A package is defined by a C++ source (.CPP) file and a special makefile whose name ends with the .BPK extension. These files are generated by the Package editor.

Creating a package

Editing an existing package

Package source files and makefiles

Packaging components

Understanding the structure of a package

Compiling packages


Creating a package

Topic groups	See also

To create a package, follow the procedure below. Refer to Understanding the structure of a package for more information about the steps outlined here.

1	Choose File|New, select the Package icon, and click OK.

2	The generated package is displayed in the Package editor.

3	The Package editor shows a Requires node and a Contains node for the new package.

4	To add a unit to the Contains list, click the Add to package speed button. In the Add unit page, type a .CPP file name in the Unit file name edit box, or click Browse to browse for the file, and then click OK. The unit you’ve selected appears under the Contains node in the Package editor. You can add additional units by repeating this step.

5	To add a package to the Requires list, click the Add to package speed button. In the Requires page, type a .BPI file name in the Package name edit box, or click Browse to browse for the file, and then click OK. (This adds USEPACKAGE("packageName.bpi") to the CPP file generated in step 1 above.) The package you’ve selected appears under the Requires node in the Package editor. You can add additional packages by repeating this step.

6	Click the Options speed button, and decide what kind of package you want to build.

To create a design-time–only package (a package that cannot be used at runtime), select the Designtime only radio button. (Or add the -Gpd linker switch to your BPK file: LFLAGS = ... -Gpd ....)

To create a runtime-only package (a package that cannot be installed), select the Runtime only radio button. (Or add the -Gpr linker switch to your BPK file: LFLAGS = ... -Gpr ....)

To create a package that is available at both design time and runtime, select the Designtime and runtime radio button.

7	In the Package editor, click the Compile package speed button to compile your package.


Editing an existing package

Topic groups	See also

There are several ways to open an existing package for editing.

Choose File|Open (or File|Reopen) and select a CPP or BPK file.

Choose Component|Install Packages, select a package from the Design Packages list, and click the Edit button.

When the Package editor is open, select one of the packages in the Requires node, right-click, and choose Open.

To edit a package’s description or set usage options, click the Options speed button in the Package editor and select the Description tab.

The Project Options dialog has a Default check box in the lower left corner. If you click OK when this box is checked, the options you’ve chosen are saved as default settings for new package projects. To restore the original defaults, delete or rename the DEFAULT.BPK file.


Package source files and makefiles

Topic groups	See also

Package source files have the .CPP extension. Package makefiles have the .BPK (Borland package) extension.

The makefile for a package called MyPack might look, in part, like this:

PROJECT = MyPack.bpl

OBJFILES = MyPack.obj Unit2.obj Unit3.obj

RESFILES =

RESDEPEN = $(RESFILES)

LIBFILES =

DEFFILE =

PACKAGES = vcl40.bpi vcl40dbx.bpi

In this case, MYPACK.CPP would include the following code:

USEPACKAGE("vcl40.bpi");

USEPACKAGE("vcl40dbx.bpi");

USEUNIT("Unit2.cpp");

USEUNIT("Unit3.cpp");

MyPack’s Contains list includes three units: MyPack itself, UNIT1, and UNIT2. MyPack’s Requires list includes VCL40 and VCL40DBX.

Packaging components


Packaging components

Topic groups	See also

The header-file declaration for a C++Builder component must include the predefined PACKAGE macro after the word class:

class PACKAGE MyComponent : ...

And in the CPP file where the component is defined, include the PACKAGE macro in the declaration of the Register function:

void __fastcall PACKAGE Register()

The PACKAGE macro expands to a statement that allows classes to be imported and exported from the resulting BPL file.

If you use the New Component wizard to create components (by choosing Component|New Component), C++Builder inserts the PACKAGE macro where it is needed. But if you have custom components from an older version of C++Builder, you’ll have to add PACKAGE manually in the two places just mentioned.


Understanding the structure of a package

Topic groups	See also

Naming packages

Package names must be unique within a project. If you name a package STATS, the Package editor generates a source file and makefile for it called “STATS.CPP” and “STATS.BPK”, respectively; the compiler generates an executable, a binary image, and (optionally) a static library called “STATS.BPL”, “STATS.BPI”, and “STATS.LIB”. To use the package in an application, add “STATS” to the Runtime Packages edit box (after choosing Project|Options and clicking the Packages tab).

The Requires list

The Requires list specifies other, external packages that are used by the current package. An external package included in the Requires list is automatically linked at compile time into any application that uses both the current package and one of the units contained in the external package.

If the unit files contained in your package make references to other packaged units, the other packages should appear in your package’s Requires list or you should add them. If the other packages are omitted from the Requires list, the compiler will import them into your package ‘implicitly contained units’.

Note:	Most packages that you create will require VCL40. Any package that depends on VCL units (including SysUtils) must list VCL40, or another package that requires VCL40, in its Requires list.

Avoiding circular package references

Packages cannot contain circular references in their Requires list. This means that

A package cannot reference itself in its own Requires list.

A chain of references must terminate without rereferencing any package in the chain. If package A requires package B, then package B cannot require package A; if package A requires package B and package B requires package C, then package C cannot require package A.

Handling duplicate package references

Duplicate references in a package’s Requires list—or in the Runtime Packages edit box—are ignored by the compiler. For programming clarity and readability, however, you should catch and remove duplicate package references.

The Contains list

The Contains list identifies the unit files to be bound into the package. If you are writing your own package, put your source code in CPP files and include them in the Contains list.

Avoiding redundant source code uses

A package cannot appear in the Contains list of another package.

All units included directly in a package’s Contains list, or included indirectly in any of those units, are bound into the package at compile time.

A unit cannot be contained (directly or indirectly) in more than one package used by the same application, including the C++Builder IDE. This means that if you create a package that contains one of the units in VCL40, you won’t be able to install your package in the IDE. To use an already-packaged unit file in another package, put the first package in the second package’s Requires list.


Compiling packages

Topic groups	See also

You can compile a package from the IDE or from the command line. To recompile a package by itself from the IDE,

1	Choose File|Open, select a package source file or makefile, and click Open.

2	When the editor opens, choose Project|Make or Project|Build.

You can insert compiler directives into your package source code. If you compile from the command line, several package-specific linker switches are available.

Package-specific compiler directives

Weak packaging

Using the command-line compiler and linker

Package files created by a successful compilation


Package-specific compiler directives

Topic groups	See also

The following table lists package-specific compiler directives that you can insert into your source code.

Directive	Purpose
#pragma package(smart_init)	Assures that packaged units are initialized in the order determined by their dependencies. (Included by default in package source file.)
#pragma package(smart_init, weak)	Packages unit “weakly”. See Weak packaging.(Put directive in unit source file.)


Weak packaging

Topic groups	See also

The #pragma package(smart_init, weak) directive affects the way an .OBJ file is stored in a package’s .BPI and .BPL files. (For information about files generated by the compiler, see Package files created by a successful compilation.) If #pragma package(smart_init, weak) appears in a unit file, the compiler omits the unit from BPLs when possible, and creates a non-packaged local copy of the unit when it is required by another application or package. A unit compiled with this directive is said to be “weakly packaged”.

For example, suppose you’ve created a package called PACK that contains only one unit, UNIT1. Suppose UNIT1 does not use any further units, but it makes calls to RARE.DLL. If you put #pragma package(smart_init, weak) in UNIT1.CPP when you compile your package, UNIT1 will not be included in PACK.BPL; you will not have to distribute copies of RARE.DLL with PACK. However, UNIT1 will still be included in PACK.BPI. If UNIT1 is referenced by another package or application that uses PACK, it will be copied from PACK.BPI and compiled directly into the project.

Now suppose you add a second unit, UNIT2, to PACK. Suppose that UNIT2 uses UNIT1. This time, even if you compile PACK with #pragma package(smart_init, weak) in UNIT1.CPP, the compiler will include UNIT1 in PACK.BPL. But other packages or applications that reference UNIT1 will use the (non-packaged) copy taken from PACK.BPI.

Note:	Unit files containing the #pragma package(smart_init, weak) directive must not have global variables.

#pragma package(smart_init, weak) is an advanced feature intended for developers who distribute their BPLs to other C++Builder programmers. It can help you to avoid distribution of infrequently used DLLs, and to eliminate conflicts among packages that may depend on the same external library.

For example, C++Builder’s PenWin unit references PENWIN.DLL. Most projects don’t use PenWin, and most computers don’t have PENWIN.DLL installed on them. For this reason, the PenWin unit is weakly packaged in VCL40. When you compile a project that uses PenWin and the VCL40 package, PenWin is copied from VCL40.BPI and bound directly into your project; the resulting executable is statically linked to PENWIN.DLL.

If PenWin were not weakly packaged, two problems would arise. First, VCL40 itself would be statically linked to PENWIN.DLL, and so you could not load it on any computer which didn’t have PENWIN.DLL installed. Second, if you tried to create a package that contained PenWin, a compiler error would result because the PenWin unit would be contained in both VCL40 and your package. Thus, without weak packaging, PenWin could not be included in standard distributions of VCL40.


Using the command-line compiler and linker

Topic groups	See also

 When you compile from the command line, use the -Tpp linker switch to ensure that the project is built as a package. Other package-specific switches are listed in the following table.

Switch	Purpose
-Tpp	Builds the project as a package. Included by default in package makefiles.
-Gi	Saves the generated BPI file. Included by default in package makefiles.
-Gpr	Generates a runtime-only package.
-Gpd	Generates a design-time–only package.
-Gl	Generates a .LIB file.
-D “description”	Saves the specified description with the package.
The -Gpr and -Gpd switches correspond to the Runtime Package and Design Package check boxes on the Description page of the Project Options dialog (available for package projects only); if neither -Gpr nor -Gpd is used, the resulting package works at both design time and runtime. The -D switch corresponds to the Description edit box on the same page. The -Gl switch corresponds to the Generate .LIB File check box on the Linker page of the Project Options dialog.


Package files created by a successful compilation

Topic groups	See also

To create a package, you compile a source (.CPP) file using a makefile with the .BPK extension. The base name of the source file should match the base name of the files generated by the compiler; that is, if the source file is called TRAYPAK.CPP, the makefile—TRAYPAK.BPK—should include

PROJECT = TrayPak.bpl

In this case, compiling the project creates a package called TRAYPAK.BPL.

The following table lists the files produced by the successful compilation of a package.

File extension	Contents
BPI	An import library. A single BPI (Borland package import library) file is created for each package. The base name for the BPI is the base name of the package source file.
OBJ	A binary image for a unit file contained in a package. One OBJ is created, when necessary, for each CPP file.
BPL	The runtime library. This file is a Windows DLL with C++Builder-specific features. The base name for the BPL is specified in the package makefile and should match the base name of the package source file.
LIB	A library for static linking. Generated only if -Gl (Generate .LIB File) is selected.


Deploying packages

Topic groups	See also

Deploying applications that use packages

When distributing an application that uses runtime packages, make sure that your users have the application’s .EXE file as well as all the library (.BPL or .DLL) files that the application calls. If the library files are in a different directory from the .EXE file, they must be accessible through the user’s Path. You may want to follow the convention of putting library files in the Windows\System directory. If you use InstallShield Express, your installation script can check the user’s system for any packages it requires before blindly reinstalling them.

Distributing packages to other developers

If you distribute runtime or design-time packages to other C++Builder developers, be sure to supply both .BPI and .BPL files as well as any required header files. To link components statically into their applications—that is, to build applications that don’t use runtime packages—developers will also need .LIB (or .OBJ) files for any packages you supply.


Package collection files

Topic groups	See also

Package collections (.DPC files) offer a convenient way to distribute packages to other developers. Each package collection contains one or more packages, including BPLs and any additional files you want to distribute with them. When a package collection is selected for IDE installation, its constituent files are automatically extracted from their .PCE container; the Installation dialog box offers a choice of installing all packages in the collection or installing packages selectively.

To create a package collection,

1	Choose Tools|Package Collection Editor to open the Package Collection editor.

2	Click the Add Package speed button, then select a BPL in the Select Package dialog and click Open. To add more BPLs to the collection, click the Add Package speed button again. A tree diagram on the left side of the Package editor displays the BPLs as you add them. To remove a package, select it and click the Remove Package speed button.

3	Select the Collection node at the top of the tree diagram. On the right side of the Package Collection editor, two fields will appear:

In the Author/Vendor Name edit box, you can enter optional information about your package collection that will appear in the Installation dialog when users install packages.

Under Directory List, list the default directories where you want the files in your package collection to be installed. Use the Add, Edit, and Delete buttons to edit this list. For example, suppose you want all source code files to be copied to the same directory. In this case, you might enter Source as a Directory Name with C:\MyPackage\Source as the Suggested Path. The Installation dialog box will display C:\MyPackage\Source as the suggested path for the directory.

4	In addition to BPLs, your package collection can contain .BPI, .OBJ, and .CPP (unit) files, documentation, and any other files you want to include with the distribution. Ancillary files are placed in file groups associated with specific packages (BPLs); the files in a group are installed only when their associated BPL is installed. To place ancillary files in your package collection, select a BPL in the tree diagram and click the Add File Group speed button; type a name for the file group. Add more file groups, if desired, in the same way. When you select a file group, new fields will appear on the right in the Package Collection editor,

In the Install Directory list box, select the directory where you want files in this group to be installed. The drop-down list includes the directories you entered under Directory List in step 3, above.

Check the Optional Group check box if you want installation of the files in this group to be optional.

Under Include Files, list the files you want to include in this group. Use the Add, Delete, and Auto buttons to edit the list. The Auto button allows you to select all files with specified extensions that are listed in the Contains list of the package; the Package Collection editor uses Delphi’s global Library Path to search for these files.

5	You can select installation directories for the packages listed in the Requires list of any package in your collection. When you select a BPL in the tree diagram, four new fields appear on the right side of the Package Collection editor:

In the Required Executables list box, select the directory where you want the .BPL files for packages listed in the Requires list to be installed. (The drop-down list includes the directories you entered under Directory List in step 3, above.) The Package Collection Editor searches for these files using Delphi’s global Library Path and lists them under Required Executable Files.

In the Required Libraries list box, select the directory where you want the .OBJ and .BPI files for packages listed in the Requires list to be installed. (The drop-down list includes the directories you entered under Directory List in step 3, above.) The Package Collection Editor searches for these files using C++Builder’s global Library Path and lists them under Required Library Files.

6	To save your package collection source file, choose File|Save. Package collection source files should be saved with the .PCE extension.

7	To build your package collection, click the Compile speed button. The Package Collection editor generates a .DPC file with the same name as your source (.PCE) file. If you have not yet saved the source file, the editor queries you for a file name before compiling.

To edit or recompile an existing .PCE file, select File|Open in the Package Collection editor.


Creating international applications: Overview
Creating international applications

Topic groups	See also

This topic discusses guidelines for writing applications that you plan to distribute to an international market. By planning ahead, you can reduce the amount of time and code necessary to make your application function in its foreign market as well as in its domestic market.

The following topics are discussed in this section:

Internationalization and localization

Internationalizing applications

Localizing applications


Internationalization and localization

Topic groups	See also

To create an application that you can distribute to foreign markets, there are two major steps that need to be performed:

Internationalization

Localization


Internationalization

Topic groups	See also

Internationalization is the process of enabling your program to work in multiple locales. A locale is the user’s environment, which includes the cultural conventions of the target country as well as the language. Windows supports a large set of locales, each of which is described by a language and country pair.


Localization

Topic groups	See also

Localization is the process of translating an application to function in a specific locale. In addition to translating the user interface, localization may include functionality customization. For example, a financial application may be modified to be aware of the different tax laws in different countries.


Internationalizing applications

Topic groups	See also

It is not difficult to create internationalized applications. You need to complete the following steps:

1	You must enable your code to handle strings from international character sets.

2	You need to design your user interface so that it can accommodate the changes that result from localization.

3	You need to isolate all resources that need to be localized.


Enabling application code

Topic groups	See also

You must make sure that the code in your application can handle the strings it will encounter in the various target locales. To do this, you must consider the following:

Character sets

OEM and ANSI character sets

Double byte character sets

Wide characters

Locale-specific features


Character sets

Topic groups	See also

The United States edition of Windows uses the ANSI Latin-1 (1252) character set. However, other editions of Windows use different character sets. For example, the Japanese version of Windows uses the Shift-Jis character set (code page 932), which represents Japanese characters as 1- or 2-byte character codes.


OEM and ANSI character sets

Topic groups	See also

It is sometimes necessary to convert between the Windows character set (ANSI) and the character set specified by the code page of the user’s machine (called the OEM character set).


Double byte character sets

Topic groups	See also

The ideographic character sets used in Asia cannot use the simple 1:1 mapping between characters in the language and the one byte (8-bit) char type. These languages have too many characters to be represented using the 1-byte char. Instead, characters are represented by a mix of 1- and 2-byte character codes.

The first byte of every 2-byte character code is taken from a reserved range that depends on the specific character set. The second byte can sometimes be the same as the character code for a separate 1-byte character, or it can fall in the range reserved for the first byte of 2-byte characters. Thus, the only way to tell whether a particular byte in a string represents a single character or part of a 2-byte character is to read the string, starting at the beginning, parsing it into 2-byte characters when a lead byte from the reserved range is encountered.

When writing code for Asian locales, you must be sure to handle all string manipulation using functions that are enabled to parse strings into 1- and 2-byte characters. See International API for a list of the RTL functions that are enabled to work with multibyte characters.

Remember that the length of the strings in bytes does not necessarily correspond to the length of the string in characters. Be careful not to truncate strings by cutting a 2-byte character in half. Do not pass characters as a parameter to a function or procedure, since the size of a character can’t be known up front. Instead, always pass a pointer to a character or a string.


Wide characters

Topic groups	See also

One approach to working with ideographic character sets is to convert all characters to a wide character encoding scheme such as Unicode. Wide characters are two bytes instead of one, so that the character set can represent many more different characters.

Using a wide character encoding scheme has the advantage that you can make many of the usual assumptions about strings that do not work for MBCS systems. There is a direct relationship between the number of bytes in the string and the number of characters in the string. You do not need to worry about cutting characters in half or mistaking the second half of a character for the start of a different character.

The biggest disadvantage of working with wide characters is that Windows 95 only supports a few wide character API function calls. Because of this, the VCL components represent all string values as single byte or MBCS strings. Translating between the wide character system and the MBCS system every time you set a string property or read its value would require tremendous amounts of extra code and slow your application down. However, you may want to translate into wide characters for some special string processing algorithms that need to take advantage of the 1:1 mapping between characters and WideChars.

See International API for a list of the RTL functions that are enabled to work with Unicode characters.


Including bi-directional functionality in applications

Topic groups	See also

Some languages do not follow the left to right reading order commonly found in western languages, but rather read words right to left and numbers left to right. These languages are termed bi-directional (BiDi) because of this separation. The most common bi-directional languages are Arabic and Hebrew, although other Middle East languages are also bi-directional.

The VCL provides support for applications developed for bi-directional localization by using two properties to the VCL: BiDiMode and ParentBiDiMode. The following table lists the VCL objects that have these properties:

Component palette page	VCL object
Standard	TButton
	TCheckBox
	TComboBox
	TEdit
	TGroupBox
	TLabel
	TListBox
	TMainMenu
	TMemo
	TPanel
	TPopupMenu
	TRadioButton
	TRadioGroup
	TScrollBar
Additional	TBitBtn
	TCheckListBox
	TDrawGrid
	TMaskEdit
	TScrollBox
	TSpeedButton
	TStaticLabel
	TStringGrid
Win32	TDateTimePicker
	THeaderControl
	TListView
	TMonthCalendar
	TPageControl
	TRichEdit
	TStatusBar
	TTabControl
Data Controls	TDBCheckBox
	TDBComboBox
	TDBEdit
	TDBGrid
	TDBListBox
	TDBLookupComboBox
	TDBLookupListBox
	TDBMemo
	TDBRadioGroup
	TDBRichEdit
	TDBText
QReport	TQRDBText
	TQRExpr
	TQRLabel
	TQRMemo
	TQRSysData
Other classes	TApplication (has no ParentBiDiMode)
	TForm
	THintWindow (has no ParentBiDiMode)
	TStatusPanel
	THeaderSection
Note:	THintWindow picks up the BiDiMode of the control that activated the hint.


Bi-directional properties

Topic groups	See also

The property BiDiMode is a new enumerated type, TBiDiMode, with four states: bdLeftToRight, bdRightToLeft, bdRightToLeftNoAlign, and bdRightToLeftReadingOnly.

bdLeftToRight

bdLeftToRight draws text using left to right reading order, and the alignment and scroll bars are not changed. For instance, when entering right to left text, such as Arabic or Hebrew, the cursor goes into push mode and the text is entered right to left. Latin text, such as English or French, is entered left to right. bdLeftToRight is the default value.

bdRightToLeft

bdRightToLeft draws text using right to let reading order, the alignment is changed and the scroll bar is moved. Text is entered as normal for right-to-left languages such as Arabic or Hebrew. When the keyboard is changed to a Latin language, the cursor goes into push mode and the text is entered left-to-right.

bdRightToLeftNoAlign

bdRightToLeftNoAlign draws text using right to left reading order, the alignment is not changed, and the scroll bar is moved.

bdRightToLeftReadingOnly

bdRightToLeftReadingOnly draws text using right to left reading order, and the alignment and scroll bars are not changed.


ParentBiDiMode property

Topic groups	See also

ParentBiDiMode is a Boolean property. When True (the default) the control looks to its parent to determine what BiDiMode to use. If the control is a TForm object, the form uses the BiDiMode setting from Application. If all the ParentBiDiMode properties are True, when you change Application’s BiDiMode property, all forms and controls in the project are updated with the new setting.


FlipChildren method

Topic groups	See also

The FlipChildren method allows you to flip the position of a container control’s children. Container controls are controls that can accept other controls, such as TForm, TPanel, and TGroupbox. FlipChildren has a single boolean parameter, AllLevels. When False, only the immediate children of the container control are flipped. When True, all the levels of children in the container control are flipped.

C++Builder flips the controls by changing the Left property and the alignment of the control. If a control’s left side is five pixels from the left edge of its parent control, after it is flipped the edit control’s right side is five pixels from the right edge of the parent control. If the edit control is left aligned, calling FlipChildren will make the control right aligned.

To flip a control at design-time select Edit|Flip Children and select either All or Selected, depending on whether you want to flip all the controls, or just the children of the selected control. You can also flip a control by selecting the control on the form, right-clicking, and selecting Flip Children from the context menu.

Note:	Selecting an edit control and issuing a Flip Children|Selected command does nothing. This is because edit controls are not containers.


Additional methods

Topic groups	See also

There are several other methods useful for developing applications for bi-directional users.

Method	Description
OkToChangeFieldAlignment	Used with database controls. Checks to see if the alignment of a control can be changed.
DBUseRightToLeftAlignment	A wrapper for database controls for checking alignment.
ChangeBiDiModeAlignment	Changes the alignment parameter passed to it. No check is done for BiDiMode setting, it just converts left alignment into right alignment and vice versa, leaving center-aligned controls alone.
IsRightToLeft	Returns True if any of the right to left options are selected. If it returns False the control is in left to right mode.
UseRightToLeftReading	Returns True if the control is using right to left reading.
UseRightToLeftAlignment	Returns True if the control is using right to left alignment. It can be overriden for customization.
UseRightToLeftScrollBar	Returns True if the control is using a left scroll bar.
DrawTextBiDiModeFlags	Returns the correct draw text flags for the BiDiMode of the control.
DrawTextBiDiModeFlagsReadingOnly	Returns the correct draw text flags for the BiDiMode of the control, limiting the flag to its reading order.
AddBiDiModeExStyle	Adds the appropriate ExStyle flags to the control that is being created.


Locale-specific features

Topic groups	See also

You can add extra features to your application for specific locales. In particular, for Asian language environments, you may want your application to control the input method editor (IME) that is used to convert the keystrokes typed by the user into character strings.

VCL components offer you support in programming the IME. Most windowed controls that work directly with text input have an ImeName property that allows you to specify a particular IME that should be used when the control has input focus. They also provide an ImeMode property that specifies how the IME should convert keyboard input. ImeName introduces several protected methods that you can use to control the IME from classes you define. In addition, the global Screen variable provides information about the IMEs available on the user’s system.

The global Screen variable also provides information about the keyboard mapping installed on the user’s system. You can use this to obtain locale-specific information about the environment in which your application is running.


Designing the user interface

Topic groups	See also

When creating an application for several foreign markets, it is important to design your user interface so that it can accommodate the changes that occur during translation.

The following topics are discussed in this section:

Text

Graphic images

Formats and sort order

Keyboard mappings


Text

Topic groups	See also

All text that appears in the user interface must be translated. English text is almost always shorter than its translations. Design the elements of your user interface that display text so that there is room for the text strings to grow. Create dialogs, menus, status bars, and other user interface elements that display text so that they can easily display longer strings. Avoid abbreviations—they do not exist in languages that use ideographic characters.

Short strings tend to grow in translation more than long phrases. The following table provides a rough estimate of how much expansion you should plan for given the length of your English strings:

Length of English string (in characters)	Expected increase
1-5	100%
6-12	80%
13-20	60%
21-30	40%
31-50	20%
over 50	10%


Graphic images

Topic groups	See also

Ideally, you will want to use images that do not require translation. Most obviously, this means that graphic images should not include text, which will always require translation. If you must include text in your images, it is a good idea to use a label object with a transparent background over an image rather than including the text as part of the image.

There are other considerations when creating graphic images. Try to avoid images that are specific to a particular culture. For example, mailboxes in different countries look very different from each other. Religious symbols are not appropriate if your application is intended for countries that have different dominant religions. Even color can have different symbolic connotations in different cultures.


Formats and sort order

Topic groups	See also

The date, time, number, and currency formats used in your application should be localized for the target locale. If you use only the Windows formats, there is no need to translate formats, as these are taken from the user’s Windows Registry. However, if you specify any of your own format strings, be sure to declare them as resourced constants so that they can be localized.

The order in which strings are sorted also varies from country to country. Many European languages include diacritical marks that are sorted differently, depending on the locale. In addition, in some countries, 2-character combinations are treated as a single character in the sort order. For example, in Spanish, the combination ch is sorted like a single unique letter between c and d. Sometimes a single character is sorted as if it were two separate characters, such as the German eszett.


Keyboard mappings

Topic groups	See also

Be careful with key-combinations shortcut assignments. Not all the characters available on the US keyboard are easily reproduced on all international keyboards. Where possible, use number keys and function keys for shortcuts, as these are available on virtually all keyboards.


Isolating resources

Topic groups	See also

The most obvious task in localizing an application is translating the strings that appear in the user interface. To create an application that can be translated without altering code everywhere, the strings in the user interface should be isolated into a single module. C++Builder automatically creates a .DFM file that contains the resources for your menus, dialogs, and bitmaps.

In addition to these obvious user interface elements, you will need to isolate any strings, such as error messages, that you present to the user. String resources are not included in the .DFM file but you can isolate them into an .RC file.

For information on using resource DLLs in your applications see "Creating resource DLLs” and "Using resource DLLs.”


Creating resource DLLs

Topic groups	See also

Isolating resources simplifies the translation process. The next level of resource separation is the creation of a resource DLL. A resource DLL contains all the resources and only the resources for a program. Resource DLLs allow you to create a program that supports many translations simply by swapping the resource DLL. Thus simplifying deployment of many translations.

Use the Resource DLL wizard to create a resource DLL for your program. The Resource DLL wizard requires an open, saved, compiled project. It will create an RC file that contains the string tables from used RC files and resourcestring strings of the project, and generate a project for a resource only DLL that contains the relevant forms and the created RES file. The RES file is compiled from the new RC file.

You should create a resource DLL for each translation you want to support. Each resource DLL should have a file name extension specific to the target locale. The first two characters indicate the target language, and the third character indicates the country of the locale. If you use the Resource DLL wizard, this is handled for you. Otherwise, use the following code obtain the locale code for the target translation:

/* This callback fills a listbox with the strings and their associated languages and countries*/

BOOL __stdcall EnumLocalesProc(char* lpLocaleString)

{

  AnsiString LocaleName, LanguageName, CountryName;

  LCID lcid;

  lcid = StrToInt("$" + AnsiString(lpLocaleString));

  LocaleName = GetLocaleStr(lcid, LOCALE_SABBREVLANGNAME, "");

  LanguageName = GetLocaleStr(lcid, LOCALE_SNATIVELANGNAME, "");

  CountryName = GetLocaleStr(lcid, LOCALE_SNATIVECTRYNAME, "");

  if (lstrlen(LocaleName.c_str()) > 0)

    Form1->ListBox1->Items->Add(LocaleName + ":" + LanguageName + "-" + CountryName);

  return TRUE;

}

/* This call causes the callback to execute for every locale */

  EnumSystemLocales((LOCALE_ENUMPROC)EnumLocalesProc, LCID_SUPPORTED);


Using resource DLLs

Topic groups	See also

The executable, DLLs, and packages that make up your application contain all the necessary resources. However, to replace those resources by localized versions, you need only ship your application with localized resource DLLs that have the same name as your EXE, DLL, or BPL files.

When your application starts up, it checks the locale of the local system. If it finds any resource DLLs with the same name as the EXE, DLL, or BPL files it is using, it checks the extension on those DLLs. If the extension of the resource module matches the language and country of the system locale, your application will use the resources in that resource module instead of the resources in the executable, DLL, or package. If there is not a resource module that matches both the language and the country, your application will try to locate a resource module that matches just the language. If there is no resource module that matches the language, your application will use the resources compiled with the executable, DLL, or package.

If you want your application to use a different resource module than the one that matches the locale of the local system, you can set a locale override entry in the Windows registry. Under the HKEY_CURRENT_USER\Software\Borland\Locales key, add your application’s path and file name as a string value and set the data value to the extension of your resource DLLs. At startup, the application will look for resource DLLs with this extension before trying the system locale. Setting this registry entry allows you to test localized versions of your application without changing the locale on your system.

For example, the following procedure can be used in an install or setup program to set the registry key value that indicates the locale to use when loading C++Builder applications:

void SetLocalOverrides(char* FileName, char* LocaleOverride)

{

  HKEY Key;

  const char* LocaleOverrideKey = "Software\\Borland\\Locales";

  if (RegOpenKeyEx(HKEY_CURRENT_USER, LocaleOverrideKey, 0, KEY_ALL_ACCESS, &Key)

        == ERROR_SUCCESS) {

    if (lstrlen(LocaleOverride) == 3)

      RegSetValueEx(Key, FileName, 0, REG_SZ, (const BYTE*)LocaleOverride, 4);

    RegCloseKey(Key);

  }

}

Within your application, use the global FindResourceHInstance function to obtain the handle of the current resource module. For example:

LoadString(FindResourceHInstance(HInstance), IDS_AmountDueName, szQuery, sizeof(szQuery));

You can ship a single application that adapts itself automatically to the locale of the system it is running on, simply by providing the appropriate resource DLLs.


Dynamic switching of resource DLLs

Topic groups	See also

In addition to locating a resource DLL at application startup, it is possible to switch resource DLLs dynamically at runtime. To add this functionality to your own applications, you need to include the ReInit unit in your project. (ReInit is located in the Richedit sample in the Demos directory.) To switch languages, you should call LoadNewResourceModule, passing the LCID for the new language, and then call ReinitializeForms.

For example, the following code switches the interface language to French:

const  FRENCH = (SUBLANG_FRENCH << 10) | LANG_FRENCH;

if (LoadNewResourceModule(FRENCH))

  ReinitializeForms();

The advantage of this technique is that the current instance of the application and all of its forms are used. It is not necessary to update the registry settings and restart the application or reacquire resources required by the application, such as logging in to database servers.

When you switch resource DLLs the properties specified in the new DLL overwrite the properties in the running instances of the forms.

Note:	Any changes made to the form properties at runtime will be lost. Once the new DLL is loaded, default values are not reset. Avoid code that assumes that the form objects are reinitialized to the their startup state, apart from differences due to localization.


Localizing applications

Topic groups	See also

Once your application is internationalized, you can create localized versions for the different foreign markets in which you want to distribute it.

Ideally your resources have been isolated into a resource DLL that contains DFM files and a RES file. You can then open the forms in the IDE and translate the relevant properties.

Note:	In a resource DLL project, you can not add or delete components. However, it is possible to change properties that could cause runtime errors. Only modify the properties that should be translated.

You can open the RC file and translate relevant strings. Use the StringTable editor by opening the RC file from the Project Manager.


Deploying applications: Overview
Deploying applications

Topic groups	See also

Once your C++Builder application is up and running, you can deploy it. That is, you can make it available for others to run. A number of steps must be taken to deploy an application to another computer so that the application is completely functional. The steps required by a given application vary, depending on the type of application. The following sections describe those steps for deploying applications:

Deploying general applications

Deploying database applications

Deploying Web applications

Programming for varying host environments

Software license requirements


Deploying general applications

Topic groups	See also

Beyond the executable file, an application may require a number of supporting files, such as DLLs, package files, and helper applications. In addition, the Windows registry may need to contain entries for an application, from specifying the location of supporting files to simple program settings. The process of copying an application’s files to a computer and making any needed registry settings can be automated by an installation program, such as InstallShield Express. These are the main deployment concerns common to nearly all types of applications:

Using installation programs

Identifying application files

Helper applications

Dll locations

C++Builder applications that access databases and those that run across the Web require additional installation steps beyond those that apply to general applications.For additional information on installing database applications, see Deploying database applications. For more information on installing Web applications, see Deploying Web applications. For more information on installing ActiveX controls, see Deploying an ActiveX control on the Web.


Using installation programs

Topic groups	See also

Simple C++Builder applications that consist of only an executable file are easy to install on a target computer. Just copy the executable file onto the computer. However, more complex applications that comprise multiple files require more extensive installation procedures. These applications require dedicated installation programs.

Setup toolkits automate the process of creating installation programs, often without needing to write any code. Installation programs created with Setup toolkits perform various tasks inherent to installing C++Builder applications, including: copying the executable and supporting files to the host computer, making Windows registry entries, and installing the Borland Database Engine for database applications.

InstallShield Express is a setup toolkit that is bundled with C++Builder. InstallShield Express is certified for use with C++Builder and the Borland Database Engine. InstallShield Express is not automatically installed when C++Builder is installed, and must be manually installed to be used to create installation programs. Run the installation program from the C++Builder CD to install InstallShield Express. For more information on using InstallShield Express to create installation programs, see the InstallShield Express online help.

Other setup toolkits are available, however, you should only use those certified to deploy the Borland Database Engine.


Identifying application files

Topic groups	See also

Besides the executable file, a number of other files may need to be distributed with an application.

Application files, listed by file name extension

Package files

ActiveX controls


Application files, listed by file name extension

Topic groups	See also

The following types of files may need to be distributed with an application.

Type	File name extension
Program files	.EXE and .DLL
Package files	.BPL and .BCP
Help files	.HLP, .CNT, and .TOC (if used)
ActiveX files	.OCX (sometimes supported by a DLL)
Local table files	.DBF, .MDX, .DBT, .NDX, .DB, .PX, .Y*, .X*, .MB, .VAL, .QBE


Package files

Topic groups	See also

If the application uses runtime packages, those package files need to be distributed with the application. InstallShield Express handles the installation of package files the same as DLLs, copying the files and making necessary entries in the Windows registry. Borland recommends installing the runtime package files supplied by Borland in the Windows\System directory. This serves as a common location so that multiple applications would have access to a single instance of the files. For packages you created, it is recommended that you install them in the same directory as the application. Only the .BPL files need to be distributed.

If you are distributing packages to other developers, supply both the .BPL and the .BCP files.


ActiveX controls

Topic groups	See also

Certain components bundled with C++Builder are ActiveX controls. The component wrapper is linked into the application’s executable file (or a runtime package), but the .OCX file for the component also needs to be deployed with the application. These components include

Chart FX, copyright SoftwareFX Inc.

VisualSpeller Control, copyright Visual Components, Inc.

Formula One (spreadsheet), copyright Visual Components, Inc.

First Impression (VtChart), copyright Visual Components, Inc.

Graph Custom Control, copyright Bits Per Second Ltd.

ActiveX controls of your own creation need to be registered on the deployment computer before use. Installation programs such as InstallShield Express automate this registration process. To manually register an ActiveX control, use the TRegSvr demo application or the Microsoft utility REGSRV32.EXE (not included with all Windows versions).

DLLs that support an ActiveX control also need to be distributed with an application.


Helper applications

Topic groups	See also

Helper applications are separate programs without which your C++Builder application would be partially or completely unable to function. Helper applications may be those supplied with Windows, by Borland, or they might be third-party products. An example of a helper application is the InterBase utility program Server Manager, which administers InterBase databases, users, and security.

If an application depends on a helper program, be sure to deploy it with your application, where possible. Distribution of helper programs may be governed by redistribution license agreements. Consult the documentation for the helper for specific information.


DLL locations

Topic groups	See also

You can install .DLL files used only by a single application in the same directory as the application. DLLs that will be used by a number of applications should be installed in a location accessible to all of those applications. A common convention for locating such community DLLs is to place them either in the Windows or the Windows\System directory. A better way is to create a dedicated directory for the common .DLL files, similar to the way the Borland Database Engine is installed.


Deploying database applications

Topic groups	See also

Applications that access databases involve special installation considerations beyond copying the application’s executable file onto the host computer. Database access is most often handled by a separate database engine, the files of which cannot be linked into the application’s executable file. The data files, when not created beforehand, must be made available to the application. Multi-tier database applications require even more specialized handling on installation, because the files that make up the application are typically located on multiple computers. Two ways of including database access are

Providing the database engine

Multi-tiered Distributed Application Services (MIDAS)


Providing the database engine

Topic groups	See also

Database access for an application is provided by various database engines. An application can use the Borland Database Engine or a third-party database engine. SQL Links is provided (not available in all versions) to enable native access to SQL database systems. The following sections describe installation of the database access elements of an application:

Borland Database Engine

Third-party database engines

SQL Links

Borland Database Engine

Third-party database engines

SQL Links


Borland Database Engine

Topic groups	See also

For standard C++Builder data components to have database access, the Borland Database Engine (BDE) must be present and accessible. See BDEDEPLOY.TXT for specific rights and limitations on redistributing the BDE.

Borland recommends use of InstallShield Express (or other certified installation program) for installing the BDE. InstallShield Express will create the necessary registry entries and define any aliases the application may require. Using a certified installation program to deploy the BDE files and subsets is important because:

Improper installation of the BDE or BDE subsets can cause other applications using the BDE to fail. Such applications include not only Borland products, but many third-party programs that use the BDE.

Under Windows 95 and Windows NT, BDE configuration information is stored in the Windows registry instead of .INI files, as was the case under 16-bit Windows. Making the correct entries and deletions for install and uninstall is a complex task.

It is possible to install only as much of the BDE as an application actually needs. For instance, if an application only uses Paradox tables, it is only necessary to install that portion of the BDE required to access Paradox tables. This reduces the disk space needed for an application. Certified installation programs, like InstallShield Express, are capable of performing partial BDE installations. Be sure to leave BDE system files that are not used by the deployed application, but that are needed by other programs.


Third-party database engines

Topic groups	See also

You can use third-party database engines to provide database access for C++Builder applications. Consult the documentation or vendor for the database engine regarding redistribution rights, installation, and configuration.


SQL Links

Topic groups	See also

SQL Links provides the drivers that connect an application (through the Borland Database Engine) with the client software for an SQL database. See DEPLOY.TXT for specific rights and limitations on redistributing SQL Links. As is the case with the Borland Database Engine (BDE), SQL Links must be deployed using InstallShield Express (or other certified installation program).

Note:	SQL Links only connects the BDE to the client software, not to the SQL database itself. It is still necessary to install the client software for the SQL database system used. See the documentation for the SQL database system or consult the vendor that supplies it for more information on installing and configuring client software.

The following table shows the names of the driver and configuration files SQL Links uses to connect to the different SQL database systems. These files come with SQL Links and are redistributable in accordance with the C++Builder license agreement.

Vendor	Redistributable files
Oracle 7	SQLORA32.DLL and SQL_ORA.CNF
Oracle8	SQLORA8.DLL and SQL_ORA8.CNF
Sybase Db-Lib	SQLSYB32.DLL and SQL_SYB.CNF
Sybase Ct-Lib	SQLSSC32.DLL and SQL_SSC.CNF
Microsoft SQL Server	SQLMSS32.DLL and SQL_MSS.CNF
Informix 7	SQLINF32.DLL and SQL_INF.CNF
Informix 9	SQLINF9.DLL and SQL_INF9.CNF
DB/2	SQLDB232.DLL and SQL_DB2.CNF
InterBase	SQLINT32.DLL and SQL_INT.CNF
Install SQL Links using InstallShield Express or other certified installation program. For specific information concerning the installation and configuration of SQL Links, see the help file SQLLNK32.HLP, by default installed into the main BDE directory.


Multi-tiered Distributed Application Services (MIDAS)

Topic groups	See also

Multi-tiered Distributed Application Services (MIDAS) consists of the Business Object Broker, OLEnterprise, the Remote DataBroker, and the ConstraintBroker Manager (SQL Explorer). MIDAS provides multi-tier database capability to C++Builder applications.

Handle the installation of the executable and related files for a multi-tier application the same as for general applications. Some of the files that comprise MIDAS may need to be installed on the client computer and others on the server computer.For general application installation information, see Deploying general applications. See the text file LICENSE.TXT on the MIDAS CD and the C++Builder file DEPLOY.TXT for specific information regarding licensing and redistribution rights for MIDAS.

For the Remote DataBroker and ConstraintBroker portions of MIDAS, the file DBCLIENT.DLL must be installed onto the client computer and registered with Windows. On the server computer, the files DBCLIENT.DLL and STDVCL40.DLL must be installed and registered for the Remote DataBroker and DBEXPLOR.EXE for the ConstraintBroker. Installation programs such as InstallShield Express automate the process of registering these DLLs. To manually register the DLLs, use the TRegSvr demo application or the Microsoft utility REGSRV32.EXE (not included with all Windows versions).

The MIDAS deployment CD provides install programs for the client and server portions of OLEnterprise and the Business ObjectBroker. Use only the Setup Launcher on the MIDAS CD to install OLEnterprise.

Following is a list of the minimum required files to be installed onto the server machine.

UNINSTALL.EXE	OBJFACT.ICO	W32PTHD.DLL	NBASE.IDL
LICENSE.TXT	ODEBKN40.DLL	RPMARN40.DLL	OBJX.EXE
README.TXT	ODECTN40.DLL	RPMAWN40.DLL	OLECFG.EXE
OLENTER.HLP	RPMEGN40.DLL	RPMCBN40.DLL	OLEWAN40.CAB
OLENTER.CNT	ODEDIN40.DLL	RPMCPN40.DLL	OLENTEXP.EXE
FILELIST.TXT	ODEEGN40.DLL	BROKER.EXE	OLENTEXP.HLP
SETLOG.TXT	ODELTN40.DLL	RPMFEN40.DLL	OLENTEXP.CNT
SETLOG.EXE	LIBAVEMI.DLL	RPMUTN40.DLL	BRKCP.EXE
OBJPING.EXE	OLEAAN40.DLL	RPMFE.CAT	BROKER.ICO
OBJFACT.EXE	OLERAN40.DLL	EXPERR.CAT
Following is a list of the required files to be installed onto the client machine.

NBASE.IDL	ODEN40.DLL	RPMFEN40.DLL	OLENTEXP.EXE
ODECTN40.DLL	RPMARN40.DLL	RPMUTN40.DLL	SETLOG.EXE
ODEDIN40.DLL	RPMAWN40.DLL	OLERAN40.DLL	OLECFG.EXE
ODEEGN40.DLL	RPMCBN40.DLL	OLEAAN40.DLL	W32PTHD.DLL
ODELTN40.DLL	RPMCPN40.DLL	OLEWAN40.CAB
ODEMSG.DLL	RPMEGN40.DLL	OBJX.EXE


Deploying Web applications

Topic groups	See also

Some C++Builder applications are designed to be run over the World Wide Web, such as those in the form of Server-side Extension (ISAPI) DLLs, CGI applications, and ActiveForms.

The steps for installing Web applications are the same as those for general applications, except the application’s files are deployed on the Web server.For information on installing general applications, seeDeploying general applications .

Here are some special considerations for deploying Web applications:

For database applications, the Borland Database Engine (or alternate database engine) is installed along with the application files on the Web server.

Security for the directories must not be so high that access to application files, the BDE, or database files is not possible.

The directory containing an application must have read and execute attributes.

The application should not use hard-coded paths for accessing database or other files.

The location of an ActiveX control is indicated by the CODEBASE parameter of the <OBJECT> HTML tag.


Programming for varying host environments

Topic groups	See also

Due to the nature of the Windows environment, there are a number of factors that vary with user preference or configuration. The following factors can affect an application deployed to another computer:

Screen resolutions and color depths

Fonts

WindowsVersions


Screen resolutions and color depths

Topic groups	See also

The size of the Windows desktop and number of available colors on a computer is configurable and dependent on the hardware installed. These attributes are also likely to differ on the deployment computer compared to those on the development computer.

An application’s appearance (window, object, and font sizes) on computers configured for different screen resolutions can be handled in various ways:

Design the application for the lowest resolution users will have (typically, 640x480). Take no special actions to dynamically resize objects to make them proportional to the host computer’s screen display. Visually, objects will appear smaller the higher the resolution is set.

Design using any screen resolution on the development computer and, at runtime, dynamically resize all forms and objects proportional to the difference between the screen resolutions for the development and deployment computers (a screen resolution difference ratio).

Design using any screen resolution on the development computer and, at runtime, dynamically resize only the application’s forms. Depending on the location of visual controls on the forms, this may require the forms be scrollable for the user to be able to access all controls on the forms.

The following topics are discussed in this section:

Considerations when not dynamically resizing

Considerations when dynamically resizing forms and controls

Accomodating varying color depths


Considerations when not dynamically resizing

Topic groups	See also

If the forms and visual controls that make up an application are not dynamically resized at runtime, design the application’s elements for the lowest resolution. Otherwise, the forms of an application run on a computer configured for a lower screen resolution than the development computer may overlap the boundaries of the screen.

For example, if the development computer is set up for a screen resolution of 1024x768 and a form is designed with a width of 700 pixels, not all of that form will be visible within the Windows desktop on a computer configured for a 640x480 screen resolution.


Considerations when dynamically resizing forms and controls

Topic groups	See also

If the forms and visual controls for an application are dynamically resized, accommodate all aspects of the resizing process to ensure optimal appearance of the application under all possible screen resolutions. Here are some factors to consider when dynamically resizing the visual elements of an application:

The resizing of forms and visual controls is done at a ratio calculated by comparing the screen resolution of the development computer to that of the computer onto which the application installed. Use a constant to represent one dimension of the screen resolution on the development computer: either the height or the width, in pixels. Retrieve the same dimension for the user’s computer at runtime using the Screen object’s Height or  Width property. Divide the value for the development computer by the value for the user’s computer to derive the difference ratio between the two computers’ screen resolutions.

Resize the visual elements of the application (forms and controls) by reducing or increasing the size of the elements and their positions on forms. This resizing is proportional to the difference between the screen resolutions on the development and user computers. Resize and reposition visual controls on forms automatically by setting the form’s Scaled property to true and calling  its ScaleBy method. The ScaleBy method does not change the form’s height and width, though. Do this manually by multiplying the current values for the Height and Width properties by the screen resolution difference ratio.

The controls on a form can be resized manually, instead of automatically with the TWincontrol::ScaleBy method, by referencing each visual control in a loop and setting its dimensions and position. The Height and Width property values for visual controls are multiplied by the screen resolution difference ratio. Reposition visual controls proportional to screen resolution differences by multiplying the Top and Left property values by the same ratio.

If an application is designed on a computer configured for a higher screen resolution than that on the user’s computer, font sizes will be reduced in the process of proportionally resizing visual controls. If the size of the font at design time is too small, the font as resized at runtime may be unreadable. For example, the default font size for a form is 8. If the development computer has a screen resolution of 1024x768 and the user’s computer 640x480, visual control dimensions will be reduced by a factor of 0.625 (640 / 1024 = 0.625). The original font size of 8 is reduced to 5 (8 * 0.625 = 5). Text in the application appears jagged and unreadable as Windows displays it in the reduced font size.

Some visual controls, such as TLabel and TEdit, dynamically resize when the size of the font for the control changes. This can affect deployed applications when forms and controls are dynamically resized. The resizing of the control due to font size changes are in addition to size changes due to proportional resizing for screen resolutions. This effect is offset by setting the AutoSize property of these controls to false.

Avoid making use of explicit pixel coordinates, such as when drawing directly to a canvas. Instead, modify the coordinates by a ratio proportionate to the screen resolution difference ratio between the development and user computers. For example, if the application draws a rectangle to a canvas ten pixels high by twenty wide, instead multiply the ten and twenty by the screen resolution difference ratio. This ensures that the rectangle visually appears the same size under different screen resolutions.


Accomodating varying color depths

Topic groups	See also

To account for all deployment computers not being configured with the same color availability, the safest way is to use graphics with the least possible number of colors. This is especially true for control glyphs, which should typically use 16-color graphics. For displaying pictures, either provide multiple copies of the images in different resolutions and color depths or explain in the application the minimum resolution and color requirements for the application.


Fonts

Topic groups	See also

Windows comes with a standard set of TrueType and raster fonts. When designing an application to be deployed on other computers, realize that not all computers will have fonts outside the standard Windows set.

Text components used in the application should all use fonts that are likely to be available on all deployment computers.

When use of a nonstandard font is absolutely necessary in an application, you need to distribute that font with the application. Either the installation program or the application itself must install the font on the deployment computer. Distribution of third-party fonts may be subject to limitations imposed by the font creator.

Windows has a safety measure to account for attempts to use a font that does not exist on the computer. It substitutes another, existing font that it considers the closest match. While this may circumvent errors concerning missing fonts, the end result may be a degradation of the visual appearance of the application. It is better to prepare for this eventuality at design time.

To make a nonstandard font available to an application, use the Windows API functions AddFontResource and DeleteFontResource. Deploy the .FOT file for the nonstandard font with the application.


Windows versions

Topic groups	See also

When using Windows API functions or accessing areas of the Windows operating system from an application, there is the possibility that the function, operation, or area may not be available on computers with different versions of Windows. For example, Services are only pertinent to the Windows NT operating system. If an application is to act as a Service or interact with one, this would fail if the application is installed under Windows 95.

To account for this possibility, you have a few options:

Specify in the application’s system requirements the versions of Windows on which the application can run. It is the user’s responsibility to install and use the application only under compatible Windows versions.

Check the version of Windows as the application is installed. If an incompatible version of Windows is present, either halt the installation process or at least warn the installer of the problem.

Check the Windows version at runtime, just prior to executing an operation not applicable to all versions. If an incompatible version of Windows is present, abort the process and alert the user. Alternately, provide different code to run dependent on different versions of Windows. Some operations are performed differently in Windows 95 than in Windows NT. Use the Windows API function GetVersionEx to determine the Windows version.


Software license requirements

Topic groups	See also

The distribution of some files associated with C++Builder applications is subject to limitations or cannot be redistributed at all. The following documents describe the legal stipulations regarding the distribution of these files where limitations exist:

DEPLOY.TXT

DEPLOY.TXT covers the some of the legal aspects of distributing of various components and utilities, and other product areas that can be part of or associated with your application. DEPLOY.TXT is a text file installed in the main directory. The topics covered include, but are not limited to

.EXE, .DLL, and .BPL files

Components and design-time packages

Borland Database Engine (BDE)

ActiveX controls

Sample Images

Multi-tiered Distributed Application Services (MIDAS)

SQL Links

README.TXT

README.TXT contains last minute information about C++Builder, possibly including information that could affect the redistribution rights for components, or utilities, or other product areas. README.TXT is a Windows help file installed into the main C++Builder directory.

No-nonsense license agreement

The C++Builder no-nonsense license agreement, a printed document, covers other legal rights and obligations concerning C++Builder.

Third-party product documentation

Redistribution rights for third-party components, utilities, helper applications, database engines, and other products are governed by the vendor supplying the product. Consult the documentation for the product or the vendor for information regarding the redistribution of the product with C++Builder applications prior to distribution.


C++ language support for the VCL

Topic groups	See also

C++Builder leverages the Rapid Application Development (RAD) capabilities of the Visual Component Library (VCL) written in Object Pascal. The following topics explain how Object Pascal language features, constructs, and concepts were implemented in C++Builder to support the VCL.

Note:	References these topicsto C++ classes derived from TObject refer to classes for which TObject is the ultimate, but not necessarily immediate, ancestor. For consistency with the compiler diagnostics, such classes are also referred to as “VCL style classes.”

The first set of topics compares C++ and Object Pascal object models, describing how C++Builder combines these two approaches:

C++ and Object Pascal object models

The second set of topics describes how Object Pascal language constructs were translated into C++ counterparts in C++Builder:

Support for Object Pascal data types and language concepts

These topics include details on keyword extensions that were added to support the VCL. Some of these extensions, like closures and properties, are useful features independent of their support for VCL-based code.


C++ and Object Pascal object models

Topic groups	See also

C++ and Object Pascal are subtly different in the way they create, initialize, reference, copy, and destroy objects. These nuances and their impact on C++Builder VCL style classes are described the following topics.

Object identity and instantiation

Object construction for C++Builder VCL classes

Calling virtual methods in base class constructors

Object destruction

AfterConstruction and BeforeDestruction

Class virtual functions


Object identity and instantiation

Topic groups	See also

In C++, an instance of a class is an actual object. That object can be directly manipulated, or it can be accessed indirectly through either a reference or a pointer to it. For example, given a C++ class CPP_class with a constructor that takes no arguments, the following are all valid instance variables of that class:

CPP_class by_value;	// an object of type CPP_class

CPP_class& ref = by_value;	// a reference to the object by_value, above

CPP_class* ptr = new CPP_class();	// a pointer to an object of type CPP_class

By contrast, in Object Pascal a variable of type object always refers to the object indirectly. The memory for all objects is dynamically allocated. For example, given an Object Pascal class OP_class

ref: OP_class;

ref := OP_class.Create;

ref is a “reference” to an object of type OP_class. Translated to C++Builder code, it would be

OP_class* ref = new OP_class;

The next few sections discuss the implications of these differences.

Distinguishing C++ and Object Pascal references

Documentation frequently refers to an Object Pascal class instance variable as a reference, but describes its behavior as that of a pointer. This is because it has properties of both. An Object Pascal object reference is like a C++ pointer with the following exceptions:

An Object Pascal reference is implicitly dereferenced (in which case it acts more like a C++ reference).

An Object Pascal reference does not have pointer arithmetic as a defined operation.

When comparing an Object Pascal reference with a C++ reference, there are also similarities and differences. References in both languages are implicitly dereferenced, however,

An Object Pascal reference can be rebound, whereas a C++ reference cannot.

An Object Pascal reference can be nil, whereas a C++ reference must refer to a valid object.

Some of the design decisions underlying the VCL framework are based upon the use of this type of instance variable. A pointer is the closest C++ language construct to an Object Pascal reference. Consequently, nearly all VCL object identifiers are translated into C++ pointers in C++Builder.

Note:	The Object Pascal var parameter type is a close match to a C++ reference.

Copying objects

Unlike C++, Object Pascal does not have built-in compiler support for making a copy of an object. This section describes the impact of this difference on assignment operators and copy constructors for VCL style classes.

Assignment operators

The Object Pascal assignment operator (:=) is not a class assignment operator (operator=()). The assignment operator copies the reference, not the object. In the following code, B and C both refer to the same object:

B, C: TButton;

B:= TButton.Create(ownerCtrl);

C:= B;

This example translates to the following code in C++Builder:

TButton *B = NULL;

TButton *C = NULL;

B = new TButton(ownerCtrl);

C = B;	// makes a copy of the pointer, not the object

VCL style classes in C++Builder follow the Object Pascal language rules for assignment operators. This means that, in the following code, assignments between dereferenced pointers are not valid because they attempt to copy the object, not the pointer:

TVCLStyleClass *p = new TVCLStyleClass;

TVCLStyleClass *q = new TVCLStyleClass;

*p = *q;	// not allowed for VCL style class objects

Note:	For VCL style classes, it is still valid to use C++ syntax to bind a reference. For example, the following code is valid:

TVCLStyleClass *ptr = new TVCLStyleClass;

TVCLStyleClass &ref = *ptr;	// OK for VCL style classes

Although this is not the same as using an assignment operator, the syntax is similar enough that it is mentioned here for clarification and comparison.

Copy constructors

Object Pascal does not have built-in copy constructors. Consequently, VCL style classes in C++Builder do not have built-in copy constructors. The following example code attempts to create a TButton pointer by using a copy constructor:

TButton *B = new TButton(ownerCtrl);

TButton *C = new TButton(*B);	// not allowed for VCL style class objects

Do not write code that depends upon a built-in copy constructor for VCL classes. To create a copy of a VCL style class object in C++Builder, you can write code for a member function that copies the object. Alternatively, descendants of the VCL TPersistent class can override the Assign method to copy data from one object to another. This is typically done, for example, in graphics classes such as TBitmap and TIcon that contain resource images. Ultimately, the manner of copying an object can be determined by the programmer (component writer); but be aware that some of the copy methods used in standard C++ are not available for VCL style classes.

Objects as function arguments

As discussed previously, instance variables in C++ and in Object Pascal are not identical. You should be aware of this when passing objects as arguments to functions. In C++, objects can be passed to functions either by value, by reference, or by pointer. In Object Pascal , when an object is passed by value to a function, remember that the object argument is already a reference to an object. So, it is, in fact, the reference that is passed by value, not the actual object. There is no Object Pascal equivalent to passing an actual object by value as in C++. VCL style objects passed to functions follow the Object Pascal rules.


Object construction for C++Builder VCL classes

Topic groups	See also

C++ and Object Pascal construct objects differently.

C++ object construction

In standard C++, the order of construction is virtual base classes, followed by base classes, and finally the derived class. The C++ syntax uses the constructor initialization list to call base class constructors. The runtime type of the object is that of the class of the current constructor being called. Virtual method dispatching follows the runtime type of the object and changes accordingly during construction.

Object Pascal object construction

In Object Pascal, only the constructor for the instantiated class is guaranteed to be called; however, the memory for base classes is allocated. Constructing each immediate base class is done by calling inherited in the corresponding derived class’s constructor. By convention, VCL classes use inherited to call (non-empty) base class constructors. Be aware, however, that this is not a requirement of the language. The runtime type of the object is established immediately as that of the instantiated class and does not change as base class constructors are called. Virtual method dispatching follows the runtime type of the object and, therefore, does not change during construction.

C++Builder object construction

VCL style objects are constructed like Object Pascal objects, but using C++ syntax. This means that the method and order of calling base class constructors follows C++ syntax using the initialization list for all non-VCL base classes and the first immediate VCL ancestor. This VCL base class is the first class to be constructed. It constructs its own base class, optionally, using inherited, following the Object Pascal method. Therefore, the VCL base classes are constructed in the opposite order from which you might expect in C++. Then the C++ base classes are all constructed, from the most distant ancestor to the derived class. The runtime type of the object and virtual method dispatching are Object Pascal-based.

The figure below illustrates the construction of an instance of a VCL style class, MyDerived, descended from MyBase, which is a direct descendant of TWinControl. MyDerived and MyBase are implemented in C++. TWinControl is a VCL class implemented in Object Pascal.

Note that the order of construction looks first backwards to the C++ programmer, starting from the leaf-most ancestor to TObject for true VCL classes, and then forward, constructing MyBase and finally the derived class.

Note:	TComponent does not call inherited because TPersistent does not have a constructor. TObject has an empty constructor, so it is not called. If these class constructors were called, the order would follow the diagram in which these classes appear in gray.

The object construction models in C++, Object Pascal, and C++Builder are summarized in the following table:

C++	Object Pascal	C++Builder
Order of construction
Virtual base classes, then base classes, finally the derived class.	Instantiated class constructor is the first and only constructor to be called automatically. If subsequent classes are constructed, they are constructed from leaf-most to root.	Most immediate VCL base class, then construction follows the Object Pascal model, then construction follows the C++ model (except that no virtual base classes are allowed).
Method of calling base class constructors
Automatically, from the constructor initialization list.	Optionally, explicitly, and at any time during the body of the derived class constructor, by using the inherited keyword.	Automatically from the constructor initialization list through the most immediate ancestor VCL base class constructor. Then according to the Object Pascal method, calling constructors with inherited.
Runtime type of the object as it is being constructed
Changes, reflecting the type of the current constructor class.	Established immediately as that of the instantiated class.	Established immediately as that of the instantiated class.
Virtual method dispatching
Changes according to the runtime type of the object as base class constructors are called.	Follows the runtime type of the object, which remains the same throughout calls to all class constructors.	Follows the runtime type of the object, which remains the same throughout calls to all class constructors.
The significance of these differences is described in Calling virtual methods in base class constructors.


Calling virtual methods in base class constructors

Topic groups	See also

Virtual methods invoked from the body of VCL base class constructors, that is, classes implemented in Object Pascal, are dispatched as in C++, according to the runtime type of the object. Because C++Builder combines the Object Pascal model of setting the runtime type of an object immediately, with the C++ model of constructing base classes before the derived class is constructed, calling virtual methods from base class constructors for VCL style classes can have subtle side-effects. The impact of this is described below, then illustrated in an example of an instantiated class that is derived from at least one base. In this discussion, the instantiated class is referred to as the derived class.

Object Pascal model

In Object Pascal, programmers can use the inherited keyword, which provides flexibility for calling base class constructors anywhere in the body of a derived class constructor. Consequently, if the derived class overrides any virtual methods that depend upon setting up the object or initializing data members, this can happen before the base class constructor is called and the virtual methods are invoked.

C++ model

The C++ syntax does not have the inherited keyword to call the base class constructor at any time during the construction of the derived class. For the C++ model, the use of inherited is not necessary because the runtime type of the object is that of the current class being constructed, not the derived class. Therefore, the virtual methods invoked are those of the current class, not the derived class. Consequently, it is not necessary to initialize data members or set up the derived class object before these methods are called.

C++Builder model

In C++Builder, the VCL style objects have the runtime type of the derived class throughout calls to base class constructors. Therefore, if the base class constructor calls a virtual method, the derived class method is invoked if the derived class overrides it. If this virtual method depends upon anything in the initialization list or body of the derived class constructor, the method is called before this happens. For example, CreateParams is a virtual member function that is called indirectly in the constructor of TWinControl. If you derive a class from TWinControl and override CreateParams so that it depends on anything in your constructor, this code is processed after CreateParams is called. This situation applies to any derived classes of a base. Consider a class C derived from B, which is derived from A. Creating an instance of C, A would also call the overridden method of B, if B overrides the method but C does not.

Note:	Be aware of virtual methods like CreateParams that are not obviously called in constructors, but are invoked indirectly.

Example calling virtual methods

Constructor initialization of data members for virtual functions


Example: calling virtual methods
Example calling virtual methods

Topic groups	See also

The following example compares C++ and VCL style classes that have overridden virtual methods. This example illustrates how calls to those virtual methods from base class constructors are resolved in both cases. MyBase and MyDerived are standard C++ classes. MyVCLBase and MyVCLDerived are VCL style classes descended from TObject. The virtual method what_am_I() is overridden in both derived classes, but is called only in the base class constructors, not in derived class constructors.

#include <sysdefs.h>

#include <sysutils.hpp>

#include <iostream.h>

// non-VCL style classes

class MyBase {

public:

MyBase() { what_am_I(); }

virtual void what_am_I() { cout << "I am a base" << endl; }

};

class MyDerived : public MyBase {

public:

virtual voidwhat_am_I() { cout << "I am a derived" << endl; }

};

// VCL style classes

class MyVCLBase : public TObject {

public:

__fastcall MyVCLBase() { what_am_I(); }

virtual void __fastcall what_am_I() { cout << "I am a base" << endl; }

};

class MyVCLDerived : public MyVCLBase {

public:

virtual void __fastcall what_am_I() { cout << "I am a derived" << endl; }

};

int main(void)

{

MyDerived d;	// instantiation of the C++ class

MyVCLDerived *pvd = new MyVCLDerived;	// instantation of the VCL style class

return 0;

}

The output of this example is

I am a base

I am a derived

because of the difference in the runtime types of MyDerived and MyVCLDerived during the calls to their respective base class constructors.


Constructor initialization of data members for virtual functions

Topic groups	See also

Because data members may be used in virtual functions, it is important to understand when and how they are initialized. In Object Pascal, all uninitialized data is zero-initialized. This applies, for example, to base classes whose constructors are not called with inherited. In standard C++, there is no guarantee of the value of uninitialized data members. The following types of class data members must be initialized in the initialization list of the class’s constructor:

References

Data members with no default constructor

Nevertheless, the value of these data members, or those initialized in the body of the constructor, is undefined when the base class constructors are called. In C++Builder, the memory for VCL style classes is zero-initialized.

Note:	Technically, it is the memory of the VCL class that is zero, that is the bits are zero, the values are actually undefined. For example, a reference is zero.

A virtual function which relies upon the value of member variables initialized in the body of the constructor or in the initialization list may behave as if the variables were initialized to zero. This is because the base class constructor is called before the initialization list is processed or the constructor body is entered. The following example illustrates this:

#include <sysdefs.h>

#include <sysutils.hpp>

class Base : public TObject {

public:

__fastcall Base() { init(); }

virtual void __fastcall init() { }

};

class Derived : public Base {

public:

Derived(int nz) : not_zero(nz) { }

virtual void __fastcall init()

{

if (not_zero == 0)

throw Exception("not_zero is zero!");

}

private:

int not_zero;

};

int main(void)

{

Derived *d42 = new Derived(42);

return 0;

}

This example throws an exception in the constructor of Base. Because Base is constructed before Derived, not_zero, has not yet been initialized with the value of 42 passed to the constructor. Be aware that you cannot initialize data members of your VCL style class before its base class constructors are called.


Object destruction

Topic groups	See also

Two mechanisms concerning object destruction work differently in C++ from the way they do in Object Pascal. These are:

Destructors called because of exceptions thrown from constructors

Virtual methods called from destructors

VCL style classes combine the methods of these two languages. The issues are discussed below.

Exceptions thrown from constructors

Destructors are called differently in C++ than in Object Pascal if an exception is thrown during object construction. Take as an example, class C, derived from class B, which is derived from class A:

class A

{

// body

};

class B: public A

{

//body

};

class C: public B

{

// body

};

Consider if an exception is raised in the constructor of class B when constructing an instance of C. What results in C++, Object Pascal, and VCL style classes is described here:

In C++, first the destructors for all completely constructed object data members of B are called, then A’s destructor is called, then the destructors for all completely constructed data members of A are called. However, the destructors for B and C are not called.

In Object Pascal, only the instantiated class destructor is called automatically. This is the destructor for C. As with constructors, it is entirely the programmer’s responsibility to call inherited in destructors. In this example, if we assume all of the destructors call inherited, then the destructors for C, B, and A are called in that order. Moreover, whether or not inherited was already called in B’s constructor before the exception occurred, A’s destructor is called because inherited was called in B’s destructor. Calling the destructor for A is independent of whether or not its constructor was actually called. More importantly, because it is common for constructors to call inherited immediately, the destructor for C is called whether or not the body of its constructor was completely executed.

In VCL style classes, the true VCL bases (implemented in Object Pascal) follow the Object Pascal method of calling destructors. The C++ VCL style classes (implemented in C++) do not follow exactly either language method. What happens is that all the destructors are called; but the bodies of those that would not have been called, according to C++ language rules, are not entered.

Classes implemented in Object Pascal thereby provide an opportunity to process any cleanup code you write in the body of the destructor. This includes code that frees memory for sub-objects (data members that are objects) that are constructed before a constructor exception occurs. Be aware that, for VCL style classes, the clean-up code may not be processed for the instantiated class or for its C++-implemented bases, even though the destructors are called.

For more information on handling exceptions in C++Builder, refer to VCL exception handling.

Virtual methods called from destructors

Virtual method dispatching in destructors follows the same pattern that it did for constructors. This means that for VCL style classes, the derived class is destroyed first, but the runtime type of the object remains that of the derived class throughout subsequent calls to base class destructors. Therefore, if virtual methods are called in VCL base class destructors, you are potentially dispatching to a class that has already destroyed itself.


AfterConstruction and BeforeDestruction

Topic groups	See also

TObject introduces two virtual methods, BeforeDestruction andAfterConstruction, that allow programmers to write code that is processed before and after objects are destroyed and created, respectively. AfterConstruction is called after the last constructor is called. BeforeDestruction is called before the first destructor is called. These methods are public and are called automatically.


Class virtual functions

Topic groups	See also

Object Pascal has the concept of a class virtual function. The C++ analogy would be a static virtual function, if it were possible; but C++ has no exact counterpart to this type of function. These functions are safely called internally from the VCL. However, you should never call a function of this type in C++Builder. You can identify these functions in the header files because they are preceded by the following comment:

/* virtual class method */


Support for Object Pascal data types and language concepts

Topic groups	See also

To support the VCL, C++Builder implements, translates, or otherwise maps most Object Pascal data types, constructs, and language concepts to the C++ language. This is done through typedefs to native C++ types; classes, structs, and class templates; C++ language counterparts; macros; and keywords that are ANSI-conforming language extensions.

Not all aspects of the Object Pascal language map cleanly to C++. Occasionally, using these parts of the language can lead to unexpected behavior in your application. For example:

Some types exist in both Object Pascal and in C++, but are defined differently. These can require caution when sharing code between these two languages.

Some extensions were added to Object Pascal for the purpose of supporting C++Builder. Occasionally these can have subtle interoperability impact.

Object Pascal types and language constructs that have no mapping to the C++ language should be avoided in C++Builder when sharing code between these languages.

The following topics provide a summary of the way C++Builder implementations and maps the Object Pascal language, and a suggestion of when to use caution.

Topics in this section:

Typedefs

Classes that support the Object Pascal language

C++ language counterparts to the Object Pascal language

Open arrays

Types defined differently

Resource strings

Default parameters

Runtime type information

Unmapped types

Keyword extensions

The __declspec keyword extension


Typedefs

Topic groups	See also

Most Object Pascal intrinsic data types are implemented in C++Builder using a typedef to a native C++ type. These are found in sysmac.h. Whenever possible you should use the native C++ type, rather than the Object Pascal type.


Classes that support the Object Pascal language

Topic groups	See also

Some Object Pascal data types and language constructs that do not have a built-in C++ counterpart are implemented as classes or structs. Class templates are also used to implement data types as well as Object Pascal language constructs, like set, from which a specific type can be declared. The declarations for these are found in the following header files:

dstring.h

wstring.h

sysclass.h

syscomp.h

syscurr.h

sysdyn.h

sysopen.h

sysset.h

systdate.h

systobj.h

systvar.h

sysvari.h

The classes implemented in these header files were created to support native types used in Object Pascal routines. They are intended to be used when calling these routines in VCL-based code.


C++ language counterparts to the Object Pascal language

Topic groups	See also

Object Pascal var and untyped parameters are not native to C++. Both have C++ language counterparts that are used in C++Builder.

Var parameters

Both C++ and Object Pascal have the concept of “pass by reference.” These are modifiable arguments. In Object Pascal they are called var parameters. The syntax for functions that take a var parameter is

procedure myFunc(var x : integer);

In C++, you should pass these types of parameters by reference:

void myFunc(int& x);

Both C++ references and pointers can be used to modify the object. However, a reference is a closer match to a var parameter because, unlike a pointer, a reference cannot be rebound and a var parameter cannot be reassigned; although, either can change the value of what it references.

Untyped parameters

Object Pascal allows parameters of an unspecified type. These parameters are passed to functions with no type defined. The receiving function must cast the parameter to a known type before using it. C++Builder interprets untyped parameters as pointers-to-void (void *). The receiving function must cast the void pointer to a pointer of the desired type. Following is an example:

int myfunc(void* MyName)

{

// Cast the pointer to the correct type; then dereference it.

int* pi = static_cast<int*>(MyName);

return 1 + *pi;

}


Open arrays

Topic groups	See also

Object Pascal has an “open array” construct that permits an array of unspecified size to be passed to a function. While there is no direct support in C++ for this type, an Object Pascal function that has an open array parameter can be called by explicitly passing both pointer to the first element of an array, and the value of the last index (number of array elements, minus one). For example, the Mean function in math.hpp has this declaration in Object Pascal:

function Mean(Data: array of Double): Extended;

The C++ declaration is

Extended __fastcall Mean(const double * Data, const int Data_Size);

The following code illustrates calling the Mean function from C++:

double d[] = { 3.1, 4.4, 5.6 };

// explicity specifying last index

long double x = Mean(d, 2);

// better: use sizeof to ensure that the correct value is passed

long double y = Mean(d, (sizeof(d) / sizeof(d[0])) - 1);

// use macro in sysdefs.h

long double z = Mean(d, ARRAYSIZE(d) - 1);

Note:	In cases similar to the above example, but where the Object Pascal function takes a var parameter, the C++ function declaration parameters will not be const.

Calculating the number of elements

Temporaries

array of const

OPENARRAY macro

EXISTINGARRAY macro

C++ functions that take open array arguments


Calculating the number of elements

Topic groups	See also

When usingsizeof(), the ARRAYSIZE macro, or EXISTINGARRAY macro to calculate the number of elements in an array, be careful not to use a pointer to the first array element instead. Pass the name of an array instead:

double d[] = { 3.1, 4.4, 5.6 };

ARRAYSIZE(d) == 3;

double *pd = d;

ARRAYSIZE(pd) == 0; // Error!

Taking the “sizeof” an array is not the same as taking the “sizeof” a pointer. For example, given the following declarations,

double d[3];

double *p = d;

taking the size of the array as shown here

sizeof(d)/sizeof d[0]

does not evaluate the same as taking the size of the pointer:

sizeof(p)/sizeof(p[0])


Temporaries

Topic groups	See also

Object Pascal provides support for passing unnamed temporary open arrays to functions. There is no syntax for doing this in C++. However, since variable definitions can be intermingled with other statements, one approach is to simply provide the variable with a name.

Object Pascal:

Result := Mean([3.1, 4.4, 5.6]);

C++, using a named “temporary:”

double d[] = { 3.1, 4.4, 5.6 };

return Mean(d, ARRAYSIZE(d) - 1);

To restrict the scope of the named “temporary” to avoid clashing with other local variables, open a new scope in place:

long double x;

{

double d[] = { 4.4, 333.1, 0.0 };

x = Mean(d, ARRAYSIZE(d) - 1);

}

For another solution, use the OPENARRAY macro.


array of const

Topic groups	See also

Object Pascal supports a language construct called an array of const. This argument type is the same as taking an open array of TVarRec by value.

The following is an Object Pascal code segment declared to accept an array of const:

function Format(const Format: string; Args: array of const): string;

In C++, the prototype is

AnsiString __fastcall Format(const AnsiString Format;

TVarRec const *Args, const int Args_Size);

The function is called just like any other function that takes an open array:

void show_error(int error_code, AnsiString const &error_msg)

{

TVarRec v[] = { error_code, error_msg };

ShowMessage(Format("%d: %s", v, ARRAYSIZE(v) - 1));

}


OPENARRAY macro

Topic groups	See also

The OPENARRAY macro defined in sysdefs.h can be used as an alternative to using a named variable for passing a temporary open array to a function that takes an open array by value. The use of the macro looks like

OPENARRAY(T, (value1, value2, value3)) // up to 19 values

where T is the type of open array to construct. For example:

void show_error(int error_code, AnsiString const &error_msg)

{

ShowMessage(Format("%d: %s", OPENARRAY(TVarRec, error_code, error_msg)));

}

Up to 19 values can be passed when using the OPENARRAY macro. If a larger array is needed, an explicit variable must be defined. Additionally, using the OPENARRAY macro incurs an additional (but small) runtime cost, due both to the cost of allocating the underlying array, and to an additional copy of each value.


EXISTINGARRAY macro

Topic groups	See also

The EXISTINGARRAY macro defined in sysdefs.h can be used to pass an existing array where an open array is expected. The use of the macro looks like

long double Mean(const double *Data, const int Data_Size);

double d[] = { 3.1, 3.14159, 2.17128 };

Mean(EXISTINGARRAY (d));

Note:	The topic Calculating the number of elements also applies to the EXISTINGARRAY macro.


C++ functions that take open array arguments

Topic groups	See also

When writing a C++ function that will be passed an open array from Object Pascal, it is important to explicitly maintain “pass by value” semantics. In particular, if the declaration for the function corresponds to “pass by value,” be sure to explicitly copy any elements before modifying them. In Object Pascal, an open array is a built-in type and can be passed by value. In C++, the open array type is implemented using a pointer, which will modify the original array unless you make a local copy of it.


Types defined differently

Topic groups	See also

Types that are defined differently in Object Pascal and C++ are not normally cause for concern. The rare cases in which they are problematic may be subtle. For this reason, these types are mentioned in this topic.

Boolean data types

The True value for the Object Pascal ByteBool, WordBool, and LongBool data types is represented in Object Pascal as –1. False is represented as 0.

Note:	The Boolean data type remains unchanged (True = 1, False = 0).

While the C++ bool type converts these Object Pascal types correctly, there is a problem when sharing a WinAPI function or any other function that uses a Window’s BOOL type, which is represented as 1. If a value is passed to a parameter of type BOOL, it evaluates to –1 in Object Pascal and to 1 in C++. Therefore, if you are sharing code between these two languages, any comparison of the two identifiers may fail unless they are both 0 (False, false). As a workaround, you can use the following method of comparison:

!A == !B;

The table below shows the results of using this method of equality comparison:

Object Pascal	C++	!A == !B
0 (False)	0 (false)	!0 == !0 (TRUE)
0 (False)	1 (true)	!0 == !1 (FALSE)
–1 (True)	0 (false)	!–1 == !0 (FALSE)
–1 (True)	1 (true)	!–1 == !1 (TRUE)
With this method of comparison, any set of values will evaluate correctly.

Char data types

The char type in C++ is a signed type, whereas it is an unsigned type in Object Pascal. It is extremely rare that a situation would occur in which this difference would be a problem when sharing code.


Resource strings

Topic groups	See also

If you have code in a Pascal unit that uses resource strings, the Pascal compiler (DCC32) generates a global variable and a corresponding preprocessor macro for each resource string when it generates the header file. The macros are used to automatically load the resource strings, and are intended to be used in your C++ code in all places where the resource string is referenced. For example, the resourcestring section in the Object Pascal code could contain

unit borrowed;

interfaceS

resourcestring

Warning = 'Be careful when accessing string resources.';

implementation

begin

end.

The corresponding code generated by the Pascal compiler for C++Builder would be

extern System::Resource ResourceString _Warning;

#define Borrowed_Warning System::LoadResourceString(&Borrowed::_Warning)

This enables you to use the exported Object Pascal resource string without having to explicitly call LoadResourceString.


Default parameters

Topic groups	See also

The Pascal compiler now accepts default parameters for compatibility with C++ regarding constructors. Unlike C++, Object Pascal constructors can have the same number and types of parameters, since they are uniquely named. In such cases, dummy parameters are used in the Object Pascal constructors to distinguish them when the C++ header files are generated. For example, for a class named TInCompatible, the Object Pascal constructors could be

constructor Create(AOwner: TComponent);

constructor CreateNew(AOwner: TComponent);

which would translate, without default parameters, to the following ambiguous code in C++ for both constructors:

__fastcall TInCompatible(Classes::TComponent* Owner);	// C++ version of the Pascal Create constructor

__fastcall TInCompatible(Classes::TComponent* Owner);	// C++ version of the Pascal CreateNew constructor

However, using default parameters, for a class named TCompatible, the Object Pascal constructors are

constructor Create(AOwner: TComponent);

constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0);

They translate to the following unambiguous code in C++Builder:

__fastcall TCompatible(Classes::TComponent* Owner);	// C++ version of the Pascal Create constructor

__fastcall TCompatible(Classes::TComponent* Owner, int Dummy);	// C++ version of the Pascal CreateNew constructor

Note:	The main issue regarding default parameters is that DCC32 strips out the default value of the default parameter. Failure to remove the default value would lead to the ambiguity that would occur if there were not defaults at all. You should be aware of this when using VCL classes or when using third-party components.


Runtime type information

Topic groups	See also

Object Pascal has language constructs dealing with RTTI. Some have C++ counterparts. These are listed in the table below:

Object Pascal RTTI	C++ RTTI
if Sender is TButton...	if (dynamic_cast <TButton*> (Sender) // dynamic_cast returns NULL on failure.
b := Sender as TButton; (* raises an exception on failure *)	TButton& ref_b = dynamic_cast <TButton&> (*Sender) // throws an exception on failure.
ShowMessage(Sender.ClassName);	ShowMessage(typeid(*Sender).name());
IClassName is a TObject method that returns a string containing the name of the actual type of the object, regardless of the type of the declared variable. Other RTTI methods introduced in TObject do not have C++ counterparts. These are all public and are listed here:

ClassInfo returns a pointer to the runtime type information (RTTI) table of the object type.

ClassNameIs determines whether an object is of a specific type.

ClassParent returns the type of the immediate ancestor of the class. In the case of TObject, ClassParent returns nil because TObject has no parent. It is used by the is and as operators, and by the InheritsFrom method.

ClassType dynamically determines the actual type of an object. It is used internally by the is and as operators.

FieldAddress uses RTTI to obtain the address of a published field. It is used internally by the steaming system.

InheritsFrom determines the relationship of two objects. It is used internally by the is and as operators.

MethodAddress uses RTTI to find the address of a method. It is used internally by the steaming system.

Some of these methods of TObject are primarily for internal use by the compiler or the streaming system.


Unmapped types

Topic groups	See also

6-byte Real types

The old Object Pascal 6-byte floating-point format is now called Real48. The old Real type is now a double. C++ does not have a counterpart for the Real48 type. Consequently, you should not use Object Pascal code that includes this type with C++ code. If you do, the header file generator will generate a warning.

Arrays as return types of functions

In Object Pascal a function can take as an argument, or return as a type, an array. For example, the syntax for a function GetLine returning an array of 80 characters is

type

Line_Data = array[0..79] of char;

function GetLine: Line_Data;

C++ has no counterpart to this concept. In C++, arrays are not allowed as return types of functions. Nor does C++ accept arrays as the type of a function argument.

Be aware that, although the VCL does not have any properties that are arrays, the Object Pascal language does allow this. Because properties can use Getand Set read and write methods that take and return values of the property’s type, you cannot have a property of type array in C++Builder.

Note:	Array properties, which are also valid in Object Pascal, are not a problem in C++ because the Get method takes an index value as a parameter, and the Set method returns an object of the type contained by the array. For more information about array properties, see Creating array properties.


Keyword extensions

Topic groups	See also

This section describes ANSI-conforming keyword extensions implemented in C++Builder to support the VCL.

The __declspec keyword also provides VCL support.

__classid

The __classid operator is used by the compiler to generate a pointer to the vtable for the specified classname. This operator is used to obtain the meta class from a class.

Syntax:	__classid(classname)

For example, __classid is used when registering property editors, components, and classes, and with the InheritsFrom method of TObject. The following code illustrates the use of __classid for creating a new component derived from TWinControl:

namespace Ywndctrl

{

void __fastcall PACKAGE Register()

{

TComponentClass classes[1] = {__classid(MyWndCtrl)};

RegisterComponents("Additional", classes, 0);

}

}

__closure

The __closure keyword is used to declare a special type of pointer to a member function. Unlike a regular C++ member function pointer, a closure contains an object pointer.

In standard C++, you can assign a derived class instance to a base class pointer; however, you cannot assign a derived class’s member function to a base class member function pointer. The following code illustrates this:

class base

{

public:

void func(int x);

};

class derived: public base

{

public:

void new_func(int i);

};

void (base::*bptr)(int);

bptr = &derived::new_func;	// illegal

However, the __closure language extension allows you to do this in C++Builder. A closure associates a pointer to a member function with a pointer to a class instance. The pointer to the class instance is used as the this pointer when calling the associated member function. A closure declaration is the same as a function pointer declaration but with the addition of the __closure keyword before the identifier being defined. For example:

struct MyObject

{

  double MemFunc(int);

};

double func1(MyObject *obj)

{

  // A closure taking an int argument and returning double.

  double ( __closure *myClosure )(int);

// Initialize the closure.

  myClosure = obj -> MemFunc;

// Use the closure to call the member function and pass it an int.

  return myClosure(1);

}

Closures are used with events in C++Builder.

__property

The __property keyword declares a property in a class declaration. Properties can only be declared in classes. For property arrays (when <prop dim list> is used), the index to the arrays can be of any type.

Syntax

<property declaration> ::=

      __property <type> <id> [ <prop dim list> ] = "{" <prop attrib list> "}"

  <prop dim list> ::= "[" <type> [ <id> ] "]" [ <prop dim list> ]

  <prop attrib list> ::= <prop attrib> [ , <prop attrib list> ]

  <prop attrib> ::=     read = <data/function id>

  <prop attrib> ::=     write = <data/function id>

  <prop attrib> ::=     stored = <data/function id>

  <prop attrib> ::=     stored = <boolean constant>

  <prop attrib> ::=     default = <constant>

  <prop attrib> ::=     nodefault

  <prop attrib> ::=     index = <const int expression>

Properties have several features that distinguish them from data members. Properties can

Associate read or write methods with an identifier (property)

Set default values for the property

Be stored in a form file

Extend a property defined in a base class

For more information about properties, see Creating properties.

__published

The __published keyword specifies that properties in that section are displayed in the Object Inspector, if the class is on the Component palette. Only classes derived from TObject can have __published sections.

The visibility rules for published members are identical to those of public members. The only difference between published and public members is that Object Pascal-style runtime type information (RTTI) is generated for data members and properties declared in a __published section. RTTI enables an application to dynamically query the data members, member functions, and properties of an otherwise unknown class type.

Note:	No constructors or destructors are allowed in a __published section. Properties, Pascal intrinsic or VCL derived data-members, member functions, and closures are allowed in a __published section. Fields defined in a __published section must be of a class type. Properties defined in a __published section cannot be array properties. The type of a property defined in a __published section must be an ordinal type, a real type, a string type, a small set type, a class type, or a method pointer type.


The __declspec keyword extension

Topic groups	See also

Some arguments to the __declspec keyword extension provide language support for the VCL. These arguments are listed below. Macros for the declspec arguments and combinations of them are defined in sysdefs.h. In most cases you do not need to specify these. When you do need to add them, you should use the macros.

__declspec(delphiclass)

The delphiclass argument is used for declarations for classes derived from TObject. These classes will be created with the following VCL compatibility:

VCL-compatible RTTI

VCL-compatible constructor/destructor behavior

VCL-compatible exception handling

A VCL-compatible class has the following restrictions.

No virtual base classes are allowed.

No multiple inheritance is allowed.

Must be dynamically allocated by using the global new operator.

Must have a destructor.

Copy constructors and assignment operators are not compiler-generated for VCL-derived classes.

A class declaration that is translated from Object Pascal will need this modifier if the compiler needs to know that the class is derived from TObject.

__declspec(delphireturn)

The delphireturn argument is for internal use only by the VCL in C++Builder. It is used for declarations of classes that were created in C++Builder to support Object Pascal’s built-in data types and language constructs because they do not have a native C++ type. These include Currency, AnsiString, Variant, TDateTime, and Set. The delphireturn argument marks C++ classes for VCL-compatible handling in function calls as parameters and return values. This modifier is needed when passing a structure by value to a function between Object Pascal and C++.

__declspec(dynamic)

The dynamic argument is used for declarations for dynamic functions. Dynamic functions are similar to virtual functions except that they are stored only in the vtables for the objects that define them, not in descendant vtables. If you call a dynamic function, and that function is not defined in your object, the vtables of its ancestors are searched until the function is found. Dynamic functions are only valid for classes derived from TObject.

__declspec(hidesbase)

The hidesbase argument preserves Object Pascal program semantics when porting Object Pascal virtual and override functions to C++Builder. In Object Pascal, virtual functions in base classes can appear in the derived class as a function of the same name, but which is intended to be a completely new function with no explicit relation to the earlier one.

The compilers use the HIDESBASE macro, defined in sysdefs.h, to specify that these types of function declarations are completely separate. For example, if a base class T1 declares a virtual function, func, taking no arguments, and its derived class T2 declared a function with the same name and signature, DCC32 -jphn would produce an HPP file with the following prototype:

   virtual void T1::func(void);

   HIDESBASE void T2::func(void);

Without the HIDESBASE declaration, the C++ program semantics indicate that virtual function T1::func() is being overridden by T2::func().

__declspec(package)

The package argument indicates that the code defining the class can be compiled in a package. This modifier is auto-generated by the compiler when creating packages in the IDE.

__declspec(pascalimplementation)

The pascalimplementation argument indicates that the code defining the class was implemented in Object Pascal. This modifier appears in an Object Pascal portability header file with a .hpp extension.


Related topic groups

Building applications with C++Builder

•	Building applications, components, and libraries

•	Developing the application user interface

•	Working with controls

•	Working with graphics

•	Working with multimedia

•	Writing multi-threaded applications

•	Exception handling

•	Working with packages and components

•	Creating international applications

•	Deploying applications

•	Programming with C++Builder

•	C++ language support for the VCL


Programming with C++Builder

Related topic groups

•	The C++Builder development environment

•	Designing applications

•	Using components

•	Writing database applications


Building applications, components, and libraries

Related topic groups

•	Creating applications

•	Windows EXEs

•	User interface models

•	SDI Applications

•	MDI applications

•	Setting IDE, project, and compilation options

•	Programming templates

•	Console applications

•	Service applications

•	Service threads

•	Service name properties

•	Creating packages and DLLs

•	When to use packages and DLLs

•	Using DLLs in C++Builder

•	Creating DLLs in C++Builder

•	Creating DLLs containing VCL components

•	Linking DLLs

•	Building distributed applications

•	Distributing applications using TCP/IP

•	Using sockets in applications

•	Creating Web server applications

•	Distributing applications using COM and DCOM

•	Distributing applications using CORBA

•	Distributing database applications


Developing the application user interface

Related topic groups

•	Developing the application user interface: Overview

•	Understanding TApplication, TScreen, and TForm

•	Using the main form

•	Adding additional forms

•	Linking forms

•	Working at the application level

•	Handling the screen

•	Managing layout

•	Working with messages

•	More details on forms

•	Controlling when forms reside in memory

•	Displaying an auto-created form

•	Creating forms dynamically

•	Creating modeless forms such as windows

•	Using a local variable to create a form instance

•	Passing additional arguments to forms

•	Retrieving data from forms

•	Retrieving data from modeless forms

•	Retrieving data from modal forms

•	Creating and managing menus

•	Opening the Menu Designer

•	Building menus

•	Naming menus

•	Naming the menu items

•	Adding, inserting, and deleting menu items

•	Adding separator bars

•	Specifying accelerator keys and keyboard shortcuts

•	Creating submenus

•	Creating submenus by demoting existing menus

•	Moving menu items

•	Adding images to menu items

•	Viewing the menu

•	Editing menu items in the Object Inspector

•	Using the Menu Designer context menu

•	Commands on the context menu

•	Switching between menus at design time

•	Using menu templates

•	Saving a menu as a template

•	Naming conventions for template menu items and event handlers

•	Manipulating menu items at runtime

•	Merging menus

•	Specifying the active menu: Menu property

•	Determining the order of merged menu items: GroupIndex property

•	Importing resource files

•	Designing toolbars and cool bars

•	Adding a toolbar using a panel component

•	Adding a speed button to a panel

•	Assigning a speed button's glyph

•	Setting the initial condition of a speed button

•	Creating a group of speed buttons

•	Allowing toggle buttons

•	Adding a toolbar using the toolbar component

•	Adding a tool button

•	Assigning images to tool buttons

•	Setting tool button appearance and initial conditions

•	Creating groups of tool buttons

•	Allowing toggled tool buttons

•	Adding a cool bar component

•	Setting the appearance of the cool bar

•	Responding to clicks

•	Writing an event handler for a button click

•	Assigning a menu to a tool button

•	Adding hidden toolbars

•	Hiding and showing toolbars

•	Using action lists

•	Action objects

•	Using Actions

•	Centralizing code

•	Linking properties

•	Executing actions

•	Updating actions

•	Pre-defined action classes

•	Standard edit actions

•	Standard Window actions

•	DataSet actions

•	Writing action components

•	How actions find their targets

•	Registering actions

•	Writing action list editors


Working with controls

Related topic groups

•	Implementing drag-and-drop in controls

•	Starting a drag operation

•	Accepting dragged items

•	Dropping items

•	Ending a drag operation

•	Customizing drag and drop with a drag object

•	Changing the drag mouse pointer

•	Implementing drag-and-dock in controls

•	Making a windowed control a docking site

•	Making a control a dockable child control

•	Controlling how child controls are docked in a docking site

•	Controlling how child controls are undocked in a docking site

•	Controlling how child controls respond to drag-and-dock operations

•	Working with text in controls

•	Setting text alignment

•	Adding scroll bars at runtime

•	Adding the Clipboard object

•	Selecting text

•	Selecting all text

•	Cutting, copying, and pasting text

•	Deleting selected text

•	Disabling menu items

•	Providing a pop-up menu

•	Handling the OnPopup event

•	Adding graphics to controls

•	Setting the owner-draw style

•	Adding graphical objects to a string list

•	Adding images to an application

•	Adding images to a string list

•	Drawing owner-drawn items

•	Sizing owner-draw items

•	Drawing each owner-draw item


Working with graphics

Related topic groups

•	Working with graphics and multimedia

•	Overview of graphics programming

•	Refreshing the screen

•	Types of graphic objects

•	Common properties and methods of Canvas

•	Using the properties of the Canvas object

•	Using pens

•	Changing the pen color

•	Changing the pen width

•	Changing the pen style

•	Changing the pen mode

•	Getting the pen position

•	Using brushes

•	Changing the brush color

•	Changing the brush style

•	Setting the Brush Bitmap property

•	Reading and setting pixels

•	Using Canvas methods to draw graphic objects

•	Drawing lines and polylines

•	Drawing lines

•	Drawing polylines

•	Drawing shapes

•	Drawing rectangles and ellipses

•	Drawing rounded rectangles

•	Drawing polygons

•	Handling multiple drawing objects in your application

•	Keeping track of which drawing tool to use

•	Changing the tool with speed buttons

•	Using drawing tools

•	Drawing shapes

•	Sharing code among event handlers

•	Drawing on a graphic

•	Making scrollable graphics

•	Adding an image control

•	Placing the control

•	Setting the initial bitmap size

•	Drawing on the bitmap

•	Loading and saving graphics files

•	Loading a picture from a file

•	Saving a picture to a file

•	Replacing the picture

•	Using the Clipboard with graphics

•	Copying graphics to the Clipboard

•	Cutting graphics to the Clipboard

•	Pasting graphics from the Clipboard

•	Rubber banding example

•	Responding to the mouse

•	What's in a mouse event

•	Responding to a mouse-down action

•	Responding to a mouse-up action

•	Responding to a mouse move

•	Adding a field to a form object to track mouse actions

•	Refining line drawing

•	Tracking the origin point

•	Tracking movement

•	Working with multimedia


Working with multimedia

Related topic groups

•	Adding silent video clips to an application

•	Example of adding silent video clips

•	Adding audio and/or video clips to an application

•	Example of adding audio and/or video clips


Writing multi-threaded applications

Related topic groups

•	Using threads: Overview

•	Defining thread objects

•	Initializing the thread

•	Writing the thread function

•	Using the main VCL thread

•	Using thread-local variables

•	Checking for termination by other threads

•	Writing clean-up code

•	CoordinatingThreads

•	Avoiding simultaneous access

•	Locking objects

•	Using critical sections

•	Using the multi-read exclusive-write synchronizer

•	Waiting for other threads

•	Waiting for a thread to finish executing

•	Waiting for a task to be completed

•	Executing thread objects

•	Overriding the default priority

•	Starting and stopping threads

•	Caching threads

•	Using threads in distributed applications

•	Using threads in message-based servers

•	Using threads with distributed objects

•	Debugging multi-threaded applications


Exception handling

Related topic groups

•	Overview: Exception handling

•	C++ exception handling

•	ANSI requirements for exception handling

•	Exception handling syntax

•	Exception declarations

•	Throwing an exception

•	Example 1

•	Example 2

•	Example 3

•	Example 4

•	Handling an exception

•	Example 1

•	Example 2

•	Example 3

•	Exception specifications

•	Constructors and destructors in exception handling

•	Unhandled exceptions

•	Setting exception handling options

•	Structured exceptions under Win32

•	Using structured exceptions in C and C++ code

•	Syntax of structured exceptions

•	Handling structured exceptions

•	Exception filters

•	Mixing C++ with structured exceptions

•	C-based exceptions in C++ program example

•	Defining exceptions

•	Raising exceptions

•	Termination blocks

•	VCL exception handling

•	Differences between C++ and VCL exception handling

•	Handling operating system exceptions

•	Handling VCL exceptions

•	VCL exception classes

•	Portability considerations


Working with packages and components

Related topic groups

•	Working with packages and components: Overview

•	Why use packages?

•	Packages and standard DLLs

•	Runtime packages

•	Using packages in an application

•	Dynamically loading packages

•	Deciding which runtime packages to use

•	Custom packages

•	Design-time packages

•	Installing component packages

•	Creating and editing packages

•	Creating a package

•	Editing an existing package

•	Package source files and makefiles

•	Packaging components

•	Understanding the structure of a package

•	Compiling packages

•	Package-specific compiler directives

•	Weak packaging

•	Using the command-line compiler and linker

•	Package files created by a successful compilation

•	Deploying packages

•	Package collection files


Creating international applications

Related topic groups

•	Creating international applications: Overview

•	Internationalization and localization

•	Internationalization

•	Localization

•	Internationalizing applications

•	Enabling application code

•	Character sets

•	OEM and ANSI character sets

•	Double byte character sets

•	Wide characters

•	Including bi-directional functionality in applications

•	Bi-directional properties

•	ParentBiDiMode property

•	FlipChildren method

•	Additional methods

•	Locale-specific features

•	Designing the user interface

•	Text

•	Graphic images

•	Formats and sort order

•	Keyboard mappings

•	Isolating resources

•	Creating resource DLLs

•	Using resource DLLs

•	Dynamic switching of resource DLLs

•	Localizing applications


Deploying applications

Related topic groups

•	Deploying applications: Overview

•	Deploying general applications

•	Using installation programs

•	Identifying application files

•	Application files, listed by file name extension

•	Package files

•	ActiveX controls

•	Helper applications

•	DLL locations

•	Deploying database applications

•	Providing the database engine

•	Borland Database Engine

•	Third-party database engines

•	SQL Links

•	Multi-tiered Distributed Application Services (MIDAS)

•	Deploying Web applications

•	Programming for varying host environments

•	Screen resolutions and color depths

•	Considerations when not dynamically resizing

•	Considerations when dynamically resizing forms and controls

•	Accomodating varying color depths

•	Fonts

•	Windows versions

•	Software license requirements


C++ language support for the VCL

Related topic groups

•	C++ language support for the VCL

•	C++ and Object Pascal object models

•	Object identity and instantiation

•	Object construction for C++Builder VCL classes

•	Calling virtual methods in base class constructors

•	Example: calling virtual methods

•	Constructor initialization of data members for virtual functions

•	Object destruction

•	AfterConstruction and BeforeDestruction

•	Class virtual functions

•	Support for Object Pascal data types and language concepts

•	Typedefs

•	Classes that support the Object Pascal language

•	C++ language counterparts to the Object Pascal language

•	Open arrays

•	Calculating the number of elements

•	Temporaries

•	array of const

•	OPENARRAY macro

•	EXISTINGARRAY macro

•	C++ functions that take open array arguments

•	Types defined differently

•	Resource strings

•	Default parameters

•	Runtime type information

•	Unmapped types

•	Keyword extensions

•	The __declspec keyword extension