devwin32
devwin32
Table of Contents
Concepts 1
Debugging C++ Applications with CodeGuard Error Reporting 3
CodeGuard Errors 3
Access Errors 4
Exception Errors 5
Function Failure Errors 6
Resource Errors 7
CodeGuard Overview 9
CodeGuard Warnings 10
Memory Block Comparison Warnings 11
Pathname Merging and Splitting Warnings 11
String Comparison Warnings 11
iii
RAD Studio
Procedures 47
CodeGuard Procedures 48
Using CodeGuard 48
Database Procedures 50
Accessing Schema Information 51
Using Data Explorer to Obtain Connection Information 52
Configuring TSQL Connection 53
Connecting to the Application Server using DataSnap Components 55
Debugging dbExpress Applications using TSQLMonitor 55
Executing the Commands using TSQLDataSet 56
Fetching the Data using TSQLDataSet 57
Specifying the Data to Display using TSQLDataSet 58
Specifying the Provider using TLocalConnection or TConnectionBroker 59
Using BDE 60
Using DataSnap 60
Using TBatchMove (BDE) 61
Connecting to Databases with TDatabase 62
Using TQuery (Procedure) 63
Using TSQLQuery 65
Using TSQLStoredProc (Procedure) 66
Using TSQLTable 66
Managing Database Sessions Using TSession 67
Using TSimpleDataSet 68
Using TSimpleObjectBroker 69
Using TStoredProc 69
Using TTable (Procedure) 70
Using TUpdateSQL to Update a Dataset 72
Using dbExpress 72
Adding a New Connection to the Data Explorer 73
Browsing a Database in the Data Explorer 74
Executing SQL in the Data Explorer 74
Modifying Connections in the Data Explorer 75
Connecting to a Database using the dbExpress Driver Framework 76
iv
RAD Studio
Reporting Procedures 81
Adding Rave Reports to RAD Studio 81
VCL Procedures 82
Building a Windows "Hello World" Console Application 88
Developing a Windows Application 89
Building Application Menus 90
Building a VCL Forms Application with Decision Support Components 91
Building VCL Forms Applications With Graphics 93
Building a VCL Forms MDI Application Using a Wizard 93
Building a VCL Forms MDI Application Without Using a Wizard 94
Building a VCL Forms SDI Application 96
Creating a New VCL Component 97
Building a VCL Forms ADO Database Application 98
Building a VCL Forms Application 99
Creating Actions in a VCL Forms Application 100
Building a VCL Forms "Hello World" Application 101
Using ActionManager to Create Actions in a VCL Forms Application 102
Building a VCL Forms dbExpress Database Application 103
Building an Application with XML Components 104
Copying Data From One Stream To Another 106
Copying a Complete String List (VCL) 107
Creating Strings 109
Creating a VCL Form Instance Using a Local Variable 110
Deleting Strings 112
Displaying an Auto-Created VCL Form 113
Displaying a Bitmap Image in a VCL Forms Application 114
Displaying a Full View Bitmap Image in a VCL Forms Application 116
Drawing a Polygon in a VCL Forms Application 117
Drawing Rectangles and Ellipses in a VCL Forms Application 118
Drawing a Rounded Rectangle in a VCL Forms Application 118
Drawing Straight Lines In a VCL Forms Application 119
Dynamically Creating a VCL Modal Form 120
Dynamically Creating a VCL Modeless Form 121
Iterating Through Strings in a List 123
Building a Multithreaded Application 124
Writing Cleanup Code 125
Avoiding Simultaneous Thread Access to the Same Memory 125
v
RAD Studio
Reference 155
C++ Reference 156
Command Line Utilities 156
BCC32, the C++ Command-Line Compiler 159
BRC32, the Resource Shell 163
BRCC32.EXE, the Resource Compiler 165
COFF2OMF.EXE, the Import Library Conversion Tool 166
CPP32.EXE, the C Compiler Preprocessor 167
DCC32.EXE, the Delphi Command Line Compiler 169
GREP.EXE, the text search utility 170
ILINK32.EXE, the Incremental Linker 174
IMPDEF.EXE, the Module Definition Manager 179
IMPLIB.EXE, the Import Library Tool 181
Using Include Files 182
MAKE 183
vi
RAD Studio
vii
RAD Studio
viii
RAD Studio
E2480: Cannot involve template parameters in complex partial specialization arguments (C++) 269
E2392: Template instance 'template' is already instantiated (C++) 270
E2393: Cannot take the address of non-type, non-reference template parameter 'parameter' (C++) 270
E2399: Cannot reference template argument 'arg' in template class 'class' this way (C++) 270
E2397: Template argument cannot have static or local linkage (C++) 270
E2485: Cannot use address of array element as non-type template argument (C++) 271
E2402: Illegal base class type: formal type 'type' resolves to 'type' (C++) 271
E2403: Dependent call specifier yields non-function 'name' (C++) 271
E2404: Dependent type qualifier 'qualifier' has no member type named 'name' (C++) 271
E2405: Dependent template reference 'identifier' yields non-template symbol (C++) 271
E2406: Dependent type qualifier 'qualifier' is not a class or struct type (C++) 272
E2407: Dependent type qualifier 'qualifier' has no member symbol named 'name' (C++) 272
E2408: Default values may be specified only in primary class template declarations (C++) 272
E2409: Cannot find a valid specialization for 'specifier' (C++) 272
E2410: Missing template parameters for friend template 'template' (C++) 273
E2486: Cannot use address of class member as non-type template argument (C++) 273
E2411: Declaration of member function default parameters after a specialization has already been 273
expanded (C++)
E2412: Attempting to bind a member reference to a dependent type (C++) 273
E2414: Destructors cannot be declared as template functions (C++) 273
E2473: Invalid explicit specialization of 'specifier' (C++) 274
E2490: Specialization within template classes not yet implemented (C++) 274
E2416: Invalid template function declaration (C++) 274
E2417: Cannot specify template parameters in explicit specialization of 'specifier' (C++) 274
E2418: Maximum instantiation depth exceeded; check for recursion (C++) 274
E2420: Explicit instantiation can only be used at global scope (C++) 274
E2422: Argument kind mismatch in redeclaration of template parameter 'parameter' (C++) 275
E2423: Explicit specialization or instantiation of non-existing template 'template' (C++) 275
E2479: Cannot have both a template class and function named 'name' (C++) 275
E2484: The name of template class 'class' cannot be overloaded (C++) 275
E2426: Explicit specialization of 'specifier' requires 'template<>' declaration (C++) 275
E2487: Cannot specify default function arguments for explicit specializations (C++) 276
E2427: 'main' cannot be a template function (C++) 276
E2429: Not a valid partial specialization of 'specifier' (C++) 276
E2430: Number of template parameters does not match in redeclaration of 'specifier' (C++) 276
E2477: Too few template parameters were declared for template 'template' (C++) 276
E2478: Too many template parameters were declared for template 'template' (C++) 277
E2431: Non-type template parameters cannot be of floating point, class, or void type (C++) 277
E2434: Template declaration missing template parameters ('template<...>') (C++) 277
ix
RAD Studio
E2435: Too many template parameter sets were specified (C++) 277
E2436: Default type for template template argument 'arg' does not name a primary template class (C++) 277
E2437: 'typename' should be followed by a qualified, dependent type name (C++) 278
E2438: Template template arguments must name a class (C++) 278
E2439: 'typename' is only allowed in template declarations (C++) 278
E2440: Cannot generate specialization from 'specifier' because that type is not yet defined (C++) 278
E2441: Instantiating 'specifier' (C++) 278
E2503: Missing or incorrect version of TypeLibImport.dll (C++) 279
E2470: Need to include header <typeinfo> to use typeid (C++) 279
E2514: Cannot (yet) use member overload resolution during template instantiation (C++) 279
E2508: 'using' cannot refer to a template specialization (C++) 279
E2462: 'virtual' can only be used with non-template member functions (C++) 279
W8086: Incorrect use of #pragma alias "aliasName"="substituteName" (C++) 280
W8099: Static main is not treated as an entry point (C++) 280
W8093: Incorrect use of #pragma codeseg [seg_name] ["seg_class"] [group] (C++) 280
W8094: Incorrect use of #pragma comment( <type> [,"string"] ) (C++) 280
W8085: Function 'function' redefined as non-inline (C++) 281
W8105: %s member '%s' in class without constructors (C++) 281
W8095: Incorrect use of #pragma message( "string" ) (C++) 281
W8098: Multi-character character constant (C++) 281
W8096: Incorrect use of #pragma code_seg(["seg_name"[,"seg_class"]]) (C++) 281
W8083: Pragma pack pop with no matching pack push (C++) 282
W8097: Not all options can be restored at this time (C++) 282
W8084: Suggest parentheses to clarify precedence (C++) 282
W8092: 'type' argument 'specifier' passed to 'function' is not an iterator: 'type' iterator required (C++) 282
W8087: 'operator::operator==' must be publicly visible to be contained by a 'type' (C++) 283
W8090: 'type::operator<' must be publicly visible to be used with 'type' (C++) 283
W8089: 'type::operator<' must be publicly visible to be contained by a 'type' (C++) 283
W8091: 'type' argument 'specifier' passed to 'function' is a 'iterator category' iterator: 'iterator category' 283
iterator required (C++)
W8076: Template instance 'specifier' is already instantiated (C++) 283
W8077: Explicitly specializing an explicitly specialized class member makes no sense (C++) 283
Informational messages (C++) 284
E2196: Cannot take address of member function 'function' (C++) 284
F1002: Unable to create output file 'filename' (C++) 284
F1003: Error directive: 'message' (C++) 284
F1004: Internal compiler error (C++) 284
F1006: Bad call of intrinsic function (C++) 284
F1007: Irreducible expression tree (C++) 285
x
RAD Studio
xi
RAD Studio
xii
RAD Studio
xiii
RAD Studio
xiv
RAD Studio
xv
RAD Studio
xvi
RAD Studio
xvii
RAD Studio
E2354: Two operands must evaluate to the same type (C++) 332
E2355: Recursive template function: 'x' instantiated 'y' (C++) 333
E2356: Type mismatch in redeclaration of 'identifier' (C++) 333
E2357: Reference initialized with 'type1', needs lvalue of type 'type2' (C++) 333
E2358: Reference member 'member' needs a temporary for initialization (C++) 333
E2360: Invalid register combination (e.g. [BP+BX]) (C++) 334
E2361: 'specifier' has already been included (C++) 334
E2362: Repeat count needs an lvalue (C++) 334
E2363: Attempting to return a reference to local variable 'identifier' (C++) 334
E2364: Attempting to return a reference to a local object (C++) 334
E2365: Member pointer required on right side of .* or ->* (C++) 335
E2366: Can't inherit non-RTTI class from RTTI base OR E2367 Can't inherit RTTI class from non-RTTI 335
base (C++)
E2368: RTTI not available for expression evaluation (C++) 335
E2371: sizeof may not be applied to a bit field (C++) 335
E2372: sizeof may not be applied to a function (C++) 335
E2373: Bit field cannot be static (C++) 335
E2374: Function 'function' cannot be static (C++) 335
Stack overflow (C++) 335
E2376: statement missing (C++) 336
E2377: statement missing ) (C++) 336
E2378: do-while or for statement missing ; (C++) 336
E2379: Statement missing ; (C++) 336
E2380: Unterminated string or character constant (C++) 336
E2381: Structure size too large (C++) 336
E2382: Side effects are not allowed (C++) 336
E2383: Switch selection expression must be of integral type (C++) 336
E2433: Specialization after first use of template (C++) 337
E2384: Cannot call near class member function with a pointer of type 'type' (C++) 337
E2390: Type mismatch in parameter 'number' in template class name 'template' (C++) 337
E2391: Type mismatch in parameter 'parameter' in template class name 'template' (C++) 337
E2394: Too few arguments passed to template 'template' (C++) 337
E2395: Too many arguments passed to template 'template' (C++) 338
E2396: Template argument must be a constant expression (C++) 338
E2401: Invalid template argument list (C++) 338
E2400: Nontype template argument must be of scalar type (C++) 338
E2415: Template functions may only have 'type-arguments' (C++) 338
E2425: 'member' is not a valid template type member (C++) 338
E2428: Templates must be classes or functions (C++) 338
xviii
RAD Studio
E2432: 'template' qualifier must name a template class or function instance' (C++) 339
E2442: Two consecutive dots (C++) 339
E2443: Base class 'class' is initialized more than once (C++) 339
E2444: Member 'member' is initialized more than once (C++) 339
E2445: Variable 'identifier' is initialized more than once (C++) 339
E2446: Function definition cannot be a typedef'ed declaration (C++) 339
E2132: Templates and overloaded operators cannot have C linkage (C++) 339
E2447: 'identifier' must be a previously defined enumeration tag (C++) 340
E2448: Undefined label 'identifier' (C++) 340
E2449: Size of 'identifier' is unknown or zero (C++) 340
E2450: Undefined structure 'structure' (C++) 340
E2451: Undefined symbol 'identifier' (C++) 340
E2453: Size of the type 'identifier' is unknown or zero (C++) 340
E2452: Size of the type is unknown or zero (C++) 341
E2454: union cannot be a base type (C++) 341
E2455: union cannot have a base type (C++) 341
E2456: Union member 'member' is of type class with 'constructor' (or destructor, or operator =) (C++) 341
E2461: '%s' requires run-time initialization/finalization (C++) 341
E2464: 'virtual' can only be used with member functions (C++) 341
E2465: unions cannot have virtual member functions (C++) 342
E2466: void & is not a valid type (C++) 342
E2467: 'Void function' cannot return a value (C++) 342
E2468: Value of type void is not allowed (C++) 342
E2469: Cannot use tiny or huge memory model with Windows (C++) 342
E2006: CodeGuarded programs must use the large memory model and be targeted for Windows (C++) 342
E2269: The function 'function' is not available (C++) 342
E2124: Invalid function call (C++) 343
E2213: Invalid 'expression' in scope override (C++) 343
E2236: Missing 'identifier' in scope override (C++) 343
Pure virtual function called (C++) 343
E2095: String literal not allowed in this context (C++) 343
Unexpected termination during compilation [Module Seg#:offset] OR Unexpected termination during linking 343
[Module Seg#:offset] (C++)
E2012: Cannot take address of 'main' (C++) 344
E2016: Ambiguous override of virtual base member 'base_function': 'derived_function' (C++) 344
E2021: Array must have at least one element (C++) 344
E2023: Array of references is not allowed (C++) 344
E2032: Illegal use of closure pointer (C++) 344
E2040: Declaration terminated incorrectly (C++) 345
xix
RAD Studio
xx
RAD Studio
E2251: Cannot find default constructor to initialize base class 'class' (C++) 352
E2252: 'catch' expected (C++) 352
E2253: Calling convention must be attributed to the function type, not the closure (C++) 352
E2261: Use of dispid with a property requires a getter or setter (C++) 353
E2262: '__except' or '__finally' expected following '__try' (C++) 353
E2270: > expected (C++) 353
E2273: 'main' cannot be declared as static or inline (C++) 353
E2281: Identifier1 requires definition of Identifier2 as a pointer type (C++) 353
E2289: __published or __automated sections only supported for Delphi classes (C++) 353
E2298: Cannot generate 'function' from template function 'template' (C++) 354
E2301: Cannot use templates in closure arguments -- use a typedef (C++) 354
E2307: Type 'type' is not a defined class with virtual functions (C++) 354
E2315: 'Member' is not a member of 'class', because the type is not yet defined (C++) 354
E2318: 'type' is not a polymorphic class type (C++) 354
E2323: Illegal number suffix (C++) 355
E2326: Use __declspec(spec1[, spec2]) to combine multiple __declspecs (C++) 355
E2328: Classes with properties cannot be copied by value (C++) 355
E2331: Number of allowable option contexts exceeded (C++) 355
E2332: Variable 'variable' has been optimized and is not available (C++) 355
E2476: Cannot overload 'function' (C++) 356
E2346: 'x' access specifier of property 'property' must be a member function (C++) 356
E2347: Parameter mismatch in access specifier 'specifier' of property 'property' (C++) 356
E2348: Storage specifier not allowed for array properties (C++) 356
E2351: Static data members not allowed in __published or __automated sections (C++) 357
E2353: Class 'classname' is abstract because of 'member = 0' (C++) 357
E2359: Reference member 'member' initialized with a non-reference parameter (C++) 357
E2369: Cannot use the result of a property assignment as an rvalue' (C++) 358
E2370: Simple type name expected (C++) 358
E2398: Template function argument 'argument' not used in argument types (C++) 358
E2419: Error while instantiating template 'template' (C++) 358
E2424: Template class nesting too deep: 'class' (C++) 358
E2457: Delphi style classes must be caught by reference (C++) 359
E2458: Delphi classes have to be derived from Delphi classes (C++) 359
E2459: Delphi style classes must be constructed using operator new (C++) 359
E2460: Delphi style classes require exception handling to be enabled (C++) 360
E2463: 'base' is an indirect virtual base class of 'class' (C++) 360
Null pointer assignment (C++) 360
E2268: Call to undefined function 'function' (C++) 360
E2375: Assembler stack overflow (C++) 360
xxi
RAD Studio
xxii
RAD Studio
xxiii
RAD Studio
W8027: Functions containing 'statement' are not expanded inline (C++) 378
W8036: Non-ANSI keyword used: 'keyword' (C++) 378
W8053: 'ident' is obsolete (C++) 379
W8103: Path 'path' and filename 'filename' exceed maximum size of 'n' (C++) 379
W8062: Previous options and warnings not restored (C++) 379
W8055: Possible overflow in shift operation (C++) 379
W8072: Suspicious pointer arithmetic (C++) 379
W8033: Conversion to 'type' will fail for members of virtual base 'class' (C++) 380
W8034: Maximum precision used for member pointer type 'type' (C++) 380
E2537: Cannot create instance of abstract class (C++) 380
E2018: Cannot catch 'identifier' -- ambiguous base class 'identifier' (C++) 380
E2550: No arguments can follow a variadic template in an argument list (C++) 381
E2538: Static assert failed: '%s' (C++) 381
E2548: ... was unexpected; expression is not a variadic template pattern (C++) 381
E2543: Combination of options 'options' is not permitted (C++) 381
E2549: Operand is not a parameter pack (C++) 381
E2544: Function exception specifications do not match (C++) 381
E2536: Incomplete type cannot be part of a exception declaration (C++) 381
E2535: Incomplete type cannot be part of a throw specification (C++) 382
E2532: Constant in new expression requires an initializer (C++) 382
E2541: Attribute '%s' cannot be set (C++) 382
E2545: Enum underlying type must be an integral (C++) 382
E2546: Redeclaration of enum is not identical (C++) 382
E2533: Parameter mismatch (wanted typename) (C++) 382
E2534: Integral constant expression expected (C++) 382
E2531: Parameter is an incomplete type (C++) 383
E2539: Constant expression expected (C++) 383
E2547: ... expected (C++) 383
E2540: String literal expected (C++) 383
E2552: This feature is not (yet) supported (C++) 383
E2542: '%s' is marked 'final' and cannot be overriden (C++) 383
E2553: %s mismatch in redeclaration of '%s' (C++) 383
E2551: Return statement not allowed in __finally block (C++) 384
W8104: Local Static with constructor dangerous for multi-threaded apps (C++) 384
W8106: %s are deprecated (C++) 384
W8110: Duplicate '%s' attribute directive ignored (C++) 384
W8108: Constant in new expression requires an initializer (C++) 384
W8113: Inline function was declared with 'extern template' (C++) 384
W8109: Parameter '%s' is a dependent type (C++) 385
xxiv
RAD Studio
xxv
RAD Studio
stdlib.h 1080
string.h 1139
sys\stat.h 1186
sys\timeb.h 1190
sys\types.h 1192
time.h 1193
typeinfo.h 1211
utime.h 1213
values.h 1214
xxvi
RAD Studio
Index a
xxvii
1 RAD Studio
1 Concepts
Topics
Name Description
Debugging C++ Applications with CodeGuard Error Reporting ( see page 3) CodeGuard provides runtime debugging for C++ applications developed with
RAD Studio. CodeGuard reports errors that are not caught by the compiler
because they do not violate syntax rules. CodeGuard tracks runtime libraries with
full support for multithreaded applications.
Developing Database Applications for the Win32 Platform ( see page 13) The Borland Database Engine (BDE) has been deprecated, so it will not be
enhanced. For instance, BDE will never have Unicode support. You should not
undertake new development with BDE. Consider migrating your existing
database applications from BDE to dbExpress.
Database applications let users interact with the information that is stored in the
databases. Databases provide structure for the information, and allow it to be
shared among different applications.
Delphi provides support for relational database applications. Relational
databases organize information into tables, which contain rows (records) and
columns (fields). These tables can be manipulated by simple operations known
as... more ( see page 13)
Developing Interoperable Applications ( see page 29) RAD Studio provides wizards and classes to make it easy to implement
applications based on the Component Object Model (COM) from Microsoft. With
these wizards, you can create COM-based classes and components to use within
applications or you can create fully functional COM clients or servers that
implement COM objects, Automation servers (including Active Server Objects),
ActiveX controls, or ActiveForms.
Developing Reports for Your Win32 Applications ( see page 35) RAD Studio ships with Rave Reports from Nevrona. Using the report
components, you can build full-featured reports for your applications. You can
create solutions that include reporting capabilities which can be used and
customized by your customers. Additionally, the ComponentOne tools that ship
with RAD Studio include components for creating and generating reports.
Developing Applications with VCL Components ( see page 36) The Visual Component Library (VCL) is a set of visual components for the rapid
development of Windows applications in the Delphi language.
VCL contains a wide variety of visual, non-visual, and utility classes for tasks
such as building Windows applications, web applications, database applications,
and console applications.
Developing Web Applications with WebSnap ( see page 41) This section provides a conceptual background for building WebSnap
applications using RAD Studio. WebSnap makes it easier to build Web server
applications that deliver complex, data-driven Web pages. WebSnap's support
for multiple modules and for server-side scripting makes development and
maintenance easier for teams of developers and Web designers.
Please note that WebSnap is being deprecated in RAD Studio. Although
WebSnap is still documented in the online help, the WebSnap product is no
longer fully supported. As an alternative, you should begin using IntraWeb (VCL
for the Web). IntraWeb ( see page 2254) is documented in this online help. For
more documentation on VCL... more ( see page 41)
1
RAD Studio 1
Developing Web Services with Win32 Applications ( see page 44) Web Services are self-contained modular applications that can be published and
invoked over the Internet. Web Services provide well-defined interfaces that
describe the services provided. Unlike Web server applications that generate
Web pages for client browsers, Web Services are not designed for direct human
interaction. Rather, they are accessed programmatically by client applications.
This section gives an overview of web services and web services support.
Developing Windows Applications ( see page 45) Windows provides a traditional approach to developing user interfaces,
client/server applications, controls, and application logic. This section provides an
overview of Windows application development using RAD Studio for Win32 and
outlines the steps you would use to build a simple Windows project.
2
1.1 Debugging C++ Applications with RAD Studio CodeGuard Errors
Topics
Name Description
CodeGuard Errors ( see page 3) CodeGuard reports four types of runtime errors.
CodeGuard Overview ( see page 9) CodeGuard provides runtime debugging for C++ applications developed with
RAD Studio. CodeGuard reports errors that are not caught by the compiler
because they do not violate syntax rules. CodeGuard tracks runtime libraries with
full support for multithreaded applications.
CodeGuard provides two principal types of coverage:
Topics
Name Description
Access Errors ( see page 4) Access errors result from improper memory management.
When CodeGuard detects accesses to freed memory blocks or deleted objects, it
can identify where each block was allocated and deleted. Enable the Delay Free
option using the CodeGuard Configuration dialog box to use this feature.
The following are types of access errors:
3
CodeGuard Errors RAD Studio 1.1 Debugging C++ Applications with
Resource Errors ( see page 7) Resources are memory blocks (allocated with functions like malloc,
GlobalAlloc) and object arrays, such as file handles, stream handles,
modules, and items returned by new[].
The following runtime error examples illustrate how CodeGuard reports improper
use of resources:
• Bad parameter
• Reference to freed resource
• Resource type mismatch
1
• Resource leaks
• Resource from different RTL
When CodeGuard detects accesses to freed memory blocks or deleted objects, it can identify where each block was allocated
and deleted. Enable the Delay Free option using the CodeGuard Configuration dialog box to use this feature.
The memory block (0x00B423DC) [size: 21 bytes] was allocated with malloc
| lang.cpp line 80:
| char * pad = (char *) malloc(200);
| // An array in the RTL heap.
|> char * buf_h = (char *) malloc(21);
| char * p;
| // A scratch buffer.
Call Tree:
0x004011A1(=LANG.EXE:0x01:0001A1) lang.cpp#80
0x00407EE5(=LANG.EXE:0x01:006EE5)
4
1.1 Debugging C++ Applications with RAD Studio CodeGuard Errors
|
Call Tree:
0x004011E5(=LANG.EXE:0x01:0001E5) lang.cpp#105
0x00407EE5(=LANG.EXE:0x01:006EE5)
Access In Uninitialized Stack
In the following example, the pointer p became invalid when getBadLocal returned from execution. No additional information is
provided because the stack frame for getBadLocal was automatically removed.
Error 00005. 0x120400 (Thread 0xFFF87283): 1
Access in uninitialized stack: Attempt to access 20 byte(s) at 0x0072FC88.
memcpy(0x0072FCC4, 0x0072FC88, 0x14 [20])
| lang.cpp line 112:
| //-----------------------//
| p = getBadLocal();
|> memcpy(buffer, p, 20);
|
| //-------------//
Call Tree:
0x00401208(=LANG.EXE:0x01:000208) lang.cpp#112
0x00407EE5(=LANG.EXE:0x01:006EE5)
Access In Invalid Stack
In the following example, an allocation was made for buf_s on the stack. However, the strcpy function writes just below the
beginning of the valid stack region. CodeGuard identifies this as an error even if the string is only one byte long.
Error 00002. 0x110400 (Thread 0xFFF87283):
Access in invalid stack: Attempt to access 22 byte(s) at 0x0072FD8F.
strcpy(0x0072FD8F, 0x00409188 ["This string is long!\n"])
| LANG.CPP line 93:
|
| // Stack underrun:
|> strcpy(buf_s -1, "This string is long!\n");
|
| // Global data overrun:
Call Tree:
0x004011C5(=LANG.EXE:0x01:0001C5) LANG.CPP#93
0x00407EED(=LANG.EXE:0x01:006EED)
5
CodeGuard Errors RAD Studio 1.1 Debugging C++ Applications with
|> *q = 1;
| }
| }
Call Tree:
0x004010E5(=GPFAULT.EXE:0x01:0000E5) gpfault.c#32
0x00406B29(=GPFAULT.EXE:0x01:005B29)
The bogus value (0x80828082) was most likely retrieved by accessing a(n)
memory block that has already been freed
The memory block (0x008322A4) [size: 16 bytes] was allocated with malloc
1 | gpfault.c line 17:
| int *q;
|
|> p = malloc(sizeof(*p) * 4);
|
| /* Initialize p */
Call Tree:
0x00401094(=GPFAULT.EXE:0x01:000094) gpfault.c#17
0x00406B29(=GPFAULT.EXE:0x01:005B29)
In the following example, the close function is given an invalid file handle, which causes it to return a value indicating that it was
unable to close a file.
Error 00009. 0x820000 (r) (Thread 0xFFF840F1):
Function failure:
close(0x80868086 [-2138668922])=0xFFFFFFFF [-1]
| lang.cpp line 125:
| // uninitialized data usage //
| //--------------------------//
|> close(m->handle);
|
|
Call Tree:
6
1.1 Debugging C++ Applications with RAD Studio CodeGuard Errors
0x00401236(=LANG.EXE:0x01:000236) lang.cpp#125
0x00407EED(=LANG.EXE:0x01:006EED)
The following runtime error examples illustrate how CodeGuard reports improper use of resources: 1
• Bad parameter
• Reference to freed resource
• Resource type mismatch
• Resource leaks
• Resource from different RTL
Bad Parameter
When a resource is passed to a function, CodeGuard checks the runtime arguments. CodeGuard notifies you if it detects a bad
parameter.
Error 00017. 0x310000 (Thread 0xFFF87283):
Bad parameter: A bad file handle (0xEA) has been passed to the function.
close(0xEA [234])
| lang.cpp line 170:
| // using a bad handle //
| //--------------------//
|> close(234);
|
| //----------------------//
Call Tree:
0x00401456(=LANG.EXE:0x01:000456) lang.cpp#170
0x00407EE5(=LANG.EXE:0x01:006EE5)
Reference To Freed Resource
In the following example, CodeGuard reports an attempt to read from a file that has already been closed. The CodeGuard log
shows where the file was opened and subsequently closed.
Error 00020. 0x310030 (Thread 0xFFF840F1):
Reference to freed resource:
read(0x3 [3], 0x0072FCC4, 0x5 [5])
| lang.cpp line 177:
| int i = open("lang.cpp", 0);
| close(i);
|> read (i, buffer, 5);
|
| //--------------//
Call Tree:
0x00401487(=LANG.EXE:0x01:000487) lang.cpp#177
0x00407EED(=LANG.EXE:0x01:006EED)
The file handle (0x00000003) [name: 'lang.cpp'] was opened with open
| lang.cpp line 175:
| // using a freed handle //
| //----------------------//
|> int i = open("lang.cpp", 0);
| close(i);
| read (i, buffer, 5);
Call Tree:
0x0040146C(=LANG.EXE:0x01:00046C) lang.cpp#175
0x00407EED(=LANG.EXE:0x01:006EED)
7
CodeGuard Errors RAD Studio 1.1 Debugging C++ Applications with
The object array (0x00B42464) [size: 21 bytes] was created with new[]
| lang.cpp line 187:
| // type mismatch //
| //---------------//
|> char * ss = new char[21];
| free(ss);
|
Call Tree:
0x00401498(=LANG.EXE:0x01:000498) lang.cpp#187
0x00407EED(=LANG.EXE:0x01:006EED)
Resource Leaks
In the following example, memory has been allocated but is never freed.
The memory block (0x00B42310) [size: 200 bytes] was allocated with malloc
| lang.cpp line 78:
| // An array on the stack.
| char buf_s[21];
|> char * pad = (char *) malloc(200);
| // An array in the RTL heap.
| char * buf_h = (char *) malloc(21);
Call Tree:
0x00401199(=LANG.EXE:0x01:000199) lang.cpp#78
0x00407EE5(=LANG.EXE:0x01:006EE5)
Resource From Different RTL
CodeGuard reports an error if your application allocates, uses, or releases resources in different versions of the runtime library.
This can happen, as the following example illustrates, if you link with a static runtime library but call a DLL.
Note: CodeGuard detects resource type mismatches before it detects mixed versions of the RTL. When the two kinds of error
are combined, CodeGuard will not report the mixed RTLs until you correct the resource type mismatch.
8
1.1 Debugging C++ Applications with RAD Studio CodeGuard Warnings
close(0x3 [3])
| testdll.cpp line 23:
| {¬
| MessageBox(NULL,"RTLMixHandle: DLL closing EXE handle", "TESTDLL.CPP", MB_OK );
|> close( handle );
| return 1;
| }
Call Tree:
0x0032115A(=testdll.dll:0x01:00015A) testdll.cpp#23
0x00401660(=WINAPI.EXE:0x01:000660) filescg.cpp#33
0x00401271(=WINAPI.EXE:0x01:000271) winapi.cpp#122 1
0x77EA15B3
0x00408B9A(=WINAPI.EXE:0x01:007B9A)
The file handle (0x00000003) [name: 'test2.dat'] was opened with open
| filescg.cpp line 32:
|
| MessageBox(NULL,"FilesMixCG: Mixing RTL file handles", "FILESCG.CPP", MB_OK );
|> i = open("test2.dat", O_CREAT, S_IREAD | S_IWRITE );
| RTLMixHandle( i );
| }
Call Tree:
0x00401657(=WINAPI.EXE:0x01:000657) filescg.cpp#32
0x00401271(=WINAPI.EXE:0x01:000271) winapi.cpp#122
0x77EA15B3
0x00408B9A(=WINAPI.EXE:0x01:007B9A)
See Also
CodeGuard Errors ( see page 3)
9
CodeGuard Warnings RAD Studio 1.1 Debugging C++ Applications with
1 Topics
Name Description
Memory Block Comparison Warnings ( see page 11) Each of the following functions has a parameter that determines the maximum
number of bytes it compares:
1. memcmp
2. memicmp
3. _fmemcmp
4. _fmemicmp
If the Warnings option is enabled for the functions listed
above, CodeGuard verifies that a comparison can be
performed for each memory block passed to the function.
If a memory block is too large, as determined by the
parameter passed to the function, CodeGuard generates
a warning.
If the Warnings option is disabled for the functions listed
above, CodeGuard checks the first byte in each memory
block passed to the function. If the memory block is
invalid, CodeGuard generates... more ( see page 11)
Pathname Merging and Splitting Warnings ( see page 11) Each of the following functions use constants defined in dir.h to determine the
maximum number of bytes to copy to or from a buffer:
1. fnmerge
2. fnsplit
3. getcurdir
String Comparison Warnings ( see page 11) Each of the following functions has a parameter that determines the maximum
number of bytes it compares:
• strncmp
• strnicmp
• strncmpi
• _fstrncmp
• _fstrnicmp
If the Warnings option is enabled for the functions listed,
CodeGuard verifies that a string comparison can be
performed for each buffer passed to the function. If the
buffer size is too large, as determined by the parameter
passed to the function, and the buffer is not
null-terminated, CodeGuard generates a warning.
If the Warnings option is disabled for the functions listed
above, CodeGuard checks the first byte in each memory
block passed to the function. If the... more ( see page 11)
10
1.1 Debugging C++ Applications with RAD Studio CodeGuard Warnings
1. memcmp
2. memicmp
3. _fmemcmp 1
4. _fmemicmp
If the Warnings option is enabled for the functions listed above, CodeGuard verifies that a comparison can be performed for
each memory block passed to the function. If a memory block is too large, as determined by the parameter passed to the
function, CodeGuard generates a warning.
If the Warnings option is disabled for the functions listed above, CodeGuard checks the first byte in each memory block passed
to the function. If the memory block is invalid, CodeGuard generates an error message.
1. fnmerge
2. fnsplit
3. getcurdir
fnmerge
If the Warnings option is enabled, the output buffer is validated against MAXPATH before fnmerge is called.
If the Warnings option is disabled, the size of the output buffer is validated against the null-terminated string length after
fnmerge is called.
fnsplit
If the Warnings option is enabled, the input buffers are validated against MAXDRIVE, MAXDIR, MAXFILE, and MAXEXT before
fnsplit is called.
If the Warnings option is disabled, the input buffers are validated against the length of the null-terminated string after fnsplit
is called.
getcurdir
If the Warnings option is enabled, the output buffer is validated against MAXDIR before getcurdir is called.
If the Warnings option is disabled, the output buffer is validated against the length of the null-terminated string after getcurdir
is called.
• strncmp
• strnicmp
• strncmpi
11
CodeGuard Warnings RAD Studio 1.1 Debugging C++ Applications with
• _fstrncmp
• _fstrnicmp
If the Warnings option is enabled for the functions listed, CodeGuard verifies that a string comparison can be performed for
each buffer passed to the function. If the buffer size is too large, as determined by the parameter passed to the function, and
the buffer is not null-terminated, CodeGuard generates a warning.
If the Warnings option is disabled for the functions listed above, CodeGuard checks the first byte in each memory block passed
to the function. If the memory block is invalid, CodeGuard generates an error message.
1
12
1.2 Developing Database Applications for RAD Studio
Database applications let users interact with the information that is stored in the databases. Databases provide structure for the
information, and allow it to be shared among different applications.
Delphi provides support for relational database applications. Relational databases organize information into tables, which contain
rows (records) and columns (fields). These tables can be manipulated by simple operations known as the relational calculus.
Topics
Name Description
dbGo Overview ( see page 14) dbGo provides the developers with a powerful and logical object model for
programmatically accessing, editing, and updating data from a wide variety of
data sources through OLE DB system interfaces. The most common usage of
dbGo is to query a table or tables in a relational database, retrieve and display
the results in an application, and perhaps allow users to make and save changes
to the data.
The ADO layer of an ADO-based application consists of the latest version of
Microsoft ADO, an OLE DB provider or ODBC driver for the data store access,
client software for the... more ( see page 14)
BDE Overview ( see page 15) Warning: The Borland Database Engine (BDE) has been deprecated, so it will
not be enhanced. For instance, BDE will never have Unicode support. You
should not undertake new development with BDE. Consider migrating your
existing database applications from BDE to dbExpress.
The Borland Database Engine (BDE) is a data-access mechanism that can be
shared by several applications. The BDE defines a powerful library of API calls
that can create, restructure, fetch data from, update, and otherwise manipulate
local and remote database servers. The BDE provides a uniform interface to
access a wide variety of database servers, using drivers... more ( see page 15)
dbExpress Components ( see page 16) dbExpress is a set of lightweight database components that provide fast access
to SQL database servers. For each supported database, dbExpress provides a
driver framework that adapts the server-specific software to a set of uniform
dbExpress interfaces. When you deploy a database application that uses
dbExpress, you include a DLL(the server-specific driver) with the application files
you build.
dbExpress lets you access databases using unidirectional datasets.
Unidirectional datasets are designed for quick lightweight access to database
information, with minimal overhead. Like other datasets, they can send an SQL
command to the database server, and if the command returns a set... more (
see page 16)
Getting Started with InterBase Express ( see page 17) InterBase Express (IBX) is a set of data access components that provide a
means of accessing data from InterBase databases. The InterBase
Administration Components, which require InterBase, are described after the
InterBase data access components.
13
dbGo Overview RAD Studio 1.2 Developing Database Applications for
dbExpress 4 Feature Overview ( see page 22) dbExpress's top level framework and metadata support has been rewritten in
Delphi for RAD Studio 2007. It has new, richer metadata support.
The DbxClient driver remotes the dbExpress 4 framework interface over a
network based transport.
This document discusses the following features:
• dbExpress Framework
• dbExpress Metadata Improvements
• DBXClient Driver
1
• DBXDynalink Driver
• DBTest
Blackfish SQL Overview ( see page 24) The design and implementation of Blackfish SQL emphasizes database
performance, scalability, ease of use, and a strong adherence to industry
standards. Blackfish SQL capabilities include the following:
The ADO layer of an ADO-based application consists of the latest version of Microsoft ADO, an OLE DB provider or ODBC
14
1.2 Developing Database Applications for RAD Studio BDE Overview
driver for the data store access, client software for the specific database system used (in the case of SQL databases), a
database back-end system accessible to the application (for SQL database systems), and a database. All of these must be
accessible to the ADO-based application for it to be fully functional.
The dbGo category of the Tool Palette hosts the dbGo components. These components let you connect to an ADO data store,
execute commands, and retrieve data from tables in databases using the ADO framework. The components require the latest
version of ADO to be installed on the host computer. Additionally, client software for the target database system (such as
Microsoft SQL Server) must be installed, as well as an OLE DB driver or ODBC driver specific to the particular database system.
1
Most dbGo components have direct counterparts in the components available for other data access mechanisms: a database
connection component, TADOConnection, and various types of datasets. In addition, dbGo includes TADOCommand, a
simple component that is not a dataset but which represents an SQL command to be executed on the ADO data store.
Components Function
TADOConnection A database connection component that establishes a connection with an ADO data store.
Multiple ADO dataset and command components can share this connection to execute commands,
retrieve data, and operate on metadata.
TRDSConnection A database connection component to marshal data in multi-tier database applications that are built using
ADO-based application servers.
TADODataSet Primary dataset used for retrieving and operating on data.
TADODataSet can retrieve data from a single or multiple tables, can connect directly to a data store, or
use a TADOConnection component
TADOTable A table-type dataset for retrieving and operating on a recordset produced by a single database table.
TADOTable can connect directly to a data store or use a TADOConnection component
TADOQuery A query-type dataset for retrieving and operating on a recordset produced by a valid SQL statement.
TADOQuery can also execute Data Definition Language (DDL) SQL statements. It can connect directly to
a data store or use a TADOConnection component.
TADOStoredProc A stored procedure-type dataset for executing stored procedures.
TADOStoredProc executes stored procedures that may or may not retrieve data. It can connect directly to
a data store or use a TADOConnection component.
TADOCommand A simple component for executing commands (SQL statements that do not return result sets).
TADOCommand can be used with a supporting dataset component, or retrieve a dataset from a table. It
can connect directly to a data store or use a TADOConnection component
See Also
Working with dbGo Components ( see page 1494)
The Borland Database Engine (BDE) is a data-access mechanism that can be shared by several applications. The BDE defines
a powerful library of API calls that can create, restructure, fetch data from, update, and otherwise manipulate local and remote
database servers. The BDE provides a uniform interface to access a wide variety of database servers, using drivers to connect
to different databases. The components on the BDE category of the Tool Palette enable you to connect to database information
15
dbExpress Components RAD Studio 1.2 Developing Database Applications for
When deploying BDE-based applications, you must include the BDE with your application. While this increases the size of the
application and the complexity of deployment, the BDE can be shared with other BDE-based applications and provides a broader
range of support for database manipulation. Although you can use the API of the BDE directly in your application, the
components on the BDE category of the Tool Palette wrap most of this functionality for you.
1 Components Function
TTable Retrieves data from a physical database table via the BDE and supplies it to one or more data-aware
components through a DataSource component. Conversely, it also sends data received from a
component to a physical database via the BDE.
TQuery Uses SQL statements to retrieve data from a physical database table via the BDE and supplies it to
one or more data-aware components through a TDataSource component. Conversely, it uses SQL
statements to send data from a component to a physical database via the BDE.
TStoredProc Enables an application to access server stored procedures. It sends data received from a component
to a physical database via the BDE.
TDatabase Sets up a persistent connection to a database, especially a remote database requiring a user login and
password.
TSession Provides global control over a group of database components. A default TSession component is
automatically created for each database application. You must use the TSession component only if
you are creating a multithreaded database application. Each database thread requires its own session
component.
TBatchMove Copies a table structure or its data. It can be used to move entire tables from one database format to
another.
TUpdateSQL Lets you use cached updates support with read-only datasets.
TNestedTable Retrieves the data in a nested dataset field and supplies it to data-aware controls through a
datasource component.
See Also
Using BDE ( see page 60)
dbExpress lets you access databases using unidirectional datasets. Unidirectional datasets are designed for quick lightweight
access to database information, with minimal overhead. Like other datasets, they can send an SQL command to the database
server, and if the command returns a set of records, retrieve those records. Unidirectional datasets do not buffer data in memory,
which makes them faster and less resource-intensive than other types of dataset. However, because there are no buffered
records, unidirectional datasets are also less flexible than other datasets.
dbExpress connections, tables, views, and stored procedures that show up in a data tree view support drag & drop with native
and managed vcl forms.
16
1.2 Developing Database Applications for RAD Studio Getting Started with InterBase Express
The dbExpress category of the Tool Palette contains components that use dbExpress to access database information. They
are:
Components Function
TSQLConnection Encapsulates a dbExpress connection to a database server
TSQLDataSet Represents any data available through dbExpress, or sends commands to a database
accessed through dbExpress
TSQLQuery A query-type dataset that encapsulates an SQL statement and enables applications to access 1
the resulting records, if any
TSQLTable A table-type dataset that represents all of the rows and columns of a single database table
TSQLStoredProc A stored procedure-type dataset that executes a stored procedure defined on a database
server
TSQLMonitor Intercepts messages that pass between an SQL connection component and a database
server and saves them in a string list
TSimpleDataSet A client dataset that uses an internal TSQLDataSet and TDataSetProvider for fetching data
and applying updates
See Also
Using dbExpress ( see page 72)
IBX components
The following components are located on the InterBase tab of the component palette.
TIBTable
TIBQuery
TIBStoredProc
TIBDatabase
TIBTransaction
TIBUpdateSQL
TIBDataSet
TIBSQL
TIBDatabaseInfo
TIBSQLMonitor
17
Getting Started with InterBase Express RAD Studio 1.2 Developing Database Applications for
TIBEvents
TIBExtract
TIBCustomDataSet
Though they are similar to BDE components in name, the IBX components are somewhat different. For each component with a
BDE counterpart, the sections below give a discussion of these differences.
1
There is no simple migration from BDE to IBX applications. Generally, you must replace BDE components with the comparable
IBX components, and then recompile your applications. However, the speed you gain, along with the access you get to the
powerful InterBase features make migration well worth your time.
IBDatabase
Use a TIBDatabase component to establish connections to databases, which can involve one or more concurrent transactions.
Unlike BDE, IBX has a separate transaction component, which allows you to separate transactions and database connections.
user_name=sysdba
password=masterkey
IBTransaction
Unlike the Borland Database Engine, IBX controls transactions with a separate component, TIBTransaction. This powerful
feature allows you to separate transactions and database connections, so you can take advantage of the InterBase two-phase
commit functionality (transactions that span multiple connections) and multiple concurrent transactions using the same
connection.
Use an IBTransaction component to handle transaction contexts, which might involve one or more database connections. In
most cases, a simple one database/one transaction model will do.
To set up a transaction:
18
1.2 Developing Database Applications for RAD Studio Getting Started with InterBase Express
FieldByName(EmpNo)
would return nothing in dialect 3 if the field was 'EMPNO'.
IBStoredProc
Use TIBStoredProc for InterBase executable procedures: procedures that return, at most, one row of information. For stored
procedures that return more than one row of data, or "Select" procedures, use either IBQuery or IBDataSet components.
IBSQL
19
Getting Started with InterBase Express RAD Studio 1.2 Developing Database Applications for
Use an TIBSQL component for data operations that need to be fast and lightweight. Operations such as data definition and
pumping data from one database to another are suitable for IBSQL components.
In the following example, an IBSQL component is used to return the next value from a generator:
Use an TIBUpdateSQL component to update read-only datasets. You can update IBQuery output with an IBUpdateSQL
component:
Use an IBEvents component to register interest in, and asynchronously handle, events posted by an InterBase server.
20
1.2 Developing Database Applications for RAD Studio Getting Started with InterBase Express
TIBConfigService
TIBBackupService
TIBRestoreService
1
TIBValidationService
TIBStatisticalService
TIBLogService
TIBSecurityService
TIBLicensingService
TIBServerProperties
TIBInstall
TIBUnInstall
IBConfigService
Use an TIBConfigService object to configure database parameters, including page buffers, async mode, reserve space, and
sweep interval.
IBBackupService
Use an TIBBackupService object to back up your database. With IBBackupService, you can set such parameters as the blocking
factor, backup file name, and database backup options.
IBRestoreService
Use an TIBRestoreService object to restore your database. With IBRestoreService, you can set such options as page buffers,
page size, and database restore options.
IBValidationService
Use an TIBValidationService object to validate your database and reconcile your database transactions. With the
IBValidationService, you can set the default transaction action, return limbo transaction information, and set other database
validation options.
IBStatisticalService
Use an TIBStatisticalService object to view database statistics, such as data pages, database log, header pages, index pages,
and system relations.
IBLogService
IBSecurityService
Use an TIBSecurityService object to manage user access to the InterBase server. With the IBSecurityService, you can create,
delete, and modify user accounts, display all users, and set up work groups using SQL roles.
21
dbExpress 4 Feature Overview RAD Studio 1.2 Developing Database Applications for
IBLicensingService
IBServerProperties
Use an TIBServerProperties component to return database server information, including configuration parameters, and version
and license information.
IBInstall
1
Use an TIBInstall component to set up an InterBase installation component, including the installation source and destination
directories, and the components to be installed.
IBUnInstall
The DbxClient driver remotes the dbExpress 4 framework interface over a network based transport.
• dbExpress Framework
• dbExpress Metadata Improvements
• DBXClient Driver
• DBXDynalink Driver
• DBTest
dbExpress Framework
VCL
The dbExpress VCL component's implementation has changed with minimal change to the API. Most applications are not
affected by changes to the dbExpress VCL. However, there are some new methods, properties, events, constants, and enums.
The provider is not bound to a driver, but to a database back end. There is a new property called
22
1.2 Developing Database Applications for RAD Studio dbExpress 4 Feature Overview
Reading metadata
The unit DBXMetaDataNames has been provided to read metadata. The dbExpress class TDBXMetaDataCommands provides a
set of constants to read various types of metadata. Set the TDBXCommand.CommandType property to
TDBXCommandTypes.DBXMetadata and set TDBXCommand.Text to one of the constants in TDBXMetaDataCommands to
acquire the designated metadata. TDBXCommand.ExecuteQuery returns a TDBXReader to access the metadata. The new
classes in DBXMetaDataNames describe and provide access to this metadata's columns.
Writing metadata
Support for creating SQL dialect sensitive CREATE, ALTER, and DROP statements is provided in Data Explorer. dbExpress
also exposes a DbxMetaDataProvider class that surfaces this capability for applications. This slightly increases the size of
application, since the metadata writers must be included. The ability to generically create tables is useful for many applications.
The interface allows you to describe what a table and its columns look like and pass this description to the
TdbxMetaDataProvider.CreateTable method. Here is a simple example that shows how to create a table with an int32 column
named "C1", a decimal with a precision of 10 and scale of 2 named "C2", and a character based column with a precision of 32
named "C3".
var MetaDataTable: TDBXMetaDataTable; DataGenerator: TDbxDataGenerator; Command:
TDBXCommand; Row: Integer; begin MetaDataTable := TDBXMetaDataTable.Create;
MetaDataTable.TableName := 'QCXXX_TABLE';
MetaDataTable.AddColumn(TDBXInt32Column.Create('C1'));
MetaDataTable.AddColumn(TDBXDecimalColumn.Create('C2', 10, 2));
MetaDataTable.AddColumn(TDBXUnicodeCharColumn.Create('C3', 32));
MetaDataProvider.CreateTable(MetaDataTable); end
Deployment
For information about deploying database applications, see dapdeployingdatabaseapplications.xml ( see page 1948).
Compatibility
The VCL components in the SqlExpr unit still work with drivers that provide the more limited dbExpress 3 metadata. However,
Data Explorer only works with dbExpress 4 metadata.
Note that Delphi includes metadata for 9 different database backends. Thus any dbExpress driver implementation for the 9
backends supported can reuse the metadata provider with their driver implementation.
DBXClient Driver
DBXClient is a thin dbExpress 4 driver that remotes the dbExpress 4 framework interface over a pluggable network based
transport. In this release, a TCP/IP transport is supported. The driver uses a JSON/RPC (Java Script Object Notation) based
streaming protocol.
The DBXClient is implemented in 100% Object Pascal. Its source code is included in the product.
23
Blackfish SQL Overview RAD Studio 1.2 Developing Database Applications for
Connectivity
DBXClient can connect to Blackfish SQL and DataSnap. Blackfish SQL is a Delphi version of JBuilder's JDataStore. DataSnap
provides a middle-tier application server that contains and manages remote data modules. DataSnap has been enhanced to
provide a very general connection mechanism between components in different tiers.
To use the DBXClient driver with Blackfish SQL or DataSnap, add the DBXClient unit to the uses clause.
1 Deployment
DBXClient needs no database client library installed when you deploy your application. DBXClient is 100% Delphi and can be
directly linked into your application as a single .exe file.
For further information about deploying database applications, see dapdeployingdatabaseapplications.xml ( see page 1948).
DBTest
This is a collection of classes that extend the capabilities of Dunit to facilitate database testing. The qcreport and cts sample
Dunit tests provide good examples of how to make use of DBTest. TestCaseExtension contains non-database related
extensions to Dunit and the DBXTest unit contains database related extensions.
Test selection
-s:<TestName> command line can be used to execute just a single method in a Dunit test case. This is useful for debugging a
single bug. See the TestCaseExtension unit.
Convenience methods
There are several methods for creating default connection and metadata provider. See the DBXTest unit.
Data generator
There is a simple, extensible data generator. See the DBXDataGenerator unit.
See Also
dbExpress Framework ( see page 26)
TDBXMetaDataCommands
24
1.2 Developing Database Applications for RAD Studio Blackfish SQL Overview
Because the Blackfish SQL for Windows implementation is more recent, some Blackfish SQL for Java features are not yet
supported. The following features are not supported:
• DBXClient: This is a win32 dbExpress 4 database driver that enables win32 Delphi and C++ applications to connect to a
remote Blackfish SQL for Windows or Blackfish SQL for Java server.
• Local ADO.NET 2.0 Provider: This is a 100% managed code driver that enables .NET applications to connect to a local
Blackfish SQL for Windows server. The local ADO.NET driver executes in the same process as the BlackFishSQL database
kernel, for greater performance.
• Remote ADO.NET 2.0 Provider: This is a 100% managed code driver that enables .NET applications to acquire a remote
connection to either a Blackfish SQL for Windows or Blackfish SQL for Java server.
• Local JDBC driver: This is a 100% managed code driver that enables Java applications to connect to a local Blackfish SQL
25
dbExpress Framework RAD Studio 1.2 Developing Database Applications for
for Java server. The local JDBC driver executes in the same process as the BlackFishSQL database kernel, for greater
performance.
• Remote JDBC driver: This is a 100% managed code driver that enables Java applications to acquire a remote connection to
either a Blackfish SQL for Windows or Blackfish SQL for Java server.
See Also
Blackfish SQL Developer's Guide: Preface
Although many applications interface with dbExpress drivers via the dbExpress VCL components, the DBX framework offers a
convenient, lighter weight option to communicate with a database driver. You can also create a database driver for dbExpress by
extending the frameworks's DBXCommon abstract base classes. The DBX framework provides most commonly needed
database driver functionality for a "set" oriented database application, yet provides a simple interface.
• The driver framework is written entirely in Delphi and allows drivers to be written in Delphi.
• It uses strongly typed data access instead of pointers. For instance, it uses String types rather than pointers to strings.
• The driver framework is single sourced. You can compile the source with the native DCC32 compiler.
• The framework has only Abstract base classes that are used for drivers, connections, commands, readers, and so on.
• The framework uses exception based error handling rather than returning error codes.
Capabilities
There are two categories of drivers that extend the classes in DBXCommon: DBXDynaLink and DBXDirect. These drivers differ
from each other in the way they are loaded and the capabilities they provide to an application. These are described in greater
detail later.
You can also extend the DBX framework to write delegation drivers, which provide an extra layer between the application and
the actual driver. Delegate drivers are useful for connection pooling, driver profiling, tracing, and auditing. Another possible
application of driver delegation is to create a thread safe driver delegate. Such a delegate could provide thread synchronized
access to all public methods.
Absolute thread safety is left to applications using dbExpress. However, some thread safety issues are best handled by the
dbExpress framework. dbExpress thread safe operations include loading and unloading drivers, and connection creation. As
mentioned earlier, a delegate driver can be created to make the entire public interface of dbExpress thread safe if needed.
A dbExpress 4 driver can statically or dynamically link drivers built as Delphi packages. The easiest way to link a driver package
is to just include it in the "uses" clause. The driver loader also loads packages specified in a config or ini file using the
LoadPackage method. This allows dynamic loading of drivers that are never specified in a uses clause of any of the application's
units. Note that the LoadPackage approach can only be employed for applications built to use packages.
dbExpress 4 driver writers should examine the initialization sections of the DBXDynalink and DBXTrace units in the source code
provided with dbExpress. These sections register themselves with a singleton unit called the ClassRegistry. The ClassRegistry is
used by the dbExpress 4 driver loader to instantiate driver loader classes by name (a String). The ClassRegistry is a simple,
lightweight mechanism for registering and instantiating a class by name.
26
1.2 Developing Database Applications for RAD Studio dbExpress Framework Compatibility
DBXDynalink Drivers
DBXDynalink is used for existing dbExpress 3 drivers as well as new drivers. It is compiled as a native Delphi package.
DBXDynalink loads native dbExpress drivers that implement a more primitive "native" interface called DBXExports. The
DBXExports interface is a small collection of "flat" export methods. DBXExports's source is included with dbExpress.
DBXExports provides a more strongly typed API than the dbExpress 3's COM based interface. This allows methods to be added
in future product generations without breaking compatibility with older implementations of the DBXExports interface.
DBXAdapter is a dbExpress 4 compliant driver that adapts the DBXExports interface to the older dbExpress 3 COM interface. 1
Newer native drivers can be written by implementing DBXExports directly.
Because the DBXExports interface is designed to be implemented using any native language (Delphi or C++), it uses more
primitive, non-exception based error handling. DBXDynalink maps error codes to a DBXCommon exception.
The DBXDynalink unit contains a dbExpress 4 driver. This driver delegates to non-Delphi drivers that implement the
DBXDynalinkExport flat export interface. DBXTrace is a delegate driver used for tracing. The dbExpress VCL uses
DBXCommon, DBXDynalink and DbxTrace as "default" drivers. However, this can be changed for statically linked applications
without modifying dbExpress VCL source code (SQLExpr.pas). SQLExpr.pas uses the unit DBXDefaultDrivers. The
DBXDefaultDrivers unit only contains a uses clause. The DBXDefaultDrivers uses clause contains DBXCommon, DBXDynalink,
and DBXTrace. DBXCommon must always be used. However, a statically linked application could remove DBXTrace and
replace DBXDynalink with a different driver.
DBXDirect Drivers
A DBXDirect driver is any driver that is implemented by extending the DBXCommon abstract base classes. These classes are
written in Delphi for native implementations.
Strictly speaking, all DBX framework drivers are a form of DBXDirect driver. However DBXDynalink and DBXRemote provide a
more "indirect" linkage to driver implementations.
See Also
dbExpress Framework Compatibility ( see page 27)
General
dbExpress 2.5 drivers cannot be used with the DBX framework.
The dbExpress framework does not provide 100% compatibility with dbExpress 3.
dbExpress 3 drivers can be used with the DBX framework. The DBX framework driver loader automatically detects dbExpress 3
drivers and uses the DBXAdapter driver (dbxadapter30.dll) to make a dbExpress 3 driver look like a dbExpress 4 driver.
• Static driver linkage. You cannot statically link dbExpress drivers into an executable.
• SqlExpr.TSQLConnection provided protected access to the Connection member that was of type TISQLConnection only in
the native version of SqlExpr.pas. This was omitted from the managed version due to the complexity of how PInvoke was
used in the managed version of the dbExpress VCL. SqlExpr.TSQLConnection now provides protected access to a
TDBXConnection instead. This protected connection is accessible to both native and managed applications.
27
dbExpress Framework Compatibility RAD Studio 1.2 Developing Database Applications for
• The event for trace monitoring is slightly different because it is based on the DBX driver framework.
• The DBXadapter driver can adapt dbExpress 3 drivers to dbExpress 4, but not dbExpress 2.5 drivers.
VCL issues
Most applications using dbExpress VCL components should work without modification. However, there are some localized
changes to VCL components due to VCL now interfacing to the more object oriented DBX driver framework instead of the C-like
COM-based dbExpress 3 driver interface.
1 In addition, the API has changed slightly for two of the VCL components: TSQLConnection and TSQLDataSet. Some data
structures have also changed. A summary of the API changes follows.
Note: Because of API changes, you must recompile SqlExpr.pas, which is provided with the product. The DBXpress unit has
been deprecated.
• TSQLConnection. The Commit method has been deprecated in favor of the new CommitFreeAndNil method. The Rollback
method has been deprecated in favor of the new RollbackFreeAndNil and RollbackIncompleteFreeAndNil methods. The
SetTraceCallbackEvent method has been replaced by SetTraceEvent. The StartTransaction method has been deprecated in
favor of the new BeginTransaction method. The MetaData property contains an instance of the new class
TDBXDatabaseMetaData instead of TISQLMetaData. The SQLConnection property has been replaced by DBXConnection,
which contains an instance of the new class TDBXConnection. The TraceCallbackEventproperty now contains a
TDBXTraceEvent.
• TSQLDataSet. A new property DbxCommandType has been added, which contains one of the constant strings in the
TDBXCommandTypes class.
• Data structures. TTransactionItem has been deprecated, replaced by the new TDBXTransaction class. TSQLDriverOption,
TSQLConnectionOption, TSQLCommandOption, TSQLCursorOption, TSQLMetaDataOption, and TSQLObjectType are
obsolete. TSTMTParamType has been replaced by the TDBXParameterDirections class. TSQLTraceFlag has been replaced
by TDBXTraceFlags. SQLTRACEDesc is replaced by TDBXTraceInfo.
See Also
dbExpress Framework ( see page 26)
28
1.3 Developing Interoperable Applications RAD Studio Developing COM Applications
Topics
Name Description
Developing COM Applications ( see page 29) Delphi provides wizards and classes to make it easy to implement applications
based on the Component Object Model (COM) from Microsoft. With these
wizards, you can create COM-based classes and components to use within
applications or you can create fully functional COM clients and servers that
implement COM objects, Automation servers (including Active Server Objects),
ActiveX controls, or ActiveForms.
This topic covers:
Applications can access the interfaces of COM components that exist on the same computer as the application or that exist on
another computer on the network using a mechanism called Distributed COM (DCOM).
COM is both a specification and an implementation. The COM specification defines how objects are created and how they
communicate with each other. According to this specification, COM objects can be written in different languages, run in different
29
Developing COM Applications RAD Studio 1.3 Developing Interoperable Applications
process spaces and on different platforms. As long as the objects conform to the written specification, they can communicate.
This allows you to integrate legacy code as a component with new components implemented in object-oriented languages.
The COM implementation is built into the Win32 subsystem, which provides a number of core services that support the
specification. The COM library contains a set of standard interfaces that define the core functionality of a COM object, and a
small set of API functions for creating and managing COM objects.
When you use Delphi wizards and VCL objects in your application, you are using Delphi’s implementation of the COM
specification. In addition, Delphi provides some wrappers for COM services for those features that it does not implement directly
1 (such as Active Documents). You can find these wrappers defined in the ComObj unit and the API definitions in the AxCtrls
unit.
Note: Delphi’s interfaces and language follow the COM specification. Delphi implements objects conforming to the COM spec
using a set of classes called the Delphi ActiveX framework (DAX). These classes are found in the AxCtrls, OleCtrls, and
OleServer units. In addition, the Delphi interface to the COM API is in ActiveX.pas and ComSvcs.pas.
COM Interfaces
COM clients communicate with objects through COM interfaces. Interfaces are groups of logically or semantically related
routines which provide communication between a provider of a service (server object) and its clients.
For example, every COM object must implement the basic interface, IUnknown. Through a routine called QueryInterface in
IUnknown, clients can request other interfaces implemented by the server.
Objects can have multiple interfaces, where each interface implements a feature. An interface provides a way to tell the client
what service it provides, without providing implementation details of how or where the object provides this service.
• Once published, interfaces do not change. You can rely on an interface to provide a specific set of functions. Additional
functionality is provided by additional interfaces.
• By convention, COM interface identifiers begin with a capital I and a symbolic name that defines the interface, such as
IMalloc or IPersist.
• Interfaces are guaranteed to have a unique identification, called a Globally Unique Identifier (GUID), which is a 128-bit
randomly generated number. Interface GUIDs are called Interface Identifiers (IIDs). This eliminates naming conflicts between
different versions of a product or different products.
• Interfaces are language independent. You can use any language to implement a COM interface as long as the language
supports a structure of pointers, and can call a function through a pointer, either explicitly or implicitly.
• Interfaces are not objects themselves, they provide a way to access an object. Therefore, clients do not access data directly,
they access data through an interface pointer. Windows 2000 adds another layer of indirection, known as an interceptor,
through which it provides COM+ features such as just-in-time activation and object pooling.
• Interfaces are always inherited from the base interface, IUnknown.
• Interfaces can be redirected by COM through proxies to enable interface method calls to call between threads, processes,
and networked machines, all without the client or server objects ever being aware of the redirection.
30
1.3 Developing Interoperable Applications RAD Studio Developing COM Applications
interface, the client is assured that it can call any method of the interface.
Objects track their own lifetime through the IUnknown methods, AddRef and Release, which are simple reference counting
methods. As long as the reference count of an object is nonzero, the object remains in memory. Once the reference count
reaches zero, the interface implementation can safely dispose of the underlying object.
The vtable is shared among all instances of an object class, so for each object instance, the object code allocates a second
structure that contains its private data. The client’s interface pointer, then, is a pointer to the pointer to the vtable.
In Windows 2000 and subsequent versions of Windows, when an object is running under COM+, another level of indirection is
provided between the interface pointer and the vtable pointer. The interface pointer available to the client points at an interceptor,
which in turn points at the vtable. This allows COM+ to provide such services as just-in-time activation, where the server can be
deactivated and reactivated dynamically in a way that is opaque to the client. To achieve this, COM+ guarantees that the
interceptor behaves as if it were an ordinary vtable pointer.
COM Servers
A COM server is an application or a library that provides services to a client application or library. A COM server consists of one
or more COM objects, where a COM object is a set of properties and methods.
Clients do not know how a COM object performs its service; the object’s implementation remains hidden. An object makes its
services available through its interfaces as described previously.
In addition, clients do not need to know where a COM object resides. COM provides transparent access regardless of the
object’s location.
When a client requests a service from a COM object, the client passes a class identifier (CLSID) to COM. A CLSID is simply a
GUID that identifies a COM object. COM uses this CLSID, which is registered in the system registry, to locate the appropriate
server implementation. Once the server is located, COM brings the code into memory, and has the server create an object
instance for the client. This process is handled indirectly, through a special object called a class factory (based on interfaces)
that creates instances of objects on demand.
• Register entries in the system registry that associate the server module with the class identifier (CLSID).
• Implement a class factory object, which creates another object of a particular CLSID.
• Expose the class factory to COM.
• Provide an unloading mechanism through which a server that is not servicing clients can be removed from memory.
COM Clients
COM clients are applications that make use of a COM object implemented by another application or library. The most common
types are Automation controllers, which control an Automation server and ActiveX containers, which host an ActiveX control.
There are two types of COM clients, controllers and containers. Controllers launch the server and interact with it through its
interface. They request services from the COM object or drive it as a separate process. Containers host visual controls or objects
that appear in the container’s user interface. They use predefined interfaces to negotiate display issues with server objects. It is
impossible to have a container relationship over DCOM; for example, visual controls that appear in the container's user interface
must be located locally. This is because the controls are expected to paint themselves, which requires that they have access to
local GDI resources.
The task of writing these two types of COM client is remarkably similar: The client application obtains an interface for the server
31
Developing COM Applications RAD Studio 1.3 Developing Interoperable Applications
object and uses its properties and methods. Delphi makes it easier for you to develop COM clients by letting you import a type
library or ActiveX control into a component wrapper so that server objects look like other VCL components. Delphi lets you wrap
the server CoClass in a component on the client, which you can even install on the Component palette. Samples of such
component wrappers appear on two pages of the Component palette, sample ActiveX wrappers appear on the ActiveX page,
and sample Automation objects appear on the Servers page.
Even if you do not choose to wrap a server object in a component wrapper and install it on the Component palette, you must
make its interface definition available to your application. To do this, you can import the server’s type information.
1 Clients can always query the interfaces of a COM object to determine what it is capable of providing. All COM objects allow
clients to request known interfaces. In addition, if the server supports the IDispatch interface, clients can query the server for
information about what methods the interface supports. Server objects have no expectations about the client using its objects.
Similarly, clients don’t need to know how an object provides the services, they simply rely on server objects to provide the
services they describe in their interfaces.
COM Extensions
As COM has evolved, it has been extended beyond the basic COM services. COM serves as the basis for other technologies
such as Automation, ActiveX controls, Active Documents, and Active Directories. In addition, when working in a large, distributed
environment, you can create transactional COM objects. Prior to Windows 2000, these objects were not an architectural part of
COM, but ran in the Microsoft Transaction Server (MTS) environment. As of Windows 2000, this support is integrated into
COM+. Delphi provides wizards to easily implement applications that use the above technologies in the Delphi environment.
Automation Servers
Automation refers to the ability of an application to control the objects in another application programmatically, such as a macro
that can manipulate more than one application at the same time. The server object being manipulated is called the Automation
object, and the client of the Automation object is referred to as an Automation controller. Automation can be used on in-process,
local, and remote servers.
• The Automation object defines a set of properties and commands, and describes their capabilities through type descriptions.
In order to do this, it must have a way to provide information about its interfaces, the interface methods, and the arguments to
those methods. Typically, this information is available in a type library. The Automation server can also generate type
information dynamically when queried via its IDispatch interface.
• Automation objects make their methods accessible so that other applications can use them. For this, they implement the
IDispatch interface. Through this interface an object can expose all of its methods and properties. Through the primary
method of this interface, the object’s methods can be invoked, once having been identified through type information.
Developers often use Automation to create and use non-visual OLE objects that run in any process space, because the
Automation IDispatch interface automates the marshaling process. Automation does, however, restrict the types that you
can use.
Active X Controls
Delphi wizards allow you to easily create ActiveX controls. ActiveX is a technology that allows COM components, especially
controls, to be more compact and efficient. This is especially necessary for controls that are intended for Intranet applications,
which need to be downloaded by a client before they are used.
ActiveX controls are visual controls that run only as in-process servers, and can be plugged into an ActiveX control container
application. They are not complete applications in themselves, but can be thought of as already written OLE controls that are
reusable in various applications. ActiveX controls have a visible user interface, and rely on predefined interfaces to negotiate I/O
and display issues with their host containers.
ActiveX controls make use of Automation to expose their properties, methods, and events. Features of ActiveX controls include
the ability to fire events, bind to data sources, and support licensing.
One use of ActiveX controls is on a Web site as interactive objects in a Web page. As such, ActiveX is a standard that targets
32
1.3 Developing Interoperable Applications RAD Studio Developing COM Applications
interactive content for the World Wide Web, including the use of ActiveX Documents used for viewing non-HTML documents
through a Web browser. For more information about ActiveX technology, see the Microsoft ActiveX Web site.
Active Documents
Active Documents (previously referred to as OLE documents) are a set of COM services that support linking and embedding,
drag-and-drop, and visual editing. Active Documents can seamlessly incorporate data or objects of different formats, such as
sound clips, spreadsheets, text, and bitmaps.
Unlike ActiveX controls, Active Documents are not limited to in-process servers; they can be used in cross-process applications. 1
Unlike Automation objects, which are almost never visual, Active Document objects can be visually active in another application.
Thus, Active Document objects are associated with two types of data: presentation data, used for visually displaying the object
on a display or output device, and native data, used to edit an object.
Active Document objects can be document containers or document servers. While Delphi does not provide an automatic wizard
for creating Active Documents, you can use the VCL class, TOleContainer, to support linking and embedding of existing Active
Documents.
You can also use TOleContainer as a basis for an Active Document container. To create objects for Active Document servers,
use the COM object wizard and add the appropriate interfaces, depending on the services the object needs to support. For more
information about creating and using Active Document servers, see the Microsoft ActiveX Web site.
Note: While the specification for Active Documents has built-in support for marshaling in cross-process applications, Active
Documents do not run on remote servers because they use types that are specific to a system on a given machine such as
window handles, menu handles, and so on.
Transactional Objects
Delphi uses the term "transactional objects" to refer to objects that take advantage of the transaction services, security, and
resource management supplied by Microsoft Transaction Server (MTS) (for versions of Windows prior to Windows 2000) or
COM+ (for Windows 2000 and later). These objects are designed to work in a large, distributed environment.
The transaction services provide robustness so that activities are always either completed or rolled back. The server never
partially completes an activity. The security services allow you to expose different levels of support to different classes of clients.
The resource management allows an object to handle more clients by pooling resources or keeping objects active only when
they are in use. To enable the system to provide these services, the object must implement the IObjectControl interface. To
access the services, transactional objects use an interface called IObjectContext, which is created for them by MTS or
COM+.
Under MTS, the server object must be built into a DLL library, which is then installed in the MTS runtime environment. That is,
the server object is an in-process server that runs in the MTS runtime process space. Under COM+, this restriction does not
apply because all COM calls are routed through an interceptor. To clients, the difference between MTS and COM+ is transparent.
MTS or COM+ servers group transactional objects that run in the same process space. Under MTS, this group is called an MTS
package, while under COM+ it is called a COM+ application. A single machine can be running several different MTS packages
(or COM+ applications), where each one is running in a separate process space.
To clients, the transactional object may appear like any other COM server object. The client does not need know about
transactions, security, or just-in-time activation unless it is initiating a transaction itself.
Both MTS and COM+ provide a separate tool for administering transactional objects. This tool lets you configure objects into
packages or COM+ applications, view the packages or COM+ applications installed on a computer, view or change the attributes
of the included objects, monitor and manage transactions, make objects available to clients, and so on. Under MTS, this tool is
the MTS Explorer. Under COM+ it is the COM+ Component Manager.
33
Developing COM Applications RAD Studio 1.3 Developing Interoperable Applications
Type Libraries
Type libraries provide a way to get more type information about an object than can be determined from an object’s interface. The
type information contained in type libraries provides needed information about objects and their interfaces, such as what
interfaces exist on what objects (given the CLSID), what member functions exist on each interface, and what arguments those
functions require.
You can obtain type information either by querying a running instance of an object or by loading and reading type libraries. With
1 this information, you can implement a client which uses a desired object, knowing specifically what member functions you need,
and what to pass those member functions.
Clients of Automation servers, ActiveX controls, and transactional objects expect type information to be available. All of Delphi’s
wizards generate a type library automatically, although the COM object wizard makes this optional. You can view or edit this type
information by using the Type Library Editor.
See Also
Using COM Wizards ( see page 79)
34
1.4 Developing Reports for Your Win32 RAD Studio Using Rave Reports in RAD Studio
Topics
Name Description
Using Rave Reports in RAD Studio ( see page 35) The RAD Studio environment supports the integration of report objects in your
applications. This integration allows you to create a report using the Rave
Reports Designer directly from within the RAD Studio IDE. Your application users
can create and display their own reports, or display existing reports.
See Also
Adding Rave Reports to RAD Studio ( see page 81)
35
VCL Overview RAD Studio 1.5 Developing Applications with VCL
VCL contains a wide variety of visual, non-visual, and utility classes for tasks such as building Windows applications, web
applications, database applications, and console applications.
Topics
Name Description
VCL Overview ( see page 36) This section introduces:
• VCL Architecture
• VCL Components
• Working With Components
Using TEncoding for Unicode Files ( see page 38)
Components Available Only on Specific OS ( see page 39) Some VCL components are specific to an operating system (such as Vista) and
thus will not work on other operating systems. For example, the design time
components TFileOpenDialog and TFileSaveDialog are specific to Vista. Some
components are designed to work with themes either enabled or disabled. (To
enable or disable themes, check or uncheck the Enable runtime themes box on
the Project Options Application dialog box.)
In the following table, note that Windows Server 2003 is treated as Windows XP,
and Windows Server 2008 is treated as Vista.
Components Available Only for Certain Operating Systems
• VCL Architecture
• VCL Components
• Working With Components
VCL Architecture
VCL is an acronym for the Visual Component Library, a set of visual components for rapid development of Windows applications
in the Delphi language. VCL contains a wide variety of visual, non-visual, and utility classes for tasks such as Windows
application building, web applications, database applications, and console applications. All classes descend from
System::TObject. System::TObject introduces methods that implement fundamental behavior like construction, destruction, and
message handling.
VCL Components
Components are a subset of the component library that descend from the class TComponent. You can place components on a
form or data module and manipulate them at designtime. Using the Object Inspector, you can assign property values without
writing code. Most components are either visual or nonvisual, depending on whether they are visible at runtime. Some
components appear on the Component Palette.
36
1.5 Developing Applications with VCL RAD Studio VCL Overview
Visual Components
Visual components, such as TForm and TSpeedButton, are called controls and descend from TControl. Controls are used in GUI
applications, and appear to the user at runtime. TControl provides properties that specify the visual attributes of controls, such as
their height and width.
NonVisual Components
Nonvisual components are used for a variety of tasks. For example, if you are writing an application that connects to a database, 1
you can place a TDataSource component on a form to connect a control and a dataset used by the control. This connection is
not visible to the user, so TDataSource is nonvisual. At designtime, nonvisual components are represented by an icon. This
allows you to manipulate their properties and events just as you would a visual control.
Using Events
Almost all the code you write is executed, directly or indirectly, in response to events. An event is a special kind of property that
represents a runtime occurrence, often a user action. The code that responds directly to an event, called an event handler, is a
Delphi procedure.
The Events page of the Object Inspector displays all events defined for a given component. Double-clicking an event in the
Object Inspector generates a skeleton event handling procedure, which you can fill in with code to respond to that event. Not all
components have events defined for them.
Some components have a default event, which is the event the component most commonly needs to handle. For example, the
default event for a button is OnClick. Double-clicking on a component with a default event in the Form Designer will generate a
skeleton event handling procedure for the default event.
37
Using TEncoding for Unicode Files RAD Studio 1.5 Developing Applications with VCL
You can reuse code by writing event handlers that respond to more than one event. For example, many applications provide
speed buttons that are equivalent to drop down menu commands. When a button performs the same action as a menu
command, you can write a single event handler and then assign it to the OnClick event for both the button and the menu item by
setting the event handler in the Object Inspector for both the events you want to respond to.
This is the simplest way to reuse event handlers. However, action lists, and in the VCL, action bands, provide powerful tools for
centrally organizing the code that responds to user commands. Action lists can be used in cross-platform applications; action
bands cannot.
1
Setting Component Properties
To set published properties at design time, you can use the Object Inspector and, in some cases, property editors. To set
properties at runtime, assign their values in your application source code.
When you select a component on a form at design time, the Object Inspector displays its published properties and, when
appropriate, allows you to edit them.
When more than one component is selected, the Object Inspector displays all properties—except Name—that are shared by the
selected components. If the value for a shared property differs among the selected components, the Object Inspector displays
either the default value or the value from the first component selected. When you change a shared property, the change applies
to all selected components.
Changing code-related properties, such as the name of an event handler, in the Object Inspector 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, are immediately reflected in the Object Inspector.
See Also
Building a VCL Forms Application ( see page 99)
If a BOM is found, it will read the data encoded as the BOM indicates. If no BOM is found, it will read it as ANSI and up-convert
based on the current active codepage.
All your files written with pre-RAD Studio 2009 versions of Delphi will still be read in, with the caveat that as long as you read
with the active codepage the same as with what was written. Likewise, any file written with RAD Studio 2009 with an ASCII
encoding should be readable with the pre-RAD Studio 2009 version.
Any file written with RAD Studio 2009 with any other encoding will generate a BOM and will not be readable with a the pre-RAD
Studio 2009 version. At this point, only the most common BOM formats are detected (UTF16 Little-Endian, UTF16 Big-Endian
and UTF8).
38
1.5 Developing Applications with VCL RAD Studio Components Available Only on Specific OS
If you wanted to force the file to read and write using a specific codepage, you can create an instance of TMBCSEncoding and
pass in the code page you want to use into the constructor. Then you use that instance to read and write the file, since the
specific codepage may not match the user’s active codepage.
The same thing holds for these classes in that the data will be read and written as ANSI data. Since INI files have always been
traditionally ANSI (ASCII) encoded, it may not make sense to convert these. It will depend on the needs of your application. If
you do wish to change to use a Unicode format, we will offer ways to use the TEncoding classes to accomplish that as well.
In all the above cases, the internal storage will be Unicode and any data manipulation you do with string will continue to function
as expected. Conversions will automatically happen when reading and writing the data.
The following list shows the overload methods that accept a TEncoding parameter:
• WriteNode (Outline.TOutlineNode)
• LoadFromFile (Outline.TOutlineNode)
• LoadFromStream (Outline.TOutlineNode)
• SaveToFile (Outline.TOutlineNode)
• SaveToStream (Outline.TOutlineNode)
• LoadFromFile (Classes.TStrings)
• LoadFromStream (Classes.TStrings)
• SaveToFile (Classes.TStrings)
• SaveToStream (Classes.TStrings)
• Create (Classes.TStringStream)
• Create (Classes.TStreamReader)
• Create (Classes.TStreamWriter)
In the following table, note that Windows Server 2003 is treated as Windows XP, and Windows Server 2008 is treated as Vista.
39
Components Available Only on Specific OS RAD Studio 1.5 Developing Applications with VCL
See Also
Building a VCL Forms Application ( see page 99)
40
1.6 Developing Web Applications with RAD Studio Win32 Web Applications Overview
Topics
Name Description
Win32 Web Applications Overview ( see page 41) This section covers:
• ISAPI
• CGI
• Web Application Debugger
Apache web applications are not supported for this release.
ISAPI
Selecting this type of application sets up your project as a DLL, with the exported methods expected by the Web server. It adds
the library header to the project file, and the required entries to the uses list and exports clause of the project file.
41
Win32 Web Applications Overview RAD Studio 1.6 Developing Web Applications with
CGI
Selecting this type of application sets up your project as a console application, and adds the required entries to the uses clause
of the project file.
Frequently, the content of Web pages is drawn from databases. You can use Internet components to automatically manage
connections to databases, allowing a single DLL to handle multiple simultaneous, thread-safe, database connections.
WebSnap augments Web Broker with additional components, wizards, and views, making it easier to build Web server
applications that deliver complex, data-driven Web pages. WebSnap's support for multiple modules and for server-side scripting
makes development and maintenance easier for teams of developers and Web designers. WebSnap allows HTML design
experts on your team to make a more effective contribution to Web server development and maintenance.
The final product of the WebSnap development process includes a series of scriptable HTML page templates. These pages can
be changed using HTML editors that support embedded script tags, like Microsoft FrontPage, or even a text editor. Changes can
be made to the templates as needed, even after the application is deployed. There is no need to modify the project source code
at all, which saves valuable development time. WebSnap’s multiple module support can be used to divide your application into
smaller pieces during the coding phases of your project, so that developers can work more independently.
To use the Web Application Debugger, you must first create your Web application as a Web Application Debugger executable.
Whether you are using Web Broker or WebSnap, the wizard that creates your Web server application includes this as an option
when you first begin the application. This creates a Web server application that is also a COM server. The first time you run your
application, it registers your COM server so that the Web Application Debugger can access it. Before you can run the Web
Application Debugger, you will need to run bin\serverinfo.exe once to register the ServerInfo application.
42
1.6 Developing Web Applications with RAD Studio Win32 Web Applications Overview
Converting your application to another type of Web server application after debugging
When you have finished debugging your Web server application with the Web Application Debugger, you will need to convert it
to another type that can be installed on a commercial Web server.
See Also
Building a WebSnap Application ( see page 148)
Converting Your Application to Another Type of Web Server Application ( see page 2245)
43
Web Services Overview RAD Studio 1.7 Developing Web Services with Win32
Topics
Name Description
Web Services Overview ( see page 44) Web Service applications are server implementations that do not require clients
to use a specific platform or programming language. These applications define
interfaces in a language-neutral document, and they allow multiple
communication mechanisms.
Web Services are designed to work using Simple Object Access Protocol
(SOAP). SOAP is a standard lightweight protocol for exchanging information in a
decentralized, distributed environment. SOAP uses XML to encode remote
procedure calls and typically uses HTTP as a communications protocol.
Web Service applications use a Web Service Definition Language (WSDL)
document to publish information on interfaces that are available and how to call
them. On... more ( see page 44)
Web Services are designed to work using Simple Object Access Protocol (SOAP). SOAP is a standard lightweight protocol for
exchanging information in a decentralized, distributed environment. SOAP uses XML to encode remote procedure calls and
typically uses HTTP as a communications protocol.
Web Service applications use a Web Service Definition Language (WSDL) document to publish information on interfaces that
are available and how to call them. On the server side, your application can publish a WSDL document that describes your Web
Service. On the client side, a wizard or command-line utility can import a published WSDL document, providing you with the
interface definitions and connection information you need. If you already have a WSDL document that describes the Web service
you want to implement, you can generate the server-side code when you import the WSDL document.
See Also
Using Web Services ( see page 2291)
44
1.8 Developing Windows Applications RAD Studio Windows Overview
• GUI Applications
• Console Applications
• Service Applications
• Packages and DLLs
• GUI Applications
• Console Applications
• Service Applications
• Packages and DLLs
GUI Applications
A graphical user interface (GUI) application is designed using graphical components such as windows, menus, dialog boxes, and
other features that make the application easy to use. When you compile a GUI application, an executable file with start-up code
is created from your source files. The executable usually provides the basic functionality of your program. Simple programs often
consist of only an executable file. You can extend the application by calling DLLs, packages, and other support files from the
executable.
45
Windows Overview RAD Studio 1.8 Developing Windows Applications
MDI applications require more planning and are more complex to design than SDI applications. MDI applications spawn child
windows that reside within the client window; the main form contains child forms. For instance, you need to set the FormStyle
property of the TForm object to specify whether a form is a child (fsMDIChild) or main form (fsMDIForm). It is a best practice to
define a base class for your child forms and derive each child form from this class. Otherwise, you will have to reset the form
properties of the child. MDI applications often include a Window pop-up on the main menu that has items such as Cascade and
Tile for viewing multiple windows in various styles. When a child window is minimized, its icon is located in the MDI parent form.
Console Applications
1 Console applications are 32-bit programs that run in a console window without a graphical interface. These applications typically
do not require much user input and perform a limited set of functions. Any application that contains {$APPTYPE CONSOLE} in
the code opens a console window of its own.
Service Applications
Service applications take requests from client applications, process those requests, and return the information to the client
applications. Service applications typically run in the background without much user input. A Web, FTP, or an email server is an
example of a service application.
Packages are special DLLs used by Delphi applications, the IDE, or both. The two types of packages are runtime and
designtime. Runtime packages provide functionality to a program while that program is running. Designtime packages extend the
functionality of the IDE.
For most applications, packages provide greater flexibility and are easier to create than DLLs. However,here are a few situations
where DLLs would work better than packages:
46
2 RAD Studio
2 Procedures
This section provides how-to information for various areas of RAD Studio development.
Topics
Name Description
CodeGuard Procedures ( see page 48) Use these procedures to debug your C++ applications with CodeGuard.
Database Procedures ( see page 50) This topic describes how to use the database components in the Tool Palette,
like dbGo components, dbExpress components, BDE components, and
DataSnap components.
Interoperable Applications Procedures ( see page 79) Delphi provides wizards and classes to make it easy to implement applications
2
based on the Component Object Model (COM) from Microsoft. The simplest
COM objects are servers that expose properties and methods (and possibly
events) through a default interface that clients can call. The COM Object Wizard
builds a lightweight COM object whose default interface descends from
IUnknown or that implements an interface already registered on your system.
This wizard provides the most flexibility in the types of COM objects you can
create.
Reporting Procedures ( see page 81) This topic provides how-to information on using reporting solutions.
VCL Procedures ( see page 82) This section provides how-to information on developing VCL for Win32
applications.
WebSnap Procedures ( see page 147) This section provides how-to information on developing WebSnap applications.
Please note that WebSnap is being deprecated in RAD Studio. Although
WebSnap is still documented in the online help, the WebSnap product is no
longer fully supported. As an alternative, you should begin using IntraWeb (VCL
for the Web). IntraWeb ( see page 2254) is documented in this online help. For
more documentation on VCL for the Web, go to
http://www.atozed.com/intraweb/docs/.
Web Services Procedure ( see page 153) This section provides how-to information on developing and using web services.
47
Using CodeGuard RAD Studio 2.1 CodeGuard Procedures
Topics
Name Description
Using CodeGuard ( see page 48) This procedure describes how to use CodeGuard when debugging a C++
application.
2 CodeGuard also generates an error log named <project_name>.cgl that lists any errors it finds. The error log is located in
the same directory as your executable.
Note: If you suspect that your program accesses a freed memory block but CodeGuard does not report an error, increase the
value of Maximum memory block size
or Delay queue length on the Resource Options page of the Configure CodeGuard dialog box.
48
2.1 CodeGuard Procedures RAD Studio Using CodeGuard
49
RAD Studio 2.2 Database Procedures
Topics
Name Description
Accessing Schema Information ( see page 51) The schema information or metadata includes information about what tables and
stored procedures are available on the server and the information about these
tables and stored procedures (like the fields of a table, the indexes that are
defined, and the parameters a stored procedure uses).
Using Data Explorer to Obtain Connection Information ( see page 52) Before you have a connection, you can use Data Explorer to assemble
connection strings.
Configuring TSQL Connection ( see page 53) The first step when working with a unidirectional dataset is to connect it to a
database server. At designtime, once a dataset has an active connection to a
database server, the Object Inspector can provide drop-down lists of values for
other properties. For example, when representing a stored procedure, you must
have an active connection before the Object Inspector can list what stored
procedures are available on the server. The connection to a database server is
represented by a separate TSQLConnection component. You work with
TSQLConnection like any other database connection component.
Connecting to the Application Server using DataSnap Components ( see page A client application uses one or more connection components in the DataSnap
55) category of the Tool Palette to establish and maintain a connection to an
application server.
Debugging dbExpress Applications using TSQLMonitor ( see page 55) While you are debugging your database application, you can monitor the SQL
messages that are sent to and from the database server through your connection
component, including those that are generated automatically for you (for example
2 by a provider component or by the dbExpress driver).
Executing the Commands using TSQLDataSet ( see page 56) You can use a unidirectional dataset even if the query or stored procedure it
represents does not return any records. Such commands include statements that
use Data Definition Language (DDL) or Data Manipulation Language (DML)
statements other than SELECT statements. The language used in commands is
server-specific, but usually compliant with the SQL-92 standard for the SQL
language. The SQL command you execute must be acceptable to the server you
are using. Unidirectional datasets neither evaluate the SQL nor execute it, but
pass the command to the server for execution.
Fetching the Data using TSQLDataSet ( see page 57)
Specifying the Data to Display using TSQLDataSet ( see page 58)
Specifying the Provider using TLocalConnection or TConnectionBroker ( see Client datasets are specialized datasets that hold all the data in memory. They
page 59) use a provider to supply them with data and apply updates when they cache
updates from a database server or another dataset, represent the data in an XML
document, and store the data in the client portion of a multi-tiered application.
Using BDE ( see page 60)
Using DataSnap ( see page 60) A multi-tiered client/server application is partitioned into logical units, called tiers,
which run in conjunction on separate machines. Multi-tiered applications share
data and communicate with one another over a local-area network or even over
the Internet. They provide many benefits, such as centralized business logic and
thin client applications.
Multi-tiered applications use the components on the DataSnap category in the
Tool Palette. DataSnap provides multi-tier database capability to Delphi
applications by allowing client applications to connect to providers in an
application server.
Using TBatchMove (BDE) ( see page 61) TBatchMove copies a table structure or its data. It can be used to move entire
tables from one database format to another.
50
2.2 Database Procedures RAD Studio Accessing Schema Information
Connecting to Databases with TDatabase ( see page 62) TDatabase sets up a persistent connection to a database, especially a remote
database requiring a user login and password. TDatabase is especially important
because it permits control over database transaction processing with the BDE
when connected to a remote SQL database server. Use TDatabase when a
BDE-based database application requires:
51
Using Data Explorer to Obtain Connection RAD Studio 2.2 Database Procedures
and the information about these tables and stored procedures (like the fields of a table, the indexes that are defined, and the
parameters a stored procedure uses).
See Also
dbExpress Components ( see page 16)
52
2.2 Database Procedures RAD Studio Configuring TSQL Connection
of connection properties. The left column contains connection string keys; the right column contains their values.
53
Configuring TSQL Connection RAD Studio 2.2 Database Procedures
54
2.2 Database Procedures RAD Studio Debugging dbExpress Applications using
55
Executing the Commands using RAD Studio 2.2 Database Procedures
To execute commands
1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. From the dbExpress category of the Tool Palette, drag a TSQLDataSet component to the form.
4. Specify the command to execute.
5. Execute the command.
6. Create and modify server metadata.
56
2.2 Database Procedures RAD Studio Fetching the Data using TSQLDataSet
57
Specifying the Data to Display using RAD Studio 2.2 Database Procedures
See Also
dbExpress Components ( see page 16)
58
2.2 Database Procedures RAD Studio Specifying the Provider using
semicolon-delimited list of field names to specify the order of fields in the dataset.
59
Using DataSnap RAD Studio 2.2 Database Procedures
See Also
Using DataSnap ( see page 60)
Multi-tiered applications use the components on the DataSnap category in the Tool Palette. DataSnap provides multi-tier
database capability to Delphi applications by allowing client applications to connect to providers in an application server.
60
2.2 Database Procedures RAD Studio Using TBatchMove (BDE)
To use TBatchMove
1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. Create a batch move component.
4. Specify a batch move mode.
5. Map data types.
6. Execute a batch move.
7. Handle batch move errors.
See Also
Using TBatchMove ( see page 1683)
61
Connecting to Databases with TDatabase RAD Studio 2.2 Database Procedures
62
2.2 Database Procedures RAD Studio Using TQuery (Procedure)
clears any value already assigned to AliasName. To provide your own name for a database connection, set the
DatabaseName. To specify a BDE alias at designtime, assign a BDE driver.
To use TQuery
1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. Associate the dataset with database and session connections.
4. Create heterogeneous queries.
63
Using TQuery (Procedure) RAD Studio 2.2 Database Procedures
5. In the Object Inspector, set the DatabaseName to specify the directory where the database tables are located if you want to
use an implicit database component for a Paradox or dBASE database.
6. Use the default session to control all database connections in your application.
7. Set the SessionName property of the TSession component to associate your dataset with an explicitly created session
component .
Note: Whether you use the default session or explicitly specify a session using the SessionName property, you can access
the session associated with a dataset by reading the DBSession property. If you use a session component, the SessionName
property of a dataset must match the SessionName property for the database component with which the dataset is
associated.
64
2.2 Database Procedures RAD Studio Using TSQLQuery
2. Set the query’s UpdateObject property to the TUpdateSQL object you are using to have more control over applying updates.
3. Set the DeleteSQL, InsertSQL, and ModifySQL properties of the update object to the SQL statements that perform the
appropriate updates for your query’s data.
If you are using the BDE to cache updates, you must use an update object.
See Also
BDE Overview ( see page 15)
To use TSQLQuery 2
1. From the dbExpress category of the Tool Palette, drag a TSQLQuery component to the form.
2. In the Object Inspector, set its Name property to a unique value appropriate to your application.
3. Set the SQLConnection property.
4. Click the ellipsis button next to the SQL property of the TSQLQuery component. The String List editor opens.
5. In the String List editor, type the query statement you want to execute.
6. If the query data is to be used with visual data controls, add a data source component to the form.
7. Set the DataSet property of the data source component to the query-type dataset.
8. To activate the query component, set the Active property to True or call the Open method at runtime.
See Also
dbExpress Components ( see page 16)
65
Using TSQLTable RAD Studio 2.2 Database Procedures
To use TSQLStoredProc
1. From the dbExpress category of the Tool Palette, drag a TSQLStoredProc component to the form.
2. In the Object Inspector, set its Name property to a unique value appropriate to your application.
3. Set the SQLConnection property.
4. Set the StoredProcName property to specify the stored procedure to execute.
5. If the stored procedure returns a cursor to be used with visual data controls, add a data source component to the form.
6. Set the DataSet property of the data source component to the stored procedure-type dataset.
7. Provide input parameter values for the stored procedure, if necessary.
8. To execute the stored procedure that returns a cursor, use the Active property or call the Open method.
9. Process any results.
See Also
To use TSQLTable
1. Choose File New Other. The New Items dialog displays.
66
2.2 Database Procedures RAD Studio Managing Database Sessions Using
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. From the dbExpress category of the Tool Palette, drag a TSQLTable component to the form.
4. In the Object Inspector, set its Name property to a unique value appropriate to your application.
5. Set the SQLConnection property
6. Set the TableName property to the name of the table in the database.
7. Add a data source component to the form.
8. Set the DataSet property of the data source component to the the name of the dataset.
See Also
dbExpress Components ( see page 16)
67
Using TSimpleObjectBroker RAD Studio 2.2 Database Procedures
To use TSQLStoredProc
1. From the dbExpress category of the Tool Palette, drag a TSimpleDataSet component to the form.
2. Set its Name property to a unique value appropriate to your application.
3. From the dbExpress section of the Tool Palette, drag a TSQLConnection component on the form.
4. Select TSimpleDataSet component. Set the Connection property to TSQLConnection component.
5. To fetch data from the server, do any of the following:
2
• Set CommandType to ctQuery and set CommandText to an SQL statement you want to execute on the server.
• Set CommandType to ctStoredProc and set CommandText to the name of the stored procedure you want to execute.
• Set CommandType to ctTable and set CommandText to the name of the database tables whose records you want to use.
6. If the stored procedure returns a cursor to be used with visual data controls, add a data source component to the form.
7. Set the DataSet property of the data source component to the TSimpleDataSet object.
8. To activate the dataset, use the Active property or call the Open method.
9. If you executed a stored procedure, use the Params property to retrieve any output parameters.
See Also
dbExpress Components ( see page 16)
68
2.2 Database Procedures RAD Studio Using TStoredProc
To use TSimpleObjectBroker
1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. From the DataSnap category of the Tool Palette, choose the connection component depending on the kind of connection you
want.
4. From the Tool Palette, drag a TSimpleObjectBroker to the form.
5. In the Object Inspector, set the ObjectBroker property of the connection component that you chose in Step 3 to use this
broker.
Warning: Do not use the ObjectBroker property with SOAP connections.
See Also
Using DataSnap ( see page 60)
To use TStoredProc
1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. Associate a dataset with database and session connections.
4. Bind the parameters.
69
Using TTable (Procedure) RAD Studio 2.2 Database Procedures
To bind parameters
1. From the BDE category of the Tool Palette, drag a TStoredProc component to the form.
2. Set the ParamBindMode property to default pbByName to specify how parameters should be bound to the parameters on the
server.
3. View the stored procedure source code of a server in the SQL Explorer if you want to set ParamBindMode to pbByNumber.
4. Determine the correct order and type of parameters.
5. Specify the correct parameter types in the correct order.
Note: Some servers also support binding parameters by ordinal value, the order in which the parameters appear in the stored
procedure. In this case the order in which you specify parameters in the parameter collection editor is significant. The first
parameter you specify is matched to the first input parameter on the server, the second parameter is matched to the second
input parameter on the server, and so on. If your server supports parameter binding by ordinal value, you can set
ParamBindMode to pbByNumber
.
See Also
BDE Overview ( see page 15)
To use TTable
1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. Associate the dataset with the database and session connections.
4. Specify the table type for local tables and control read/write access to local tables.
5. Specify a dBASE index file.
6. Rename local tables.
7. Import data from another table.
70
2.2 Database Procedures RAD Studio Using TTable (Procedure)
4. Use the default session to control all database connections in your application.
5. Set the SessionName property of the TSession component to associate your dataset with an explicitly created session
component.
If you use a session component, the SessionName property of a dataset must match the SessionName property for the
database component with which the dataset is associated.
5. After adding all desired indexes, click the OK button in the Index Files editor.
Note: To do steps 3-5 at runtime, access the IndexFiles property using properties and methods of string lists.
71
Using dbExpress RAD Studio 2.2 Database Procedures
72
2.2 Database Procedures RAD Studio Browsing a Database in the Data Explorer
73
Executing SQL in the Data Explorer RAD Studio 2.2 Database Procedures
74
2.2 Database Procedures RAD Studio Modifying Connections in the Data Explorer
3. Right-click the connection and choose SQL Window. This opens a tabbed SQL Window in the Code Editor.
To execute SQL
1. Enter a valid SQL statement or stored procedure name in the multi-line text box at the top of the SQL Window.
2. Click Execute SQL. If the SQL statement or stored procedure is valid, the result set appears in the bottom pane of the SQL
Window.
Note: The SQL statement or stored procedure must operate against the current connection and its target database. You
cannot execute SQL against a database to which you are not connected.
3. Click Clear All SQL to clear the SQL statement or stored procedure from the multi-line text box.
See Also
Browsing a Database ( see page 74)
To modify connections
1. Choose View Data Explorer. 2
2. Select a provider.
3. Right-click to display a pop-up menu to view your options.
To refresh a connection
1. Choose View Data Explorer.
2. Select a provider.
3. Right-click to display a pop-up menu.
4. Choose Refresh. This operation reinitializes all connections defined for the selected provider.
To delete a connection
1. Choose View Data Explorer.
2. Select a connection.
3. Right-click to display a pop-up menu.
4. Choose Delete Connection. This displays a confirmation message that asks if you want to delete the connection.
5. Click OK.
To modify a connection
1. Choose View Data Explorer.
2. Select a connection.
3. Right-click to display a pop-up menu.
4. Choose Modify Connection. This displays the Connections Editor dialog.
75
Connecting to a Database using the RAD Studio 2.2 Database Procedures
To close a connection
1. Choose View Data Explorer.
2. Select a connection.
3. Right-click to display a pop-up menu.
4. Choose Close Connection. If the connection is open, this operation closes it.
Note: If the Close Connection
command is disabled in the menu, the connection is not open.
To rename a connection
1. Choose View Data Explorer.
2. Select a connection.
3. Right-click to display a pop-up menu.
4. Choose Rename Connection. This displays Rename Connection dialog.
5. Enter a new name.
6. Click OK. The Data Explorer displays the connection with its new name.
See Also
Browsing a Database ( see page 74)
76
2.2 Database Procedures RAD Studio Connecting to a Database using the
9. Get whatever information you want from the database. For instance, TDBXReader.GetColumnCount returns the number of
database columns. The TDBXReader properties ValueTypeand Value contain the data type and value for a given column
number in the current record.
// This sample connects to a database using the ini files.
// These files must be configured for the database.
// Once connected, the sample reads values and displays the
// ANSI values for the first 100 records in a listbox.
procedure Connect;
var
connection: TDBXConnection;
command: TDBXCommand;
reader: TDBXReader;
value: TDBXValue;
valueType: TDBXValueType;
colCountStr: string;
i, j: Integer; 2
numCols: integer;
ListBox1: TListBox;
const
sqlCommand = 'select * from employee';
begin
// Open connection to DB.
connection := BuildConnectionFromConnectionName('ConnectionName');
connection.Open;
// Get command
command := connection.CreateCommand();
command.Text := sqlCommand;
// Execute query
command.Prepare;
reader := command.ExecuteQuery;
77
Connecting to a Database using the RAD Studio 2.2 Database Procedures
begin
value := reader.Value[i];
ListBox1.Items.Add(valueType.Name + ' = ' +
value.GetString);
end
else
ListBox1.Items.Add(valueType.Name);
end;
Inc(j);
until (j > 100) or not reader.Next;
reader.Next;
end;
// Free resources
command.Free;
end;
78
2.3 Interoperable Applications Procedures RAD Studio Using COM Wizards
Topics
Name Description
Using COM Wizards ( see page 79) RAD Studio provides wizards that help you create COM projects and COM
objects. These wizards are available for both Delphi and C++ projects. The
following COM wizards are available in the list for
File New Other <personality> ActiveX:
• Active Form
• Active Server Object
• ActiveX Control
• ActiveX Library
• Automation Object
• COM Object
• COM+ Event Object
2
• COM+ Subscription Object
• Property Page
• Transactional Object
• Type Library
Two other related wizards are available from the
File New Other <personality> Multitier list:
• Remote Data Module
• Transactional Data Module
• Active Form
• Active Server Object
• ActiveX Control
• ActiveX Library
• Automation Object
• COM Object
79
Using COM Wizards RAD Studio 2.3 Interoperable Applications Procedures
80
2.4 Reporting Procedures RAD Studio Adding Rave Reports to RAD Studio
Topics
Name Description
Adding Rave Reports to RAD Studio ( see page 81) Rave Reports offers a powerful set of tools for building reports and including
them in your applications. Rave Reports are installed in a \RaveReports
subdirectory in your installation directory. To make the Rave Reports more easily
accessible, add the command executable to your Tools menu.
81
RAD Studio 2.5 VCL Procedures
Topics
Name Description
Building a Windows "Hello World" Console Application ( see page 88) This "Hello World" console application demonstrates the essential steps for
creating a Windows application in Delphi or C++. The application uses Windows,
a console window, an event, and will display a dialog in response to a user action.
Developing a Windows Application ( see page 89) The following procedure illustrates the essential steps for building a Windows
application.
Building Application Menus ( see page 90) Menus provide an easy way for your users to execute logically grouped
commands. You can add or delete menu items, or drag them to rearrange them
during designtime. In addition to TMainMenu and TPopupMenu components,
the Tool Palette also contains TActionMainMenuBar, TActionManager, and
TActionToolBar.
Building a VCL Forms Application with Decision Support Components ( see Creating a form with tables and graphs of multidimensional data consists of the
page 91) following major steps:
82
2.5 VCL Procedures RAD Studio
Building a VCL Forms ADO Database Application ( see page 98) The following procedure describes how to build an ADO database application.
Building a VCL ADO application consists of the following major steps:
83
RAD Studio 2.5 VCL Procedures
Building an Application with XML Components ( see page 104) This example creates a VCL Forms application that uses an XMLDocument
component to display contents in an XML file.
Copying Data From One Stream To Another ( see page 106) Creating this VCL application consists of the following steps:
84
2.5 VCL Procedures RAD Studio
Displaying a Bitmap Image in a VCL Forms Application ( see page 114) This procedure loads a bitmap image from a file and displays it to a VCL form.
85
RAD Studio 2.5 VCL Procedures
Dynamically Creating a VCL Modeless Form ( see page 121) A modless form is a window that is displayed until it is either obscured by another
window or until it is closed or minimuzed by the user. Using RAD Studio, the
following procedure creates a modeless form dynamically.
Building this VCL application consists of the following steps:
86
2.5 VCL Procedures RAD Studio
Placing A Bitmap Image in a Control in a VCL Forms Application ( see page This procedure adds a bitmap image to a combo box in a VCL forms application.
135)
1. Create a VCL form.
2. Place components on the form.
3. Set component properties in the Object Inspector.
4. Write event handlers for the component's drawing action.
5. Build and run the application.
Reading a String and Writing It To a File ( see page 136) Creating this VCL application consists of the following steps:
87
Building a Windows "Hello World" Console RAD Studio 2.5 VCL Procedures
Creating an Application that Uses Ribbon Controls ( see page 143) This procedure describes how to create an application that uses ribbon controls.
The core ribbon functionality is derived from the TRibbon component. While the
ribbon uses other components, none of the core components are registered on
the tool palette.
Components:
88
2.5 VCL Procedures RAD Studio Building Application Menus
WriteLn('Hello, World!');
ReadLn;
For C++, enter the following after #pragma hdrstop:
#include <iostream>
2. For C++, enter the following code after the opening brace ({):
std::cout<<”Hello, World!”<<std::endl;
std::cin.ignore();
3. Save the application.
89
Building Application Menus RAD Studio 2.5 VCL Procedures
4. Right-click anywhere on the Menu Designer to use the Menu Designer context menu. A drop-down list opens. This is the
Menu Designer context menu.
5. To insert a placeholder below or to the right of the cursor, choose Insert from the context menu.
90
2.5 VCL Procedures RAD Studio Building a VCL Forms Application with
6. To delete the selected menu item (and all its subitems, if any), click Delete from the context menu.
7. To switch among menus in a form, choose Select Menu from the context menu. The Select Menu dialog box appears. It lists
all the menus associated with the form whose menu is currently open in the Menu designer.
8. From the list in the Select Menu dialog box, choose the menu you want to view or edit.
91
Building a VCL Forms Application with RAD Studio 2.5 VCL Procedures
2. Right-click the DecisionQuery component, and select Decision Query Editor.... The Decision Query Editor displays.
3. On the Dimensions/Summary tab, select the BCDEMOS database from the Database: drop-down list.
4. From the Table: drop-down, select the parts.db table. The List of Available Fields: listbox displays the fields in the parts.db
table.
5. Use CTRL+Click to select the PartNo, OnOrder, and Cost fields; then click the right-arrow button next to the Dimensions:
listbox. PartNo, OnOrder, and Cost display in the listbox.
6. Select the OnOrder field; then click the right-arrow button next to the Summaries: listbox and select count from the pop-up
that displays. COUNT(OnOrder) displays in the Summaries: listbox.
7. Select the Cost field in the List of Available Fields: listbox; then click the right-arrow button next to the Summaries: listbox
and select sum from the pop-up that displays. SUM(Cost) displays in the Summaries: listbox.
8. Click OK to close the Decision Query Editor.
2 Note: When you use the Decision Query Editor, the query is initially handled in ANSI-92 SQL syntax and then translated (if
necessary) into the dialect used by the server. The Decision Query editor reads and displays only ANSI standard SQL. The
dialect translation is automatically assigned to the TDecisionQuery's SQL property. To modify a query, edit the ANSI-92
version in the Decision Query rather than the SQL property.
2. In the Object Inspector, select DecisionSource1 from the drop-down list next to the decision pivot's DecisionSource property.
92
2.5 VCL Procedures RAD Studio Building a VCL Forms MDI Application
Placing A Bitmap Image In a Combo Box of a VCL Application ( see page 135)
93
Building a VCL Forms MDI Application RAD Studio 2.5 VCL Procedures
2. Navigate to the folder in which you want to store the files for the project.
3. Click OK.
4. Choose Run Run to compile and run the application.
5. Try commands that are automatically set up by the MDI Application wizard.
See Also
VCL Overview ( see page 36)
94
2.5 VCL Procedures RAD Studio Building a VCL Forms MDI Application
To add event handlers for the New child and Close All commands
1. If necessary, open the Menu designer and select New child.
2. In the Object Inspector, double-click the OnClick event on the Events tab. The Code Editor displays with the cursor in the
TfrMain.mnNewChildClick (Delphi) or TfrMain::mnNewChildClick (C++) event handler block.
3. For Delphi, enter the following code:
CreateChildForm('Child '+IntToStr(MDIChildCount+1));
For C++, enter the following code:
CreateChildForm( “Child “ + IntToStr( MDIChildCount + 1 ) );
4. In the Menu designer, select Close All.
95
Creating a New VCL Component RAD Studio 2.5 VCL Procedures
5. In the Object Inspector, double-click the OnClick event on the Events tab. The Code Editor displays with the cursor in the
TfrMain.mnCloseAllClick (Delphi) or TfrMain::mnCloseAllClick (C++) event handler block.
6. For Delphi, enter the following code:
for i:=0 to MDIChildCount - 1 do
MDIChildren[i].Close;
For C++, enter the following code:
for( int i = 0; i < MDIChildCount; i++ ) {
MDIChildren[i]->Close();
}
7. For Delphi, declare the local variable i. The first two lines of the event handler code should appear as shown here when you
are done:
procedure TfrMain.mnCloseAllClick(Sender: TObject);
var i: integer;
Note: The event handler minimizes the child window in the main window. To close the child window, you must add an OnClose
procedure to the child form (next).
96
2.5 VCL Procedures RAD Studio Creating a New VCL Component
To create a unit
1. On the Create Unit page, select the Create Unit radio button.
2. Click Finish. The new unit opens in the Code Editor.
97
Building a VCL Forms ADO Database RAD Studio 2.5 VCL Procedures
To install a unit into the package created before starting the wizard
1. On the Create Unit page, select Add unit to <my_new_package>.
2. Click Finish. The new unit opens in the Code Editor.
See Also
VCL Overview ( see page 36)
2
2.5.10 Building a VCL Forms ADO Database Application
The following procedure describes how to build an ADO database application.
98
2.5 VCL Procedures RAD Studio Building a VCL Forms Application
8. Click OK to close the Data Link Properties dialog. Click OK to close the ConnectionString dialog.
99
Creating Actions in a VCL Forms RAD Studio 2.5 VCL Procedures
Building a VCL Forms MDI Application Without Using a Wizard ( see page 94)
Using ActionManager to Create Actions in a VCL Forms Application ( see page 102)
1. Create a main window and add tools for creating a main menu and a File open action.
2. Add the File category to the main menu.
3. Add the File open action to the File category.
4. Build and run the application.
100
2.5 VCL Procedures RAD Studio Building a VCL Forms "Hello World"
8. Click File in the editor. The FileOpen1 action displays in the Action listbox.
101
Using ActionManager to Create Actions in RAD Studio 2.5 VCL Procedures
s = “Hello world!”;
ShowMessage( s );
Building the VCL application with ActionManager actions consists of the following major steps:
102
2.5 VCL Procedures RAD Studio Building a VCL Forms dbExpress
Building a VCL Forms MDI Application Without Using a Wizard ( see page 94)
Building a VCL Forms dbExpress application consists of the following major steps:
103
Building an Application with XML RAD Studio 2.5 VCL Procedures
104
2.5 VCL Procedures RAD Studio Building an Application with XML
<StockHoldings>
<Stock exchange="NASDAQ">
<name>CodeGear</name>
<price>10.375</price>
<symbol>BORL</symbol>
<shares>100</shares>
</Stock>
<Stock exchange="NYSE">
<name>MyCompany</name>
<price>8.75</price>
<symbol>MYCO</symbol>
<shares type="preferred">25</shares>
</Stock>
</StockHoldings>
2. Save the file to your local drive as an XML document. Give it a name such as stock.xml.
3. Open the document in your browser. The contents should display without error.
Note: In the browser, you can choose View->Source
to view the source file in the text editor.
105
Copying Data From One Stream To RAD Studio 2.5 VCL Procedures
var
BorlandStock: IXMLNode;
Price: string;
4. In the Object Inspector with Button2 selected, double-click the OnClick event on the Events tab. The Code displays with the
cursor in the TForm1.Button2Click event handler block.
5. Enter the following code to display the stock price for the second child node when the MyCompany button is clicked:
MyCompany:=XMLDocument1.DocumentElement.ChildNodes[1];
Price:= MyCompany.ChildNodes['price'].Text;
Memo1.Text := Price;
IXMLNode *MyCompany = XMLDocument1–>DocumentElement
->ChildNodes->GetNode(1);
WideString Price = BorlandStock->ChildNodes
->FindNode( “price” )->Text;
Memo1–>Text = Price;
6. For Delphi, add a var section just above the code block in the event handler, and enter the following local variable
declarations:
var
MyCompany: IXMLNode;
Price: string;
106
2.5 VCL Procedures RAD Studio Copying a Complete String List (VCL)
107
Copying a Complete String List (VCL) RAD Studio 2.5 VCL Procedures
108
2.5 VCL Procedures RAD Studio Creating Strings
Memo1.Lines.Assign(ComboBox1.Items);
Memo1–>Lines->Assign( ComboBox1–>Items );
The strings from ComboBox1 overwrite the 'Memo1' string.
See Also
VCL Overview ( see page 36)
109
Creating a VCL Form Instance Using a RAD Studio 2.5 VCL Procedures
var
StringList: TStrings;
For C++, enter the following variable declarations:
TStrings *StringList;
5. Insert the cursor within the code block, and type the following code:
StringList := TStringList.Create;
try
with StringList do begin
Add('Animals');
Add('Cats');
Add('Flowers');
end;
110
2.5 VCL Procedures RAD Studio Creating a VCL Form Instance Using a
111
Deleting Strings RAD Studio 2.5 VCL Procedures
3. With Form2 displayed, attempt to click on Form1 to activate it. Nothing happens. Click the X in the upper right corner of
Form2. Form2 closes and Form1 becomes the active form.
See Also
VCL Overview ( see page 36)
2 2. From the Standard page of the Tool palette, place two TButtons and a TListBox component on the form.
3. Select Button1 on the form.
4. In the Object Inspector, enter Add for the Name and Caption properties.
5. Select Button2 on the form.
6. In the Object Inspector, enter Delete for the Name and Caption properties.
112
2.5 VCL Procedures RAD Studio Displaying an Auto-Created VCL Form
Add('Elephants');
Add('Birds');
ListBox1.Items.AddStrings(MyList);
end;
finally
MyList.Free;
end;
MyList = new TStringList();
try {
MyList->Add( “Mice” );
MyList->Add( “Goats” );
MyList->Add( “Elephants” );
MyList->Add( “Birds” );
ListBox1–>Items->AddStrings( MyList );
} __finally {
MyList->Free();
}
113
Displaying a Bitmap Image in a VCL Forms RAD Studio 2.5 VCL Procedures
114
2.5 VCL Procedures RAD Studio Displaying a Bitmap Image in a VCL Forms
Tip: You can change the size of the rectangle to be displayed by adjusting the Rect parameter values.
3. For Delphi, add the following variable declaration in the var block:
Bitmap : TBitmap;
115
Displaying a Full View Bitmap Image in a RAD Studio 2.5 VCL Procedures
Placing A Bitmap Image In a Combo Box of a VCL Application ( see page 135)
116
2.5 VCL Procedures RAD Studio Drawing a Polygon in a VCL Forms
3. For Delphi, add the following variable declaration in the var block:
Bitmap : TBitmap;s
Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)
Placing A Bitmap Image In a Combo Box of a VCL Forms Application ( see page 135)
117
Drawing a Rounded Rectangle in a VCL RAD Studio 2.5 VCL Procedures
Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)
1. Create a VCL form and code the form's OnPaint event handler.
2. Build and run the application.
118
2.5 VCL Procedures RAD Studio Drawing Straight Lines In a VCL Forms
Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)
119
Dynamically Creating a VCL Modal Form RAD Studio 2.5 VCL Procedures
See Also
VCL Overview ( see page 36)
Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)
120
2.5 VCL Procedures RAD Studio Dynamically Creating a VCL Modeless
121
Iterating Through Strings in a List RAD Studio 2.5 VCL Procedures
5. Create a control on the main form to create and display the modal form; then write the event handler.
6. Build and run the application.
122
2.5 VCL Procedures RAD Studio Iterating Through Strings in a List
123
Writing Cleanup Code RAD Studio 2.5 VCL Procedures
} __finally {
MyList->Free();
}
2 See Also
VCL Overview ( see page 36)
124
2.5 VCL Procedures RAD Studio Avoiding Simultaneous Thread Access to
1. Lock objects.
2. Use critical sections.
3. Use a multi-read exclusive-write synchronizer 2
To lock objects
1. For objects such as canvas that have a Lock method, call the Lock method, as necessary, to prevent other objects from
accessing the object, and call Unlock when locking is no longer required.
2. Call TThreadList.LockList (Delphi) or TThreadList::LockList() (C++) to block threads from using the list object
TThreadList, and call TThreadList.UnlockList when locking is no longer required.
Note: You can safely make calls to TCanvas.Lock and TThreadList.LockList.
125
Defining the Thread Object RAD Studio 2.5 VCL Procedures
} __finally {
LockXY->Release();
}
Warning: Critical sections only work if every thread uses them to access global memory. Otherwise, problems of simultaneous
access can occur.
4. Click OK.
The Code Editor displays the skeleton code for the thread object.
The code generated for the new unit will look like this if you named your thread class TMyThread.
unit Unit1;
interface
uses
Classes;
type
TMyThread = class(TThread)
private
126
2.5 VCL Procedures RAD Studio Defining the Thread Object
{ Private declarations }
protected
procedure Execute; override;
end;
implementation
Synchronize(UpdateCaption);
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{ TMyThread }
procedure TMyThread.Execute;
begin
{ Place thread code here }
end;
end.
Adding a name for the thread generates additional code for the unit. It includes the Windows unit, adds the procedure (Delphi) or
function (C++) SetName, and adds the record TThreadNameInfo (Delphi) or struct THREADNAME_INFO (C++). The name is
assigned to the FName field, as shown here:
unit Unit1;
2
interface
uses
Classes {$IFDEF MSWINDOWS} , Windows {$ENDIF};
type
TMyThread = class(TThread)
private
procedure SetName;
protected
procedure Execute; override;
end;
implementation
Synchronize(UpdateCaption);
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{$IFDEF MSWINDOWS}
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
127
Defining the Thread Object RAD Studio 2.5 VCL Procedures
{ TMyThread }
procedure TMyThread.SetName;
{$IFDEF MSWINDOWS}
var
ThreadNameInfo: TThreadNameInfo;
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'MyThreadName';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), @ThreadNameInfo
);
except
end;
{$ENDIF}
end;
procedure TMyThread.Execute;
begin
SetName;
{ Place thread code here }
end;
2 end.
// Unit1.h
#ifndef Unit1H
#define Unit1H
#include <Classes.hpp>
class TMyThread : public TThread
{
typedef struct tagTHREADNAME_INFO
{
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
} THREADNAME_INFO;
private:
void SetName();
protected:
void __fastcall Execute();
public:
__fastcall TMyThread(bool CreateSuspended);
};
#endif
// Unit1.cpp
#include "Unit3.h"
#pragma package(smart_init)
128
2.5 VCL Procedures RAD Studio Handling Exceptions
void TMyThread::SetName()
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = "TMyThreadName";
info.dwThreadID = -1;
info.dwFlags = 0;
__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD),(DWORD*)&info; );
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
}
129
Initializing a Thread RAD Studio 2.5 VCL Procedures
Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)
Value Priority
tpIdle The thread executes only when the system is idle. Windows won't interrupt the 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.
2 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.
2. Override the Create method (Delphi) or default constructor (C++) of the thread class by adding a new constructor to the
declaration.
3. Code the constructor. The following is an example for a low-priority thread:
constructor TMyThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
Priority := tpIdle;
end;
TMyThread::TMyThread( bool CreateSuspended ) : TThread( CreateSuspended ) {
Priority = tpIdle;
}
4. Indicate whether the thread should be freed automatically when it finishes executing.
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.
130
2.5 VCL Procedures RAD Studio Using the Main VCL Thread
See Also
VCL Overview ( see page 36)
1. Create a separate routine to handle Windows messages received by components in your application.
2. Call CheckSynchronize periodically.
3. Declare thread-local variables, as necessary, for exclusive use by your thread.
Note: Because Synchronize uses a message loop, it does not work in console applications. For console applications, use
other mechanisms, such as critical sections, to protect access to VCL objects.
To call CheckSynchronize
1. Call CheckSynchronize periodically within the main thread to enable background threads to synchronize execution with the
main thread.
2. To ensure the safety of making background thread calls, call CheckSynchronize when the application is idle, for example,
from an OnIdle event handler.
131
Waiting for Threads RAD Studio 2.5 VCL Procedures
section for global variables only. Do not use it for Pointer and Function variables or types that use copy-on-write semantics,
such as long strings.
variable, you must initialize it to a constant expression. For example, int __thread foo = 3; is a legal statement, but int
__thread foo = get_value(); is not permitted because the initialization occurs at runtime.
See Also
VCL Overview ( see page 36)
Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)
132
2.5 VCL Procedures RAD Studio Waiting for Threads
133
Placing A Bitmap Image in a Control in a RAD Studio 2.5 VCL Procedures
DoSomething();
}
WaitFor return values
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.
See Also
VCL Overview ( see page 36)
Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)
Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)
134
2.5 VCL Procedures RAD Studio Placing A Bitmap Image in a Control in a
135
Renaming Files RAD Studio 2.5 VCL Procedures
2 3. From the Standard page of the Tool palette, place a TButton component on the form.
136
2.5 VCL Procedures RAD Studio Adding and Sorting Strings
137
Adding and Sorting Strings RAD Studio 2.5 VCL Procedures
MyList.Add('Cars');
MyList.Sort;
if MyList.Find('Flowers', Index) then
begin
ListBox1.Items.AddStrings(MyList);
Label1.Caption := 'Flowers has an index value of ' + IntToStr(Index);
end;
finally
MyList.Free;
end;
MyList = new TStringList();
try {
MyList->Add( "Animals" );
MyList->Add( "Flowers" );
MyList->Add( "Cars" );
MyList->Sort();
if( MyList->Find( "Flowers", Index ) {
ListBox1–>Items->AddStrings( MyList );
Label1–>Caption = "Flowers has an index of " +
IntToStr( Index );
}
} __finally {
138
2.5 VCL Procedures RAD Studio Creating a VCL Forms ActiveX Button
MyList->Free();
}
Note: Find will only work on sorted lists. Use IndexOf on unsorted lists.
This procedure uses the VCL forms ActiveX wizard to create an ActiveX control. To test the control, you can install it on your
machine as a VCL component in the IDE. To install the control, you first need to create a package for it. This procedure consists
of the following major steps:
8. Click OK. The wizard generates the code needed to implement the ActiveX control and adds the code to the project. If the
project is already an ActiveX library, the wizard adds the control to the current project.
139
Creating a VCL Forms ActiveX Active Form RAD Studio 2.5 VCL Procedures
140
2.5 VCL Procedures RAD Studio Building a VCL Forms Web Browser
This procedure uses the VCL forms ActiveX Active Form wizard to create an Active Form containing two components. To test
the control, you can deploy it to the Web. This procedure consists of the following major steps:
141
Creating an Application that Uses Ribbon RAD Studio 2.5 VCL Procedures
142
2.5 VCL Procedures RAD Studio Adding Commands to the Ribbon
Components:
TRibbon
TRibbon
TRibbonApplicationMenuBar
Caption
TRibbonQuickAccessToolbar
TRibbonPage
TRibbonGroup
143
Adding Commands to the Ribbon RAD Studio 2.5 VCL Procedures
This topic assumes that you are familiar with the TActionManager component and the components associated with its use.
Numerous new properties have been added to help support the ribbon requirements. Many existing properties have no effect
when modified on a command that is displayed on the ribbon.
For instance:
• Small buttons always display their glyph to the left of the caption.
• Large buttons always display their glyph at the top.
• A Large button must have a caption. The caption can be a maximum of two lines, and the button width is resized accordingly.
A large button's height is fixed to cover the height of the group where the command is displayed.
• Only small buttons with no caption can be displayed in groups.
New Properties
CommandStyle: The CommandStyle determines the type of control that is used to represent this command on the ribbon. The
default style is csButton. CommandStyle is used extensively for determining the control type that is used for the command
except under one exception.
type TCommandStyle = (csButton, csMenu, csSeparator, csText, csGallery, csComboBox, csControl,
csCustom);
2
Style of the Command on the Ribbon Group
Note: You can only use the csComboBox CommandStyle if you first place a TRibbonComboBox from the tool palette onto your
ribbon Group.
CommandProperties: CommandProperties is a dynamic property class. The published properties of this property (it is a
TPersistent descendant) vary depending on the CommandStyle that has been selected. If you select the csButton
CommandStyle, the CommandProperties class used is called TButtonProperties. This property class publishes properties that
are specific to the csButton CommandStyle.
An example is ButtonSize, which allows you to indicate if the button is a large button or a small button. There is no need for a
csMenu command to have a ButtonSize property because the menu does not react to a size variance.
All CommandProperties classes descend from TCommandProperties. If you are using the csCustom CommandStyle, you must
descend from the TCommandProperties class.
144
2.5 VCL Procedures RAD Studio Adding Commands to the Ribbon
Properties that can be available in the CommandProperties property depending on your selected CommandStyle
csButton ButtonSize
Size of the button:
TButtonSize = (bsSmall, bsLarge);
ButtonType
Special types of buttons allowed:
TButtonType = (btNone, btDropDown, btSplit, btGallery); // btNone - normal
button // btDropdown - button display a dropdown menu // btSplit - button has
dropdown menu and a default action // btGallery - button displays a gallery as a
dropdown
GroupPosition
Position of this command in a group of commands:
TGroupPosition = (gpNone, gpStart, gpMiddle, gpEnd, gpSingle); // Determines
whether a border is drawn around a button // gpNone - no border drawn // gpStart
- the right edge of a border isn't drawn // gpMiddle - top and bottom of border
is drawn // gpEnd - the left edge isn't drawn // gpSingle - the full border is
drawn
csCheckBox Command appears like an Office 2007 checkbox.
csComboBox AllowResize Controls whether the popup menu associated with the combo box can be resized:
TGalleryResize = (grNone, grVertical, grBoth); // grNone – don’t allow resizing
// grVertical – only allow vertical resizing // grBoth – allow both vertical and
horizontal resizing
Items
Items to display when the user selects the dropdown button. These items display in a window like a regular
combobox.
Text
The text to display in the combobox. 2
Width
The width of the spinner control, excluding any caption width.
csControl ContainedControl Reference to the control it is associated with on the ribbon.
csCustom User-defined.
csGallery The csGallery CommandProperties class descends from the csButton CommandProperties class.
This means all of the csButton properties are also available for csGallery commands, as well as the
following gallery ones.
GalleryType
Type of gallery to be displayed:
TGalleryType = (gtDropDown, gtGrid, gtRibbon); // gtDropDown - Gallery is in the
form of a dropdown menu // gtGrid - Gallery is a grid layout. Meaning it can be
more than one item across. ItemsPerRow controls the number of items across //
gtRibbon - Gallery is in Ribbon
ItemsPerRow
Number of items to display on a row.
ShowRichContent
Set to true to display rich content for the gallery items.
csMenu ShowRichContent: Set to true to display rich content for the menu item.
Content: The content to be displayed as rich content.
Font: Use a custom font when displaying the rich content. Rich content menu items are limited to two lines.
Depending on the content, the menu items might be wider and are not changed to be taller, and some menu
items therefore display additional lines (beyond the two permitted.)
csRadioButton Command appears like an Office 2007 radio button.
145
Adding Commands to the Ribbon RAD Studio 2.5 VCL Procedures
csSeparator csText and csSeparator share the same CommandProps class, so the available properties are the same.
Alignment: The alignment of the caption text.
EllipsisPosition: Position of any ellipsis if caption text is too wide for the menu width. It is only possible
for menu items to be displayed in the Application menu.
Font: Font to use when drawing the caption text.
Width: Force the width of the created control to be a specific size. Leave as -1 for csSeparator
CommandStyle and modify as required for csText CommandStyle.
csText csText and csSeparator share the same CommandProps class, so the available properties are the same.
KeyTip: The key that can be pressed to activate the command when using the keyboard. To activate KeyTips, press either the
Alt or F10 key.
NewCol: Setting NewCol for a command forces the control to be displayed in a new column of the ribbon group. This property is
only effective when the ribbon group alignment is gaVertical.
NewRow: Setting NewRow for a command forces the control to be displayed in a new row of the ribbon group. This property is
only effective when the ribbon group alignment is gaHorizontal.
Default: Set to true to force a menu items caption to be bolded. Only effective for menu items.
See Also
VCL Overview ( see page 36)
146
2.6 WebSnap Procedures RAD Studio Building a WebSnap Application
Please note that WebSnap is being deprecated in RAD Studio. Although WebSnap is still documented in the online help, the
WebSnap product is no longer fully supported. As an alternative, you should begin using IntraWeb (VCL for the Web). IntraWeb
( see page 2254) is documented in this online help. For more documentation on VCL for the Web, go to
http://www.atozed.com/intraweb/docs/.
Topics
Name Description
Building a WebSnap Application ( see page 148) The following procedure describes the generic steps required to build a simple
WebSnap project. For more advanced topics, refer to related information
following the procedure.
Building a WebSnap application consists of five major steps:
147
Building a WebSnap Application RAD Studio 2.6 WebSnap Procedures
3. Click OK.
148
2.6 WebSnap Procedures RAD Studio Building a WebSnap "Hello World"
Building the WebSnap "Hello world" application consists of five major steps:
3. Click OK.
149
Debugging a WebSnap Application using RAD Studio 2.6 WebSnap Procedures
To register the server information application for the Web Application Debugger
1. Navigate to the bin directory of your RAD Studio installation.
2. Run serverinfo.exe.
3. Close the blank application window that opens.
This step only needs to be performed the first time you use the Web Application Debugger.
150
2.6 WebSnap Procedures RAD Studio Using the HTML Tag Editor
The Tag Editor lets you review and modify HTML tags while viewing the corresponding controls in the Designer window, above
it. The Tag Editor allows you to use the Code Completion, Error Insight, and Live Template Completion features that are
also available in the Code Editor. Refer to the links at the end of this topic for more information about using each of these
features.
The Tag Editor works with one tag at a time, unless you have the Document object selected or you have zoomed out from a tag. 2
(When the document object is selected, you'll see the item "DOCUMENT" on the Object Inspector.)
Use the zoom buttons to zoom out to a tag's parent and zoom back in to the selected child tag. Zooming isn't specific to the tag,
it's more generic to the markup in the document itself. For example, if the cursor is on a tag in your HTML markup, and you use
the Zoom command, it will take you to the outer tag, or one level above the attribute where the cursor is positioned.
Validation against standard HTML style rules occurs automatically. If validation fails, the incorrect element is highlighted in red in
the Designer, and Error Insight appears in the Tag Editor to help you correct the problem.
151
Using the HTML Tag Editor RAD Studio 2.6 WebSnap Procedures
To modify a control
1. Click anywhere on the Designer surface to deselect all controls.
2. Locate the tag that corresponds to the control you want to modify.
3. Modify the code, and the change is immediately reflected in the control on the Designer surface.
4. Save your project to make the modifications permanent.
2. To zoom in so that you can view only the content within the FORM tags, click the right-hand blue arrow in the gray header of
the tag editor.
Note: You can only use this feature when the cursor is somewhere in the tag editor, rather than on the Designer surface.
152
2.7 Web Services Procedure RAD Studio Building a "Hello World" Web Services
Topics
Name Description
Building a "Hello World" Web Services Application ( see page 153) Web Services are self-contained modular applications that can be published and
invoked over a network (such as the World Wide Web). Web Services use
SOAP, a standard lightweight protocol for exchanging information in a distributed
environment. It uses HTTP as a communications protocol and XML to encode
remote procedure calls.
153
Building a "Hello World" Web Services RAD Studio 2.7 Web Services Procedure
7. Click Finish. The importer creates new units that define and register invokable interfaces for the operations defined in the
document, and that define and register remotable classes for the types that the document defines.
See Also
Web Services Overview ( see page 44)
154
3 RAD Studio
3 Reference
Topics
Name Description
C++ Reference ( see page 156) This section contains reference topics for the C++ library in RAD Studio.
Win32 Developer's Guide ( see page 1217) This section contains the Win32 Developer's Guide topics for the Delphi Win32
personality in RAD Studio.
155
Command Line Utilities RAD Studio 3.1 C++ Reference
Topics
Name Description
Command Line Utilities ( see page 156) C++Builder provides a rich set of command line utilities in addition to its
integrated development environment (IDE). These utilities enable you to use the
command line to perform targeted compilation and other related functions,
including file search and import of definition files.
C++ Compiler Errors And Warnings (C++) ( see page 216) This section describes the RAD Studio C++ compiler error and warning
messages.
C++ Language Guide ( see page 385) This sections contains C++ language topics.
C Runtime Library Reference ( see page 711) RAD Studio has several hundred functions, macros, and classes that you call
from within your C and C++ programs to perform a wide variety of tasks,
including low- and high-level I/O, string and file manipulation, memory allocation,
process control, data conversion, mathematical calculations, and more.
Note: In the online help, each function, macro, and class in the C Runtime
Library is listed only once . However, some functions, macros, and classes are
defined in more than one header file.
For example, _strerror is defined in both string.h and stdio.h. For functions
that are defined in several header files, the online... more ( see page 711)
Topics
Name Description
BCC32, the C++ Command-Line Compiler ( see page 159) The CodeGear C++ compiler (BCC32.EXE) is a resource compiler shell. It
invokes BRCC32 and RLINK32, depending on the command-line syntax.
BRC32, the Resource Shell ( see page 163) The Borland resource compiler (BRC32) is a resource compiler shell. It invokes
BRCC32 and RLINK32, depending on the command-line syntax.
BRCC32.EXE, the Resource Compiler ( see page 165) BRCC32 is the command-line version of the resource compiler. It accepts a
resource script file (.RC) as input and produces a resource object file (.RES) as
output.
RAD Studio provides a choice in resource compilers. You can choose to use
either BRCC32 or RC (the Microsoft SDK resource compiler) on the
Project Options Resource Compiler dialog box.
COFF2OMF.EXE, the Import Library Conversion Tool ( see page 166) COFF2OMF converts a COFF import library file (InputFile) to a corresponding
OMF import library file (OutputFile). COFF2OMF.EXE is located in the
C++Builder \bin directory.
CPP32.EXE, the C Compiler Preprocessor ( see page 167) CPP32.EXE produces a file that lists a C or C++ program, in which all #include
3 files and #define macros have been expanded. While you do not need to use the
preprocessor during normal compilation, you may find the list file helpful for
debugging purposes.
Often, when the compiler reports an error inside a macro or an include file, you
can get more information about what the error is if you can see the include files
or the results of the macro expansions. In many multi-pass compilers, a separate
pass performs this work, and the results of the pass can be... more ( see page
167)
DCC32.EXE, the Delphi Command Line Compiler ( see page 169) DCC32 is the Delphi (Object Pascal) command line compiler.
To display command line help, enter:
156
3.1 C++ Reference RAD Studio Command Line Utilities
GREP.EXE, the text search utility ( see page 170) GREP (Global Regular Expression Print) is a powerful text-search program
derived from the UNIX utility of the same name. GREP searches for a text pattern
in one or more files or in its standard input stream.
ILINK32.EXE, the Incremental Linker ( see page 174) ILINK32 links object modules (.OBJ files), library modules (.LIB files), and
resources to produce executable files (.EXE, .DLL, and .BPL files). ILINK32
creates and maintains a series of state files that contains this information. These
state files allow subsequent links to be incremental, greatly reducing the total link
time.
IMPDEF.EXE, the Module Definition Manager ( see page 179) Import libraries provide access to the functions in a Windows DLL. Import
libraries contain records. Each record contains the name of a DLL and specifies
where in the DLL the imported functions reside. These records are bound to the
application by the linker and provide Windows with the information necessary to
resolve DLL function calls. You can substitute an import library for part or all of
the IMPORTS section of a module definition file.
IMPDEF takes as input a DLL name, and produces as output a module definition
file with an EXPORTS section containing the names of functions exported by...
more ( see page 179)
IMPLIB.EXE, the Import Library Tool ( see page 181) IMPLIB takes as input either DLLs or module definition files, or both, and
produces an import library as output.
If you've created a Windows application, you've already used IMPORT32.LIB, the
import library for the standard Windows DLLs. IMPORT32.LIB is linked
automatically when you build a Win32 application in the C++Builder IDE and
when using BCC32 at the command line.
An import library lists some or all of the exported functions for one or more DLLs.
IMPLIB creates an import library directly from DLLs or from module definition files
for DLLs (or a combination of the two).
Using Include Files ( see page 182) In C++, include files always have the file extension .h.
MAKE ( see page 183) MAKE.EXE is a command-line utility that helps you manage project compilation
and link cycles. MAKE is not inherently tied to compiling and linking, but is a
more generic tool for executing commands based on file dependencies. MAKE
helps you quickly build projects by compiling only the files you have modified
since the last compilation. In addition, you can set up rules that specify how
MAKE should deal with the special circumstances in your builds.
MAKE Directives ( see page 186) MAKE directives resemble directives in languages such as C and Pascal. In
MAKE, directives perform various control functions, such as displaying
commands onscreen before executing them. MAKE directives begin either with
an exclamation point or a period, and they override any options given on the
command line. Directives that begin with an exclamation point must appear at the
start of a new line.
The following table lists the MAKE directives and their corresponding
command-line options:
MAKE Macros ( see page 191) A macro is a variable that MAKE expands into a string whenever MAKE
encounters the macro in a makefile. For example, you can define a macro called
LIBNAME that represents the string "mylib.lib." To do this, type the line LIBNAME
= mylib.lib at the beginning of your makefile. Then, when MAKE encounters the
macro $(LIBNAME), it substitutes the string mylib.lib. Macros let you create
template makefiles that you can change to suit different projects.
To use a macro in a makefile, type $(MacroName) where MacroName is a
defined macro. You can use either braces or parentheses to enclose
MacroName.
MAKE... more ( see page 191)
MAKE Rules (Explicit and Implicit) and Commands ( see page 193) You write explicit and implicit rules to instruct MAKE how to build the targets in
your makefile. In general, these rules are defined as follows:
157
Command Line Utilities RAD Studio 3.1 C++ Reference
Module Definition Files ( see page 199) You use module definition files with ILINK32. A module definition file is an ASCII
text file that provides information to ILINK32 about the contents and system
requirements of a Windows application. Use IMPDEF to create a module
definition file.
The module definition file names the .EXE or .DLL, identifies the application type,
lists imported and exported functions, describes the code section and data
segment attributes, lets you specify attributes for additional code sections and
data segments, specifies the size of the stack, and provides for the inclusion of a
stub program.
Using Precompiled Header Files ( see page 203) Precompiled header files can dramatically increase compilation speed by storing
an image of the symbol table on disk in a file, then later reloading that file from
disk instead of parsing all the header files again. Directly loading the symbol table
from disk is much faster than parsing the text of header files, especially if several
source files include the same header file.
To use precompiled header files, specify the various -H options in your BCC32
command.
Precompiled Header Options
RLINK32.DLL, the Resource Linker (C++) ( see page 204) RLINK32.DLL is the resource linker that binds resources, in .RES file form, to an
.EXE file, and marks the resulting .EXE file as a Windows executable.
RLINK32.DLL also:
158
3.1 C++ Reference RAD Studio Command Line Utilities
WSDLIMP.EXE, the Command Line WSDL Import Tool ( see page 214) WSDLIMP generates code to represent the types and APIs that a WSDL
document defines. This code can be used to write client applications that call on
the Web Service that the WSDL (Web Services Description Language) document
describes. If you want to write a server that implements the Web Service, one of
the command line options tells the importer to generate implementation classes
that you can then complete by filling in the bodies of the generated methods.
Note: WSDLIMP ignores any definitions in the WSDL document for which it can't
generate code. That is, it can only import Web Services... more ( see page 214)
Use spaces to separate the command-line compiler name, each option, and the filenames. Precede each option by either a
hyphen (-) or a forward slash (/). For example:
BCC32 -Ic:\code\hfiles
You can also specify options in configuration (.CFG) files, which are described in a following section.
You can use BCC32 to send .OBJ files to ILINK32 or .ASM files to TASM32 (if you have TASM32 installed on your machine).
For example, to display a list of the commonly used compiler command line options, type:
BCC32 -h
The displayed list indicates the options that are enabled by default (*):
C:\>bcc32 -h CodeGear C++ 5.92 for Win32 Copyright (c) 1993, 2007 CodeGear
Available options (* = default setting, xxx = has sub-options: use -h -X):
(Note: -X- or -w-XXX will usually undo whatever was set or unset by -X)
-3 Generate 80386 protected-mode compatible instructions
-4 Generate 80386/80486 protected-mode compatible instructions
-5 Generate Pentium instructions
-6 Generate Pentium Pro instructions
-Axxx Enable ANSI conformance
-B Compile to .ASM (-S), then assemble to .OBJ
-C Enable nested comments
-CP Enable code paging (for MBCS)
-D -D <name> defines 'name' as a null string, or use -D<name>=<value>
-E Specify which assembler to use
-G Optimize for size/speed; use -O1 and -O2 instead
-Hxxx Generate and use precompiled headers
-I Set the include file search path
-Jxxx Template generation options
-K Set default character type to unsigned 3
-L Library file search path
-M Create a linker map file
-O Optimize jumps
-P Perform C++ compile regardless of source extension
-Q Extended compiler error information
-R Include browser information in generated .OBJ files
-RF Find references to symbol
* -RT Enable runtime type information
-S Compile to assembly
-T Specify assembler option, e.g. -Tx
159
Command Line Utilities RAD Studio 3.1 C++ Reference
Displaying Help for Specific Options, Groups such as -Axxx and -Vxxx
You can get more specific information about each of the multi-letter options, such as -Axxx (language compatibility and
standards compliance) and -Vxxx (backward compatibility).
To do this, use the -h command line option with the initial letter of the option group (such as -A to specify the -Axxx options).
BCC32 will display only the help topics for the specified set of options (such as —Axxx, —Vxxx or —Wxxx).
For example, to display a description of the -Axxx (language compatibility and standards compliance) options, use the —h and —A
command line options:
C:\>bcc32 -h -A
CodeGear C++ 6.10 for Win32 Copyright (c) 1993-2008 CodeGear
3 Available options (* = default setting, xxx = has sub-options: use -h -X):
(Note: -X- or -w-XXX will usually undo whatever was set or unset by -X)
-A Enable ANSI conformance
-AF Use SUN Forte keywords and extensions
-AG Use GNU keywords and extensions
-AK Use Kernighan and Ritchie keywords and extensions
-AT Use CodeGear C++ keywords and extensions (also -A-)
-AU Use UNIX System V keywords and extensions
-An Use C99 keywords and extensions
-Ax Use C++-0x keywords and extensions
160
3.1 C++ Reference RAD Studio Command Line Utilities
In the following example, the BCC32 command line help displays details about all the -Vxxx (backward compatibility) options:
C:\>bcc32 -h -V
CodeGear C++ 6.10 for Win32 Copyright (c) 1993-2008 CodeGear
Available options (* = default setting, xxx = has sub-options: use -h -X):
(Note: -X- or -w-XXX will usually undo whatever was set or unset by -X)
-V Compatibility options
-V0 External C++ virtual tables
-V1 Public C++ virtual tables
* -VA Generate all global functions in their own virtual/weak segment
-VC Do not mangle calling convention into symbols
-VF MFC compatibility
-VF3 Support MFC 3.2
-VF4 Support MFC 4.0
* -VI Use Microsoft search algorithm to locate header files
-VM Microsoft Visual C++ compatibility
-Va Support old-style class arguments
-Vb Enable backward compatability with Bcc versions 5.8.2 and earlier
-Vbc Don't collapse reference to reference and allow qualified references
-Vbe Allow old-style explicit template specialization
-Vbn Allow calling of non-const or non-volatile member function for a const
or volatile object
-Vbo Use old Borland overload resolution rules
-Vbr Allow non-const reference binding
-Vbs Treat string literals as non-const
-Vbt Use old Borland type rules for ternary operators
-Vbx Allow explicit template specialization as a member function
-Vc Support constructor displacements
-Vd Use old C++ for-statement scoping rules
-Ve Zero-length empty base classes
-Vg Disable lexical digraph scanner
-Vi Use old 8.3 search algorithm to locate header files
-Vl Use old Borland class layout
-Vm Member pointer options
-Vmd Use the smallest possible representation for member pointers
-Vmm Support multiple inheritance for member pointers
-Vmp Honor declared precision of member pointers
-Vms Support single inheritance for member pointers
-Vmv Place no restrictions on where member pointers can point
-Vn Enable new operator names: and, or, and_eq, bitand, etc.
-Vo Set (almost) all compatibility flags; used with old code
-Vp Push 'this' first, as does Pascal
-Vr Reverse order for Multi-character constant
-Vs Use old-style virdef generation
-Vt Put virtual table pointer at front of object layout
-Vv Use 'slow' virtual base pointers
-Vw Emit native code instead of Unicode for multi-byte character
-Vx Zero-length empty class member functions
Default Settings
BCC32.EXE has specific options that are on by default. To turn off a default option or to override options in a configuration file,
follow the option with a minus (-) sign.
Files with the .CPP extension compile as C++ files. Files with a .C extension, with no extension, or with extensions other than 3
.CPP, .OBJ, .LIB, or .ASM compile as C files.
The compiler tries to link with a module-definition file with the same name as the executable, and extension .DEF.
161
Command Line Utilities RAD Studio 3.1 C++ Reference
-e Specify Link file using <filename> as the name of the executable file. If you do not specify an executable
<filename> executable name with this option, the linker creates an executable file based on the name of the first source
filename file or object file listed in the command.
-l <x> Pass option to Use this command-line option to pass option(s) <x> to the linker from a compile command. Use
linker. the command-line option -l-x to disable a specific linker option.
-M Create a MAP Use this compiler option to instruct the linker to create a map file.
file
-o Compike Compiles the specified source file to <filename>.OBJ
<filename> .OBJ to
<filename>
-P C++ compile Causes the compiler to compile all source files as C++ files, regardless of their extension. Use -P-
to compile all .CPP files as C++ source files and all other files as C source files.
The command-line option -Pext causes the compiler to compile all source files as C++ files and it
changes the default extension to whatever you specify with ext. This option is provided because
some programmers use different extensions as their default extension for C++ code.
The option -P-ext compiles files based on their extension (.CPP compiles to C++, all other
extensions compile to C) and sets the default extension (other than .CPP).
-tWM Generate a Creates a multi-threaded .EXE or .DLL. This option is not needed if you include a module
multi-threaded definition file (.DEF file) in your compile and link commands which specify the type of 32-bit
target application you intend to build.
• If you duplicate any option (except for the options -D, -I, -L, or -U), the last option typed overrides any earlier one.
• Options typed at the command line override configuration and response file options except for the -D, -I, -L, and -U options,
which are cumulative.
• You can stack multiple entries with a single -L or -I option by using a semicolon: BCC32.EXE —L
dirname1;dirname2;dirname3 —I include1;include2;include3 myfile.c
• You can place more than one of each option on the command line, like this: BCC32.EXE —L dirname1 —L dirname2 —L
dirname3 —I include1 —I include2 —I include3 myfile.c
• You can mix styles: BCC32.EXE —L dirname1;dirname2 —Ldirname3 —I include1;include2 —I include3
162
3.1 C++ Reference RAD Studio Command Line Utilities
myfile.c
If you list multiple -L or -I options on the command line, the result is cumulative. The compiler searches all the directories listed,
in order from left to right.
Whenever you issue a compile command, BCC32.EXE searches for a configuration file called BCC32.CFG. The compiler looks
for the .CFG file first in the directory where you issue the compile command, then in the directory where the compiler is located.
You can create and use multiple configuration files in addition to using the default .CFG file.
To use a configuration file, use the following syntax where you would place the compiler options:
+[path]filename
For example, you could use the following command line to use a configuration file called MYCONFIG.CFG:
BCC32 +C:\MYPROJ\MYCONFIG.CFG mycode.cpp
Options typed on the command line override settings stored in configuration files except for the prepended options -D, -I, -L, and
-U.
Options typed at the command line override any option or file name in a response file except for -D, -I, -L, and -U, which are
prepended.
See Also
Using Include Files ( see page 182)
163
Command Line Utilities RAD Studio 3.1 C++ Reference
Option Description
-d<name> Defines a symbol you can test with the #IFDEF preprocessor directive.
[=string]
-fo<filename> Renames the .RES file.
-fe<filename> Renames the .EXE file.
-i<path> Adds one or more directories (separated by semicolons) to the include search path.
-k Disables the contiguous preload of segments and resources in the .EXE file. Segments are kept in the order in
which they appear in the .DEF file. (This option only applies to 16-bit resources and is disabled when the -r
option is in effect.)
-r Creates a .RES file only. The compiled .RES file is not added to the .EXE.
-v Prints progress messages (verbose listing).
-x Directs the compiler to ignore the INCLUDE environment variable when it searches for include or resource files.
-16 Builds 16–bit .RES files.
-32 Builds 32–bit .RES files.
-Vd.d Makes the .EXE file with Windows version provided (v3.1 is the default for 16-bit resources; -v4.0 is the default
for 32-bit resources). Version options are listed in the following table.
Option Description
-t Creates an application that runs only in protected mode (Windows Standard or 386 Enhanced mode).
-31 Builds Windows 3.1-compatible .RES files.
-w32 Builds Win32-compatible .RES files.
3
Resource Shell Examples
The following statement compiles the .RC file, creates a .RES file, and adds the .RES file to the executable file:
brc32 <filename>.RC <filename>.EXE
BRC32 automatically seeks an .EXE file with the same name as the .RC file. You need to specify the .EXE file only if its name is
different from that of the .RC file.
164
3.1 C++ Reference RAD Studio Command Line Utilities
The following statement creates a .RES file, but not an .EXE file. If you name an .EXE file in the command line, BRC ignores it:
brc32 -r <filename>.EXE
The following statement adds an existing .RES file to an executable file. The .EXE file name is required only if it differs from the
.RES file name:
brc32 <filename>.RES <filename>.EXE
This example uses BRC32 to build a 16-bit Windows 3.1 compatible .RES file:
brc32 -16 -v3.1 -fo<filename>.RES <filename>.RC
See Also
RLINK32.DLL ( see page 204)
RAD Studio provides a choice in resource compilers. You can choose to use either BRCC32 or RC (the Microsoft SDK resource
compiler) on the Project Options Resource Compiler dialog box.
Option Description
@<responsefile> Takes instructions from the specified command file.
-c <codepage> Uses the specified code page for resource translation. If -c is not used, the default ANSI code page is
used.
-d<name>[=<string>] Defines a preprocessor symbol.
-fo<filename> Renames the output .RES file. (By default, BRCC32 creates the output .RES file with the same name
as the input .RC file.)
-i<path> Adds one or more directories (separated by semicolons) to the include search path.
-l<language> Specifies default language. 3
-m Indicates that the code page specified with the -c switch contains double-byte character set (DBCS)
characters.
-r This switch is ignored. It is included for compatibility with other resource compilers.
-v Prints progress messages (verbose).
-x Deletes the current include path.
-h or ? Displays help.
165
Command Line Utilities RAD Studio 3.1 C++ Reference
BRCC32 predefines common resource-related Windows constants such as WS_VISIBLE and BS_PUSHBUTTON. Also, two
special compiler-related symbols are defined: RC_INVOKED and WORKSHOP_INVOKED. These symbols can be used in the
source text in conjunction with conditional preprocessor statements to control compilation.
Option Description
-16 Builds 16–bit .RES files.
-32 Builds 32–bit .RES files.
-31 Builds Windows 3.1–compatible .RES files.
-w32 Builds Win32–compatible .RES files.
See Also
BRC32.EXE ( see page 163)
COFF2OMF converts the publicly exported symbols in the COFF import library into a corresponding set of symbols in the OMF
import library. COFF2OMF enables C++Builder users to link to Microsoft and other third-party DLLs that use the COFF format.
COFF2OMF does not convert .OBJ files.
Run the COFF2OMF tool on a COFF import library created for a specific DLL, and use the resulting import library to link OMF
format EXEs and DLLs to the COFF DLL.
3 Command Description
Line
Option
-q Quiet mode. Converts without writing tool and copyright information to standard output.
-v Dumps selected symbols. Dumps the converted symbols to standard output, which can be redirected to an output
file.
-h or -? Displays help.
166
3.1 C++ Reference RAD Studio Command Line Utilities
-r Removes (deletes) output file if empty. Deletes the output file if there is an error and the conversion results in an
empty file.
-lib:xx Specifies options for OMF import library generation. The xx options can be:
• ms — Allow entries that have MS C++ name mangling. The default is No.
• st — Normalize names instead of aliasing MS stdcall mangling.
• ca — Don't perform MS cdecl aliasing. Default is to alias.
Often, when the compiler reports an error inside a macro or an include file, you can get more information about what the error is
if you can see the include files or the results of the macro expansions. In many multi-pass compilers, a separate pass performs
this work, and the results of the pass can be examined. Because the CodeGear C++ compiler is a single-pass compiler, use
CPP32 to get the first-pass functionality found
For each file processed by CPP32, the output is written to a file in the current directory (or the output directory named by the -n
option) with the same name as the source name but with an extension of .I.
This output file is a text file containing each line of the source file and any include files. Any preprocessing directive lines have
been removed, along with any conditional text lines excluded from the compile. Unless you use a command-line option to specify
otherwise, text lines are prefixed with the file name and line number of the source or include file the line came from. Within a text
line, any macros are replaced with their expansion text. Use the -Sr option to produce a file which doesn't have line numbers.
You can then pass this file to the compiler (use the -P compiler option to force a C++ compile).
CPP32 recognizes all the same options that BCC32 does, except for the following additions for the -S option (Control
preprocessed output format):
Option Description
-Sc Keep comments in preprocessed file.
-Sd Keep defines in preprocessed file.
-Sk Keep output on errors.
-Sr Make output readable by preserving comments and indentations
3
-Ss Show statistics of file names and line counts.
167
Command Line Utilities RAD Studio 3.1 C++ Reference
/* HELLOFP.C 2: */
/* HELLOFP.C 3: */
/* HELLOFP.C 4: */
/* HELLOFP.C 5: */main()
/* HELLOFP.C 7: */}
/* HELLOFP.C 8: */}
Option Description
-<cpp_cmd> Tells MIDL which preprocessor to use when processing an .IDL or .ACF file. MIDL calls the
{<CPP32>} preprocessor to expand macros within source files.
-<cpp_opt> Specifies the command line options for the preprocessor. The -Sr option removes line number and file
"{<options>}" name information from each line of the preprocessed output. The -oCON option indicates that
preprocessed output should go to standard output, instead of to file. The preprocessor banner and the
current file that is being processed are not emitted. Including -oCON within a .CFG file processed by
the preprocessor causes the banner to be emitted.
{<CPP32 options>} Passes the options to CPP32.
{<MIDL options>} Any MIDL command-line options.
{<.idl/.acf file> The source file that MIDL processes.
168
3.1 C++ Reference RAD Studio Command Line Utilities
file>}
See Also
BCC32.EXE ( see page 159)
169
Command Line Utilities RAD Studio 3.1 C++ Reference
You can also use -JL on the .dpk file containing the .pas file.
Using GREP
Here is a quick example of a situation where you might want to use GREP. Suppose you wanted to find out which text files in
your current directory contained the string "Bob". You would type:
grep Bob *.txt
GREP responds with a list of the lines in each file (if any) that contained the string "Bob". Because GREP does not ignore case
3 by default, the strings "bob" and "boB" do not match.
GREP can do a lot more than match a single, fixed string. You can make GREP search for any string that matches a particular
pattern. (See GREP: The search string.)
170
3.1 C++ Reference RAD Studio Command Line Utilities
To display a list of the GREP command line options, special characters, and defaults for GREP, enter:
grep ?
GREP Command Line Options
Option Description
<options> Consists of one or more letters, preceded by a hyphen (-), that changes the behavior of GREP.
<searchstring> Gives the pattern to search for.
<file(s)> Tells GREP which files to search. (If you do not specify a file, GREP searches standard input; this lets you use
pipes and redirection.)
Files can be an explicit file name or a generic file name incorporating the DOS ? and * wildcards. In addition,
you can type a path (drive and directory information). If you list files without a path, GREP searches the
current directory. If you do not specify any files, input to GREP must come from redirection (<) or a vertical bar
(|).
Option Description
-c Count only: Prints only a count of matching lines. For each file that contains at least one matching line, GREP prints
the file name and a count of the number of matching lines. Matching lines are not printed. This option is off by
default.
-d Search subdirectories: For each file specified on the command line, GREP searches for all files that match the file
specification, both in the directory specified and in all subdirectories below the specified directory. If you give a file
without a path, GREP assumes the files are in the current directory. This option is off by default.
-e Search expression follows: Indicates that the next argument is the search expression. This option is useful when
you want to search for an expression that begins with "-".
-i Ignore case: GREP ignores upper/lowercase differences. When this option is on, GREP treats all letters a to z as
3
identical to the corresponding letters A to Z in all situations. This option is off by default.
-l List file names only: Prints only the name of each file containing a match. After GREP finds a match, it prints the file
name and processing immediately moves on to the next file. This option is off by default.
-n Line numbers: Each matching line that GREP prints is preceded by its line number. This option is off by default.
171
Command Line Utilities RAD Studio 3.1 C++ Reference
-o UNIX output format: Changes the output format of matching lines to support more easily the UNIX style of
command-line piping. All lines of output are preceded by the name of the file that contained the matching line. This
option is off by default.
-r Regular expression search: The text defined by searchstring is treated as a regular expression instead of as a
literal string. This option is on by default. A regular expression is one or more occurrences of one or more
characters optionally enclosed in quotes. The following symbols are treated specially:
• ^ start of line
• . any character
• * match zero or more chatacteres
• [aeiou0-9] match a, e, i, o, u, and 0-9
• [^aeiou0-9] match all but a, e, i, o, u, and 0-9
• $ end of line
• \ quote next character
• + match one or more
-u < Update options: Creates a copy of GREP.EXE called <filename>.EXE. Any options included on the command line
filename> are saved as defaults in the new copy of GREP. Use the -u option to customize the default option settings. To verify
that the defaults have been set correctly, type filename ?; each option on the help screen is followed by a + or - to
indicate its default setting.
-v Nonmatch: Prints only nonmatching lines. Only lines that do not contain the search string are considered
nonmatching lines. This option is off by default.
-w Word search: Text found that matches the regular expression is considered a match only if the character
immediately preceding and following cannot be part of a word. The default word character set includes A to Z, 0 to
9, and the underscore ( _ ). This option is off by default. An alternate form of this option lets you specify the set of
legal word characters. Its form is -w[set], where set is any valid regular expression.
If you define the set with alphabetic characters, it is automatically defined to contain both the uppercase and
lowercase values for each letter in the set (regardless of how it is typed), even if the search is case-sensitive. If you
use the -w option in combination with the -u option, the new set of legal characters is saved as the default set.
-z Verbose: GREP prints the file name of every file searched. Each matching line is preceded by its line number. A
count of matching lines in each file is given, even if the count is zero. This option is off by default.
? Displays a help screen showing the options, special characters, and defaults for GREP.
• In a regular expression, certain characters have special meanings: They are operators that govern the search. (A regular
expression is either a single character or a set of characters enclosed in brackets. A concatenation of regular expressions is a
regular expression.)
3 • In a literal string, there are no operators: Each character is treated literally.
You can enclose the search string in quotation marks to prevent spaces and tabs from being treated as delimiters. To search for
an expression that begins with "-", use the -e option. The text matched by the search string cannot cross line boundaries; that
is, all the text necessary to match the pattern must be on a single line.
When you use the -r option (on by default), the search string is treated as a regular expression (not a literal expression).
The following characters have special meanings:
172
3.1 C++ Reference RAD Studio Command Line Utilities
Symbol Description
^ A circumflex at the start of the expression matches the start of a line.
$ A dollar sign at the end of the expression matches the end of a line.
. A period matches any character.
* An asterisk after a character matches any number of occurrences of that character followed by any characters,
including zero characters. For example, bo* matches bot, boo, as well as bo.
+ A plus sign after a character matches any number of occurrences of that character followed by any characters, except
zero characters. For example, bo+ matches bot and boo, but not b, bo, or bt.
{} Characters or expressions in braces are grouped so that the evaluation of a search pattern can be controlled and so
grouped text can be referred to by number.
[] Characters in brackets match any one character that appears in the brackets, but no others. For example [bot]
matches b, o, or t.
[^] A circumflex at the start of the string in brackets means NOT. Hence, [^bot] matches any characters except b, o, or t.
[-] A hyphen within the brackets signifies a range of characters. For example, [b-o] matches any character from b
through o..
\ A backslash before a wildcard character tells GREP to treat that character literally, not as a wildcard. For example, \^
matches ^ and does not look for the start of a line.
Four of the "special" characters ($, ., *, and +) do not have any special meaning when used within a bracketed set. In addition,
the character ^ is only treated specially if it immediately follows the beginning of the set definition (immediately after the [
delimiter).
GREP Examples
Example 1
grep -r "[^a-z]main\ *\(" *.c
Matches:
main(i,j:integer)
if (main ()) halt;
if (MAIN ()) halt;
Does Not Match:
mymain()
Explanation: The search string tells GREP to search for the word main with no preceding lowercase letters ([^a-z]), followed by
zero or more occurrences of blank spaces (\ *), then a left parenthesis. Since spaces and tabs are normally considered
command-line delimiters, you must quote them if you want to include them as part of a regular expression.
Example 2
grep -ri [a-c]:\\data\.fil *.c *.inc
Matches:
A:\data.fil 3
B:\DATA.FIL
c:\Data.Fil
Does Not Match:
d:\data.fil a:data.fil
Explanation: Because the backslash (\) and period (.) characters usually have special meaning in path and file names, you must
place the backslash escape character immediately in front of them if you want to search for them. The -i option is used here, so
the search is not case sensitive.
173
Command Line Utilities RAD Studio 3.1 C++ Reference
Example 3l
grep "search string with spaces" *.doc *.c
Matches:
A search string with spaces in it.
Does not match
This search string has spaces in it.
Explanation: This is an example of how to search for a string containing specific text.
Example 4
grep -rd "[ ,.:?'\"]"$ \*.doc
Matches:
He said hi to me.
Where are you going?
In anticipation of a unique situation,
Examples include the following:
"Many men smoke, but fu man chu."Explanation
Does not match:
He said "Hi" to me
Where are you going? I'm headed to the
Explanation: This example searches for any one of the characters " . : ? ' and , at the end of a line. The double quote within the
range is preceded by an escape character so it is treated as a normal character instead of as the ending quote for the string.
Also, the $ character appears outside of the quoted string. This demonstrates how regular expressions can be concatenated to
form a longer expression.
Example 5
grep -w[=] = *.c
Matches:
i = 5;
j=5;
i += j;
Does not match:
if (i == t) j++;
/* ==================================== */
This example redefines the current set of legal characters for a word as the assignment operator (=) only, then does a word
search. It matches C assignment statements, which use a single equal sign (=), but not equality tests, which use a double equal
sign (==).
See Also
BCC32.EXE ( see page 159)
3
3.1.1.8 ILINK32.EXE, the Incremental Linker
ILINK32 links object modules (.OBJ files), library modules (.LIB files), and resources to produce executable files (.EXE, .DLL,
and .BPL files). ILINK32 creates and maintains a series of state files that contains this information. These state files allow
subsequent links to be incremental, greatly reducing the total link time.
174
3.1 C++ Reference RAD Studio Command Line Utilities
The linker can also use a configuration file called ILINK32.CFG for options that you'd typically type at the command-line.
Element Description
[@<respfile>] A response file is an ASCII file that lists linker options and file names that you would normally type at the
command line. By placing options and file names in a response file, you can save the amount of keystrokes you
need to type to link your application.
<options> Linker options that control how the linker works. For example, options specify whether to produce an .EXE,
.BPL, or .DLL file. Linker options must be preceded by either a slash (/) or a hyphen (-).
<startup> A CodeGear initialization module for executables or DLLs that arranges the order of the various segments of
the program. Failure to link in the correct initialization module usually results in a long list of error messages
telling you that certain identifiers are unresolved, or that no stack has been created.
<myobjs> The .OBJ files you want linked. Specify the path if the files aren't in the current directory. (The linker appends an
.OBJ extensions if no extension is present.)
<exe> The name you want given to the executable file (.EXE, .BPL, or .DLL). If you don't specify an executable file
name, ILINK32 derives the name of the executable by appending .EXE, .BPL, or .DLL to the first object file
name listed. (The linker assumes or appends an .EXE extensions for executable files if no extension is present.
It also appends a .DLL extension for dynamic link libraries if no extension is present. Similarly, the linker
appends a .BPL extension for package files if no extension is present.)
<mapfile> The name you want given to the map file. If you don't specify a name, the map file name is the same as the
.EXE file (but with the .MAP extension). (The linker appends a .MAP extension if you do not specify an
extension.)
<libraries> The library files you want included at link time. Do not use commas to separate the libraries listed. If a file is not
in the current directory or the search path (see the /L option) then you must include the path in the link
statement. (The linker appends a .LIB extension if no extension is present.)
The order in which you list the libraries is very important; be sure to use the order defined in this list:
1. Code Guard libraries (if needed)
2. Any of your own user libraries (note that if a function is defined more than once, the linker uses the first
definition encountered)
3. IMPORT32.LIB (if you are creating an executable that uses the Windows API)
4. Math libraries
5. Runtime libraries
<deffile> The module definition file for a Windows executable. If you don't specify a module definition (.DEF) file and you
have used the /Twd or /Twe option, the linker creates an application based on default settings. (The linker
appends a .DEF extension if no extension is present.) 3
<resfile> A list of .RES files (compiled resource files) to bind to the executable. (The linker appends an .RES extension if
no extension is present.)
Linker Options
175
Command Line Utilities RAD Studio 3.1 C++ Reference
Option Description
@xxxx Uses the response file xxxx.
/A:dd Specifies file alignment (backward compatibility switch, use /Af).
/Af:nnnn Specifies file alignment; set nnnn in hex or decimal. nnnn must be a power of 2. Default is 0x200 =
512 byte boundaries.
/Ao:nnnn Specifies object alignment; set nnnn in hex or decimal. nnnn must be a power of 2. Default is
0x1000 = 4096 byte boundaries.
/aa Builds a 32-bit Windows application.
/ad Builds a 32-bit Windows device driver.
/ap Builds a 32-bit Windows console application.
/B:xxxx Specifies the image base address and removes the relocation table.
/b:xxxx Specifies the image base address, and preserves DLL relocation table. Successive objects are
aligned on 64K linear address boundaries. Improves load-time and runtime
performance.Recommended for producing DLLs. Default is Off.
/C Refreshes the linker state files. Erases all linker state files before each link; then recreates the files
and continues with the link.
/c Treats case as significant in public and external symbols. Default is On.
/d Delay-loads a DLL. The specified DLL is not loaded or initialized until an entrypoint in the DLL is
actually called.
/D:xxxx Saves the specified description in the PE image.
/Enn Specifies the max. number of errors.
/GC Inserts a comment string ino the image directly after the object table in the PE file header. You can
specify more than one string. Default is Off.
/GD Generates a Delphi compatible RC file (DRC file). Default is Off.
/GF:xxxx Sets image flags.
The xxxx flags are:
• -GF SWAPNET copies the image to a local swap file and runts it from there if the image resides
on a network drive.
• -GF SWAPCD copies the image to a local swap file and runs it if the image resides on
removable media (CD, zip drive).
• -GF UNIPROCESSOR prevents the application from running on a multiprocessor system.
• -GF LARGEADDRESSAWARE tells the OS that the application understands addresses larger
than 4G.
• -GF AGGRESSIVE aggressively trims the workingg seet of an application when the application
is idel (suited for screen savers and other processes that you want to stay out of the way of
main line processes).
176
3.1 C++ Reference RAD Studio Command Line Utilities
/Gs:string=[EICRWSDKP] Set section flags. Adds the specified flag(s) to the existing flags for a given section, but cannot
remove default flags from a section.
Section flags are:
E = Executable
C = Contains code
I = Contains initialized data
R = Section is readable
W = Section is writable
S = Section is shared
D = Section is discardable
K = Section must not be cached
P = Section must not be paged
Example -GS:.rsrc=W This switch makes the RSRC section writable.
/Gz Calculate checksum of target and insert result in PE header. Used for NT Kernel mode drivers and
system DLLs. Default is Off.
/H:xxxx Specifies application heap reserve size in hex or decimal. Minimum value is 0. This switch
overrides the HEAPSIZE sestting in a module definition file. Default is 1 MB (0x1000000).
/HC:nnnn Specifies application heap commit size.
/I Specifies the directory for intermediate output files. Directs linker state files, but the MAP file and
TDS files are saved in the same directory as the output image, unless otherwise specified for the
MAP file.
/j Specifies object search paths.
Example ILINK32 /jc:\myobjs;.\objs splash .\common\logo,,,utils logolib This command directs the
linker to first search the current directory for SPLASH.OBJ. If the file is not found in the current
directory, the linker then searches the C:\MYOBJS directory, and then the .\OBJs directory.
However, the linker does not use the object search paths to find the file LOGO.OBJ because an
explicit path was given for this file.
/L Specifies the library search path to use if no explicit path is given for the LIB file and the linker
cannot find the LIB file in the current directory.
Example ILINK32 /Lc:\mylibs;.\libs splash .\common\logo,,,utils logolib directs the linker to first
search the current directory for SPLASH.LIB. If the file is not found in the current directory, the
linker then searches the C:\MYLIBS directory, and then the .\LIBs directory. However, the linker
does not use the library search paths to find the file LOGO.LIB because an explicit path was given
for this file.
/M Prints the mangled C++ identifiers in the map file, not the full name.
/m The segments listing has a line for each segment, showing the segment starting address, segment
length, segment name, and the segment class. The public symbols are broken down into two lists,
the first showing the symbols in sorted alphabetically, the second showing the symbols in
increasing address order. Symbols with absolute addresses are tagged Abs. A list of public
symbols is useful when debugging.:Many debuggers use public symbols, which lets you refer to
symbolic addresses while debugging.
/q Suppresses command line banner.
/r Verbose linking. Default is Off. 3
/Rr Replaces resources.
/S:xxxx Specifies application stack reserve size.
/Sc:xxxx Specifies application stack commit size.
/s Produces a detailed map file of segments.
/Tpd Targets a 32-bit Windows DLL file.
177
Command Line Utilities RAD Studio 3.1 C++ Reference
Response files are ASCII files that list linker options and file names that you would normally type at the command line. Response
files allow you longer command lines than most operating systems support, plus you don't have to continually type the same
information. Response files can include the same information as configuration files, but they also support the inclusion of file
names.
Unlike the command line, a response file can be several lines long. To specify an added line, end a line with a plus character (+)
and continue the command on the next line. Note that if a line ends with an option that uses the plus to turn it on (such as /v+),
the + is not treated as a line continuation character (to continue the line, use /v+ +).
If you separate command-line components (such as .OBJ files from .LIB files) by lines in a response file, you must leave out the
comma used to separate them on the command line.
For example:
/c c0ws+
myprog,myexe +
mymap +
mylib cws
leaves out the commas you'd have to type if you put the information on the command line:
ILINK32 /c c0ws myprog,myexe,mymap,mylib cws
To use response files:
3
1. Type the command-line options and file names into an ASCII text file and save the file. Response files typically have an .RSP
extension.
2. Type: ILINK32 @[<path>]<RESFILE.RSP> where <RESFILE.RSP> is the name of your response file.
You can specify more than one responses file, as follows:
ilink32 /c @listobjs.rsp,myexe,mymap,@listlibs.rsp
Note: You can add comments to response files using semicolons; the linker ignores any text on a line that follows a semicolon.
178
3.1 C++ Reference RAD Studio Command Line Utilities
If you delete the EXETYPE statement, the linker can determine what kind of executable you want to produce from the options
you supply on the command line.
You can include an import library to substitute for the IMPORTS section of the module definition.
You can use the __declspec(dllexport) or _export keywords in the definitions of export functions in your C and C++ source code
to remove the need for an EXPORTS section. Note, however, that if __declspec(dllexport) or _export is used to export a
function, that function is exported by name rather than by ordinal. Please also note that __declspec(dllexport) is the preferred
method of export
Linker-State Files
The four linker-state files have file names of <Project>.IL?, where <Project> is taken from the name of the project .BPR file, and
the character in place of the question mark (?) identifies each of the four individual linker-state files.
See Also
RLINK32.EXE ( see page 204)
IMPDEF takes as input a DLL name, and produces as output a module definition file with an EXPORTS section containing the
names of functions exported by the DLL.
179
Command Line Utilities RAD Studio 3.1 C++ Reference
Option Description
-a Adds '_' alias for cdecl functions for compatibility with Microsoft libraries
-h Emits hints
For example:
IMPDEF DestName.DEF SourceName.DLL
This creates a module definition file named DestName.DEF from the file SourceName.DLL. The resulting module definition file
would look something like this:
LIBRARY <FileName>
DESCRIPTION '<Description>'
EXPORTS
<ExportFuncName> @<Ordinal>
.
.
.
<ExportFuncName> @<Ordinal>
• <FileName> is the root file name of the DLL.
• '<Description>' is the value of the DESCRIPTION statement if the DLL was previously linked with a module definition file that
included a DESCRIPTION statement.
• <ExportFuncName> names an exported function.
• <Ordinal> is that function's ordinal value (an integer).
Classes in a DLL
IMPDEF is useful for a DLL that uses C++ classes. If you use the __declspec (or _export) keyword when defining a class, all of
the non-inline member functions and static data members for that class are exported. It's easier to let IMPDEF make a module
definition file for you because it lists all the exported functions, and automatically includes the member functions and static data
members.
Since the names of these functions are mangled, it would be tedious to list them all in the EXPORTS section of a module
definition file simply to create an import library from the module definition file. If you use IMPDEF to create the module definition
file, it will include the ordinal value for each exported function. If the exported name is mangled, IMPDEF will also include that
function's unmangled, original name as a comment following the function entry. So, for instance:
LIBRARY <FileName>
DESCRIPTION '<Description>'
EXPORTS
<MangledExportFuncName> @<Ordinal> ; <ExportFuncName>
.
.
.
<MangledExportFuncName> @<Ordinal> ; <ExportFuncName>
3
• <FileName> is the root file name of the DLL.
• '<Description>' is the value of the DESCRIPTION statement if the DLL was previously linked with a module definition file that
included a DESCRIPTION statement.
• <MangledExportFuncName> provides the mangled name.
• <Ordinal> is that function's ordinal value (an integer).
• <ExportFuncName> gives the function's original name.
180
3.1 C++ Reference RAD Studio Command Line Utilities
Functions in a DLL
IMPDEF creates an editable source file that lists all the exported functions in the DLL. You can edit this .DEF file to contain only
those functions that you want to make available to a particular application, then run IMPLIB on the edited .DEF file. This results
in an import library that contains import information for a specific subset of a DLL's export functions.
Suppose you're distributing a DLL that provides functions to be used by several applications. Every export function in the DLL is
defined with __declspec (or _export). Now, if all the applications used all the DLL's exports, then you could use IMPLIB to make
one import library for the DLL. You could deliver that import library with the DLL, and it would provide import information for all of
the DLL's exports. The import library could be linked to any application, thus eliminating the need for the particular application to
list every DLL function it uses in the IMPORTS section of its module definition file.
But suppose you want to give only a few of the DLL's exports to a particular application. Ideally, you want a customized import
library to be linked to that application--an import library that provides import information only for the subset of functions that the
application will use. All of the other export functions in the DLL will be hidden to that client application.
To create an import library that satisfies these conditions, run IMPDEF on the compiled and linked DLL. IMPDEF produces a
module definition file that contains an EXPORT section listing all of the DLL's export functions. You can edit that module
definition file, remove the EXPORTS section entries for those functions you don't want in the customized import library, and then
run IMPLIB on the module definition file. The result will be an import library that contains import information for only those export
functions listed in the EXPORTS section of the module definition file.
See Also
ILINK32.EXE ( see page 174)
If you've created a Windows application, you've already used IMPORT32.LIB, the import library for the standard Windows DLLs.
IMPORT32.LIB is linked automatically when you build a Win32 application in the C++Builder IDE and when using BCC32 at the
command line.
An import library lists some or all of the exported functions for one or more DLLs. IMPLIB creates an import library directly from
DLLs or from module definition files for DLLs (or a combination of the two).
181
Command Line Utilities RAD Studio 3.1 C++ Reference
<options> An optional list of one or more of the following IMPLIB command options:
• -a Adds '_' alias for cdecl functions for compatibility with Microsoft libraries. If the identifier already
begins with an underscore (_), it is skipped (unless you use the -aa option).
• -aa Forces the creation of an '_' alias for cdecl functions for compatibility with Microsoft libraries. If the
identifier begins with an underscore (_), the -aa option adds a second underscore.
• -c Emits warning on case sensitive symbols.
• -f Forces imports by name.
• -w Emits no warnings.
Example
Note: A DLL can also have an extension of .EXE or .DRV, not just .DLL.
See Also
IMPDEF.EXE ( see page 179)
• If you specify a path and/or directory with your include statement, the compiler searches only the specified location. For
example, if you have the following statement in your code: #include "c:\C++\include\vcl\vcl.h" the header file
vcl.h must reside in the directory C:\C++\include. In addition, if you use the statement: #include <vcl\vcl.h> and you set
the Include option (-I) to specify the path C:\C++\include, the file vcl.h must reside in C:\C++\include\vcl, and not in
C:\C++include or C:\vcl.
• If you put a #include <somefile> statement in your source code, the compiler searches for "somefile" only in the directories
3 specified with the Include (-I) option.
• If you put a #include "somefile" statement in your code, the compiler will search for "somefile" in the following order:
1. The same directory as the file containing the #include statement.
2. The directories of flies that include (#include) that file.
3. The current directory
4. The directories specified with the include (-I) option
182
3.1 C++ Reference RAD Studio Command Line Utilities
• Implicit libraries: The CodeGear C++ compiler searches for implicit libraries only in the specified library directories; this is
similar to the search algorithm for: #include “somefile” Implicit library files are the ones the compiler automatically links
in and the start-up object file (C0x.OBJ).
• Explicit libraries: Where the compiler searches for explicit (user-specified) libraries depends in part on how you list the
library file name. Explicit library files are ones you list on the command line or in a project file; these are file names with a .LIB
extension.
• If you list an explicit library file name with no drive or directory (such as MYLIB.LIB), the compiler first searches for that library
in the current directory. If the first search is unsuccessful, the compiler looks in the directories specified with the Library (-L)
option. This is similar to the search algorithm for #include "somefile".
• If you list a user-specified library with drive and/or directory information (like this: c:\mystuff\mylib1.lib), the CodeGear C++
compiler searches only in the location you explicitly listed as part of the library path name and not in any specified library
directories.
See Also
BCC32.EXE ( see page 159)
3.1.1.12 MAKE
MAKE.EXE is a command-line utility that helps you manage project compilation and link cycles. MAKE is not inherently tied to
compiling and linking, but is a more generic tool for executing commands based on file dependencies. MAKE helps you quickly
build projects by compiling only the files you have modified since the last compilation. In addition, you can set up rules that
specify how MAKE should deal with the special circumstances in your builds.
MAKE Basics
MAKE uses rules you write along with its default settings to determine how it should compile the files in your project. For
example, you can specify when to build your projects with debug information and to compile your .OBJ files only if the date/time
stamps of a source file is more recent than the .OBJ itself. If you need to force the compilation of a module, use TOUCH.EXE to
modify the time stamp of one of the module’s dependents.
In an ASCII makefile, you write explicit and implicit rules to tell MAKE how to treat the files in your project; MAKE determines if it
should execute a command on a file or set of files using the rules you set up. Although your commands usually tell MAKE to
compile or link a set of files, you can specify nearly any operating system command with MAKE.
You must separate the MAKE command and the options and target arguments with spaces.
When specifying targets, you can use wildcard characters (such as * and ?) to indicate multiple files.
183
Command Line Utilities RAD Studio 3.1 C++ Reference
<target> The name of the target listed in the makefile that you want to build
After loading the makefile, MAKE tries to build only the first explicit target listed in the makefile by checking the time and date of
the dependent files of the first target. If the dependent files are more recent than the target file, MAKE executes the commands
to update the target.
If one of the first target’s dependent files is used as a target elsewhere in the makefile, MAKE checks that target’s dependencies
and builds it before building the first target. This chain reaction is called a linked dependency.
If something during the build process fails, MAKE deletes the target file it was building. Use the precious directive if you want
MAKE to keep the target when a build fails.
You can stop MAKE after issuing the MAKE command by pressing Ctrl+Break or Ctrl+C
About makefiles
A makefile is an ASCII file that contains the set of instructions that MAKE uses to build a certain project. Although MAKE
assumes your makefile is called MAKEFILE or MAKEFILE.MAK, you can specify a different makefile name with the -f option.
MAKE either builds the target(s) you specify with the make command or it builds the first target it finds in the makefile. To build
more than a single target, use a symbolic target in your makefile.
Symbolic Targets
A symbolic target forces MAKE to build multiple targets in a makefile. When you specify a symbolic target, the dependency line
lists all the targets you want to build (a symbolic target basically uses linked dependencies to build more than one target).
For example, the following makefile uses the symbolic target AllFiles to build both FILE1.EXE and FILE2.EXE:
AllFiles: file1.exe file2.exe #Note that AllFiles has no commands file1.exe: file1.obj
3 bcc32 file1.obj file2.exe: file2.obj bcc32 file2.obj
Rules for symbolic targets
184
3.1 C++ Reference RAD Studio Command Line Utilities
BUILTINS.MAK
You can create the optional file BUILTINS.MAK and store in it the standard rules and macros that you want MAKE to use when it
builds the targets in a makefile. To ignore this file when it exists, use the -r MAKE option.
CC = bcc32
RC = brcc32
AS = tasm32
.asm.obj:
$(AS) $(AFLAGS) $&.asm
.c.exe:
$(CC) $(CFLAGS) $&.c
.c.obj:
$(CC) $(CFLAGS) /c $&.c
.cpp.exe:
$(CC) $(CFLAGS) $&.cpp
.cpp.obj:
$(CC) $(CPPFLAGS) /c $&.cpp
.rc.res:
$(RC) $(RFLAGS) /r $&
!if !$d(BCEXAMPLEDIR)
BCEXAMPLEDIR = $(MAKEDIR)\..\EXAMPLES
!endif
MAKE Command Options
You can use command-line options to control the behavior of MAKE. MAKE options are case-sensitive and must be preceded
with either a hyphen (-) or slash (/).
You must separate the MAKE command and the options and target arguments with spaces. When specifying targets, you can
use wildcard characters (such as * and ?) to indicate multiple files. To get command-line help for MAKE, type MAKE -?.
Option Description
-a Checks dependencies of include files and nested include files associated with .OBJ files and updates
the .OBJ if the .h file changed. See also -c.
-B Builds all targets regardless of file dates.
185
Command Line Utilities RAD Studio 3.1 C++ Reference
-c Caches autodependency information, which can improve MAKE speed. Use with -a. Do not use this
option if MAKE modifies include files (which can happen if you use TOUCH in the makefile or if you
create header or include files during the MAKE process).
-D<macro> Defines macro as a single character, causing an expression !ifdef macro written in the makefile to return
true.
-D<macro>=<string> Defines <macro> as <string>. If <string> contains any spaces or tabs, enclose <string> in quotation
marks. The -D is optional.
-d<directory> Specifies the drive and the directory that MAKER (the real mode version of MAKE) uses when it swaps
out of memory. This option must be used with -S. MAKE ignores this option.
-e Ignores a macro if its name is the same as an environment variable. MAKE uses the environment
variable instead of the macro.
-f<filename> Uses <filename> or <fillename>.MAK instead of MAKEFILE (a space after -f is optional).
-h or: -? Help. Displays the MAKE options. Default settings are shown with a trailing plus sign.
-I<directory> Searches for include files in the current directory first, then in the specified directory.
-i Ignores the exit status of all programs run from the makefile and continues the build process.
-K Keeps temporary files that MAKE creates (MAKE typically deletes temporary files).
-m Displays the date and timestamp of each file as MAKE processes it.
-n Prints the MAKE commands but does not perform them. This is helpful for debugging makefiles.
-N Causes MAKE to mimic Microsoft's NMAKE.
-p Displays all macro definitions and implicit rules before executing the makefile.
-q Returns 0 if the target is up-to-date and nonzero if it is not up-to-date (for use with batch files).
-r Ignores any rules defined in BUILTINS.MAK.
-s Suppresses onscreen command display (silent).
-S Swaps MAKER out of memory while commands are executed, reducing memory overhead and allowing
compilation of large modules. MAKE ignores this option.
-U<macro> Undefines the previous macro definition of <macro>.
-W<filename> Writes MAKE to <filename>, updating all non-string options.
See Also
MAKE Macros ( see page 191)
The following table lists the MAKE directives and their corresponding command-line options:
186
3.1 C++ Reference RAD Studio Command Line Utilities
187
Command Line Utilities RAD Studio 3.1 C++ Reference
.keep -K Keeps temporary files that MAKE creates (MAKE usually deletes them).
!message Prints a message to stdout while MAKE runs the makefile
The !message directive lets you send messages to the screen from a makefile. You can use
these messages to help debug a makefile that isn't working properly. For example, if you're
having trouble with a macro definition, you could put this line in your makefile:
!message The macro is defined here as: $(MacroName)
When MAKE interprets this line, it will print onscreen (assuming the macro expands to .CPP):
The macro is defined here as: .CPP
.noautodepend Turns off autodependency checking.
a
.noswap Tells MAKE not to swap iteself out of memory before executing a command.
S
.path.ext Tells MAKE to search for files with the extension .ext in path directories
To tell MAKE to look for files with the .c extension in C:\SOURCE or C:\CFILES and to look
for files with the .obj extension in C:\OBJS:
.path.c = C:\CSOURCE;C:\CFILES .path.obj = C:\OBJS
.precious Saves the target or targets even if the build fails If a MAKE build fails, MAKE deletes the
target file. The .precious directive prevents the file deletion, which you might desire for
certain kinds of targets. For example, if your build fails to add a module to a library, you
might not want the library to be deleted. The syntax for .precious is:
.precious: <target> [<target>...]
.silent -s MAKE executes commands without printing them first.
188
3.1 C++ Reference RAD Studio Command Line Utilities
.suffixes Determines the implicit rule for ambiguous dependencies. The .suffixes directive tells MAKE
the order (by file extensions) for building implicit rules. The syntax of .suffixes is:
.suffixes: .<ext> [.<ext> ...]
where .<ext> represents the dependent file extensions you list in your implicit rules.
For example, you could include the line .suffixes: .asm .c .cpp to tell MAKE to
interpret implicit rules beginning with the ones dependent on .ASM files, then .C files, then
.CPP files, regardless of what order they appear in the makefile.
The following .suffixes example tells MAKE to look for a source file first with an .ASM
extension, next with a .C extension, and finally with a .CPP extension. If MAKE finds
MYPROG.ASM, it builds MYPROG.OBJ from the assembler file by calling TASM. MAKE
then calls ILINK32; otherwise, MAKE searches for MYPROG.C to build the .OBJ file or it
searches for MYPROG.CPP.
.suffixes: .asm .c .cpp
myprog.exe: myprog.obj
bcc32 myprog.obj
.cpp.obj:
bcc32 -P -c $<
.asm.obj:
tasm /mx $
.c.obj:
bcc32 -P- -c $<
.swap -S Tells MAKE to swap itself out of memory before executing a command.
!undef Clears the definition of a macro. After this, the macro is undefined. !undef (undefine) causes
an !ifdef MacroName test to fail. The syntax of the !undef directive is:
!undef MacroName
Null Macros
you can substitute the characters .obj for the characters .cpp by using the following MAKE command:
NULLMACRO =
Either of the following lines can define a null macro on the MAKE command line:.
NULLMACRO =""
-DNULLMACRO 3
!if and Other Conditional Directives
The !if directive works like C if statements. As shown here, the syntax of !if and the other conditional directives resembles
compiler conditionals:
189
Command Line Utilities RAD Studio 3.1 C++ Reference
• One !else directive is allowed between !if, !ifdef, or !ifndef and !endif directives.
• Multiple !elif directives are allowed between !if, !ifdef, or !ifndef, !else and !endif.
• You can't split rules across conditional directives.
• You can nest conditional directives.
• !if, !ifdef, and !ifndef must have matching !endif directives within the same file.
The following information can be included between !if and !endif directives:
• Macro definition
• Explicit rule
• Implicit rule
• Include directive
• !error directive
• !undef directive
In an if statement, a conditional expression consists of decimal, octal, or hexadecimal constants and the operators shown in the
following table:
190
3.1 C++ Reference RAD Studio Command Line Utilities
To use a macro in a makefile, type $(MacroName) where MacroName is a defined macro. You can use either braces or
parentheses to enclose MacroName.
MAKE expands macros at various times depending on where they appear in the makefile:
Element Description
<MacroName> Is case-sensitive (MACRO1 is different from Macro1). Limited to 512 characters.
<expansion_text> Is limited to 4096 characters. Expansion characters may be alphanumeric, punctuation, or spaces.
You must define each macro on a separate line in your makefile and each macro definition must start on the first character of the
line. For readability, macro definitions are usually put at the top of the makefile. If MAKE finds more than one definition of
MacroName, the new definition overwrites the old one.
You can also define macros using the -D command-line option. No spaces are allowed before or after the equal sign (=);
however, you can define more than one macro by separating the definitions with spaces. The following examples show macros
defined at the command line:
make -Dsourcedir=c:\projecta
make -Dcommand="bcc32 -c"
make -Dcommand=bcc32 option=-c
Note: Macros defined in makefiles overwrite macros defined on the command line.
you can substitute the characters .obj for the characters .cpp by using the following MAKE command:
$(SOURCE:.cpp=.obj)
This substitution does not redefine the macro.
• Syntax: $(MacroName:original_text=new_text)
191
Command Line Utilities RAD Studio 3.1 C++ Reference
You can use this to create explicit rules that generate response files for TLIB.EXE. For example:
myfile.lib: file1.obj file2.obj file3.obj
TLIB $@ @&&!
+-$(**: = &^
+-)
!
Here, MAKE substitutes all space characters in the dependency list with a space followed by an ampersand (&) followed by the
new-line character followed by "+-". The resulting response file looks like this:
+-file1.obj &
+-file2.obj &
+-file3.obj &
+-
Default MAKE Macros
MAKE contains several default macros you can use in your makefiles. The following table lists the macro definition and what it
expands to in explicit and implicit rules.
192
3.1 C++ Reference RAD Studio Command Line Utilities
See Also
Using MAKE.EXE ( see page 183)
MAKE supports multiple dependency lines for a single target, and a single target can have multiple command lines. However,
3
only one dependency line should contain a related command line. For example:
Target1: dependent1 dep2 dep3 dep4 dep5
Target1: dep6 dep7 dep8
bcc32 -c $**
Explicit Rule Syntax
Explicit rules specify the instructions that MAKE must follow when it builds specific targets. Explicit rules name one or more
targets followed by one or two colons. One colon means one rule is written for the target(s); two colons mean that two or more
193
Command Line Utilities RAD Studio 3.1 C++ Reference
Element Description
<target> Specifies the name and extension of the file to be built (a target must begin a line in the makefile -- you cannot
precede the target name with spaces or tabs). To specify more than one target, separate the target names with
spaces or tabs. Also, you cannot use a target name more than once in the target position of an explicit rule.
<path> Is a list of directories that tells MAKE where to find the dependent files. Separate multiple directories with
semicolons and enclosed the entire path specification in braces.
<dependent> Is the file (or files) whose date and time MAKE checks to see if it is newer than target. Each dependent file must
be preceded by a space. If a dependent appears elsewhere in the makefile as a target,
MAKE updates or creates that target before using the dependent in the original target (this in known as a linked
dependency).
<commands> Are any operating system command or commands. You must indent the command line by at least one space or
tab, otherwise they are interpreted as a target. Separate multiple commands with spaces.
If a dependency or command line continues on the following line, use a backslash (\) at the end of the first line to indicate that
the line continues. For example:
MYSOURCE.EXE: FILE1.OBJ\ #Dependency line
FILE3.OBJ #Dependency line continued
bcc32 file1.obj file3.obj #Command line
The following example shows targets with multiple rules and commands:
.cpp.obj:
bcc32 -c -ncobj $<
.asm.obj:
tasm /mx $<, asmobj\
If implicit dependents are out-of-date with respect to the target, or if the dependents don't exist, MAKE executes the commands
associated with the rule. MAKE updates explicit dependents before it updates implicit dependents.
194
3.1 C++ Reference RAD Studio Command Line Utilities
[{>source_dir>}].<source_ext>[{target_dir}].<target_ext>:
[<commands>]
Element Description
<source_dir> Specifies the directory (or directories) containing the dependent files. Separate multiple directories with a
semicolon.
.<source_ext> Specifies the dependent filename extension.
<target_dir> Specifies the directory where MAKE places the target files. The implicit rule will only be used for targets in
this directory. Without specifying a target directory, targets from any directory will match the implicit rule.
.<target_ext> Specifies the target filename extension. Macros are allowed here.
: (colon) Marks the end of the dependency line.
<commands> Are any operating system command or commands. You must indent the command line by at least one
space or tab; otherwise they are interpreted as a target.
If two implicit rules match a target extension but no dependent exists, MAKE uses the implicit rule whose dependent's extension
appears first in the .SUFFIXES list.
Commands in both implicit and explicit rules can have prefixes that modify how MAKE treats the commands. The following table
lists the prefixes you can use in makefiles:
3
Prefix Description
@ Does not display the command while it's being executed.
-<num> Stops processing commands in the makefile when the exit code returned from command exceeds the integer num.
Normally, MAKE aborts if the exit code is nonzero. No space is allowed between - and <num>.
- Continues processing commands in the makefile, regardless of the exit codes they return.
195
Command Line Utilities RAD Studio 3.1 C++ Reference
& Expands either the macro $**, which represents all dependent files, or the macro $?, which represents all dependent
files stamped later than the target. Execute the command once for each dependent file in the expanded macro.
! Behaves like the & prefix.
Using @
The following command uses the @ prefix, which prevents MAKE from displaying the command onscreen:
diff.exe : diff.obj
@bcc32 diff.obj
Using -<num> and —
The prefixes -<num> and - (hyphen) control the makefile processing when errors occur. You can choose to continue with the
MAKE process if any error occurs, or you can specify a number of errors to tolerate.
The & prefix issues a command once for each dependent file. It is especially useful for commands that don't take a list of files as
parameters. For example:
copyall : file1.cpp file2.cpp
© $** c:\temp
invokes COPY twice, as follows:
copy file1.cpp c:\temp
copy file2.cpp c:\temp
Without the & modifier, MAKE would call COPY only once. Note: the & prefix only works with $** and $! macros.
Operator Description
< Use input from a specified file rather than from standard input.
> Send the output from command to file.
>> Append the output from command to file.
<< Create a temporary inline file and use its contents as standard input to command. Also, create temporary
response file when -N is used. Note: this is only for use with Microsoft's NMAKE.
&& Create a temporary response file and insert its name in the makefile.
<delimiter> Use delimiters with temporary response files. You can use any character other than # as a delimiter. Use << and
3 && as a starting and ending delimiter for a temporary file. Any characters on the same line and immediately
following the starting delimiter are ignored. The closing delimiter must be written on a line by itself.
See Also
Using MAKE.EXE ( see page 183)
196
3.1 C++ Reference RAD Studio Command Line Utilities
• To enable a particular warning message, enter the -w option with a one- to three-letter option code.
• To disable the warning message, enter the -w- option with a one- to three- letter option code.
Examples
To display all warning and error messages, include the -w command option in your BCC32 command:
-w
To enable reporting of the warning "Mixing pointers to different 'char' types" (option code ucp, Default OFF), include the following
flag in your BCC32 command:
-wucp
To disable reporting of the warning "Declaration ignored" (option code dig, Default ON), include the following flag in your BCC32
command:
-w-dig
To display help on the warning message codes, enter a compiler command that contains only the -h and -w options:
bcc32 -h -w
CodeGear C++ 5.92 for Win32 Copyright (c) 1993, 2007 CodeGear
Available options (* = default setting, xxx = has sub-options: use -h -X):
(Note: -X- or -w-XXX will usually undo whatever was set or unset by -X)
-w Display all warnings
-w! Return non-zero from compiler on warnings
-wamb 8000 Ambiguous operators need parentheses
-wamp 8001 Superfluous & with function
* -wasc 8002 Restarting compile using assembly
-wasm 8003 Unknown assembler instruction
* -waus 8004 '%s' is assigned a value that is never used
* -wali 8086 Incorrect use of #pragma alias "aliasName"="substituteName"
* -watr 8100 '%s' attribute directive ignored
-wbbf 8005 Bit fields must be signed or unsigned int
* -wbei 8006 Initializing %s with %s
* -wbig 8007 Hexadecimal value contains too many digits
* -wccc 8008 Condition is always %s
-wcln 8009 Constant is long
* -wcom 8010 Continuation character \ found in // comment
* -wcpt 8011 Nonportable pointer comparison
* -wcsu 8012 Comparing signed and unsigned values
* -wcod 8093 Incorrect use of #pragma codeseg [seg_name] ["seg_class"] [grou
197
Command Line Utilities RAD Studio 3.1 C++ Reference
198
3.1 C++ Reference RAD Studio Command Line Utilities
The module definition file names the .EXE or .DLL, identifies the application type, lists imported and exported functions,
describes the code section and data segment attributes, lets you specify attributes for additional code sections and data
segments, specifies the size of the stack, and provides for the inclusion of a stub program.
CODE Statement
Defines the default attributes of code sections. Code sections can have any name, but must belong to section classes whose
name ends in CODE (such as CODE or MYCODE).
CODE [PRELOAD | LOADONCALL]
[EXECUTEONLY | EXECUTEREAD]
• PRELOAD means code is loaded when the calling program is loaded.
• LOADONCALL (the default) means the code is loaded when called by the program.
• EXECUTEONLY means a code section can only be executed.
• EXECUTEREAD (the default) means the code section can be read and executed.
• FIXED (the default) means the section remains at a fixed memory location.
• MOVEABLE means the sction can be moved.
• DISCARDABLE means the section can be discarded if it is no longer needed (this implies MOVEABLE).
• NONDISCARDABLE (the default) means the section can not be discarded.
DATA Statement
Defines attributes of data segments:
DATA [NONE | SINGLE | MULTIPLE]
[READONLY | READWRITE]
[PRELOAD | LOADONCALL]
[SHARED | NONSHARED]
• NONE means that there is no data section created. This option is available only for libraries.
• SINGLE (the default for .DLLs) means a single data section is created and shared by all processes.
• MULTIPLE (the default for .EXEs) means that a data section is created for each process.
• READONLY means the data section can be read only.
• READWRITE (the default) means the data section can be read and written to.
• PRELOAD means the data section is loaded when a module that uses it is first loaded. 3
• LOADONCALL (the default) means the data section is loaded when it is first accessed. (LOADONCALL is ignored for 32-bit
applications.)
• SHARED means one copy of the data section is shared among all processes.
• NONSHARED (the default for programs .DLLs) means a copy of the data section is loaded for each process needing to use
the data section.
199
Command Line Utilities RAD Studio 3.1 C++ Reference
EXETYPE Statement
Defines the default executable file (.EXE) header type for applications. You can leave this section in for 32-bit applications for
backward compatibility, but if you need to change the EXETYPE, see the NAME statement.
EXETYPE [WINDOWAPI] | [WINDOWCOMPAT]
• WINDOWAPI is a Windows executable, and is equivalent to the ILINK32 option -aa.
• WINDOWCOMPAT is a Windows-compatible character-mode executable, and is equivalent to the ILINK32 option -ap.
EXPORTS Statement
Defines the names and attributes of functions to be exported. The EXPORTS keyword marks the beginning of the definitions. It
can be followed by any number of export definitions, each on a separate line.
EXPORTS
<EsportName> [<Ordinal>]
[RESIDENTNAME] [<Parameter>]
• <ExportName> specifies an ASCII string that defines the symbol to be exported as follows: <EntryName>
[=<InternalName>] <EntryName> is the name listed in the executable file's entry table and is externally visible.
<InternalName> is the name used within the application to refer to this entry.
• <Ordinal> defines the function's ordinal value as follows: @<ordinal> where <ordinal> is an integer value that
specifies the function's ordinal value. When an application or DLL module calls a function exported from a DLL, the calling
module can refer to the function by name or by ordinal value. It is faster to refer to the function by ordinal because string
comparisons aren't required to locate the function. To use less memory, export a function by ordinal (from the point of view of
that function's DLL) and import/call a function by ordinal (from the point of view of the calling module). When a function is
exported by ordinal, the name resides in the nonresident name table. When a function is exported by name, the name resides
in the resident name table. The resident name table for a module is in memory whenever the module is loaded; the
nonresident name table isn't.
• RESIDENTNAME specifies that the function's name must be resident at all times. This is useful only when exporting by
ordinal (when the name wouldn't be resident by default).
• <Parameter> is an optional integer value that specifies the number of words the function expects to be passed as
parameters.
HEAPSIZE Statement
Defines the number of bytes the application needs for its local heap. An application uses the local heap whenever it allocates
local memory.
HEAPSIZE <Reserve>[, <Commit>]
• <Reserve> can be a decimal or hex value, the default of which is 1MB. To help with backward (16-bit) compatibility for 32-bit
ports, the linker uses the default value of 1MB if you specify in the .DEF ile a reserve value less than 64K.
• <Commit> is a decimal or hex value. The commit size is optional, and if not specified defaults to 4K. The minimum commit
3 size you can specify is 0. In addition, the specified or default commit size must always be smaller or equal to the reserve size.
Reserved memory refers to the maximum amount of memory that can be allocated either in physical memory or in the paging
file. In other words, reserved memory specifies the maximum possible heap size. The operating system guarantees that the
specified amount of memory will be reserved and, if necessary, allocated.
The meaning of committed memory varies among operating systems. In Windows NT, commited memory refers to the amount of
physical memory allocated for the heap at application load/initialization time. Committed memory causes space to be
allocated either in physical memory or in the paging file. A higher commit value saves time when the application needs more
heap space, but increases memory requirements and possible startup time.
200
3.1 C++ Reference RAD Studio Command Line Utilities
You can override any heap reserve or commit size specified in the .DEF file with the -H or -Hc ILINK32 command-line options. -H
lets you specify a heap reserve size less than the 64K minimum allowed in the .DEF file.
IMPORTS Statement
Defines the names and attributes of functions to be imported from DLLs. The IMPORTS keyword marks the beginning of the
definitions followed by any number of import definitions, each on a separate line.
IMPORTS [<InternalName>=]<ModuleName>.<Entry>
• <InternalName> is an ASCII string that specifies the unique name the application uses to call the function.
• <ModuleName> specifies one or more uppercase ASCII characters that define the name of the executable module containing
the function. The module name must match the name of the executable file. For example, the file SAMPLE.DLL has the
module name SAMPLE.
• <Entry> specifies the function to be imported--either an ASCII string that names the function or an integer that gives the
function's ordinal value.
Instead of listing imported DLL functions in the IMPORTS statement, you can either specify an import library for the DLL in the
ILINK32 command line, or include the import library for the DLL in the project manager in the IDE.
You must use either __declspec(dllimport) or __import to import any function, class, or data you want imported. The prefered
method is to use __declspec(dllimport)
The IMPORTS keyword can also be applied to (global) variables, as follows:
[ in the dll source file (dll.cpp) ] int sample = 100;
[ app.def ]
IMPORTS
dll._sample
LIBRARY Statement
Defines the name of a DLL module. A module definition file can contain either a LIBRARY statement to indicate a .DLL or a
NAME statement to indicate a .EXE. A library's module name must match the name of the executable file. For example, the
library MYLIB.DLL has the module name MYLIB.
LIBRARY <LibrarName> [INITGLOBAL | INITINSTANCE]
• <LibraryName> (optional) is an ASCII string that defines the name of the library module. If you don't include a LibraryName,
ILINK32 uses the file name with the extension removed. If the module definition file includes neither a NAME nor a LIBRARY
statement, ILINK32 assumes a NAME statement without a ModuleName parameter.
• INITGLOBAL means the library-initialization routine is called.
• INITINSTANCE means the library-initialization routine is called each time a new process uses the library.
NAME Statement
Is the name of the application's executable module. The module name identifies the module when exporting functions. NAME
must appear before EXETYPE. If NAME and EXETYPE don't specify the same target type, the linker uses the type listed with
NAME. 3
NAME <ModuleName> [WINDOWSAPI] | [WINDOWCOMPAT]
• <ModuleName> (optional) specifiesone or more uppercase ASCII characters that name the executable module. The name
must match the name of the executable file. For example, an application with the executable file SAMPLE.EXE has the
module name SAMPLE. If <ModuleName> is missing, ILINK32 assumes that the module name matches the file name of the
executable file. For example, if you do not specify a module name and the executable file is named MYAPP.EXE, ILINK32
assumes that the module name is MYAPP. If the module definition file includes neither a NAME nor a LIBRARY statement,
ILINK32 assumes a NAME statement without a <ModuleName> parameter.
201
Command Line Utilities RAD Studio 3.1 C++ Reference
• WINDOWSAPI specifies a Windows executable, and is equivalent to the ILINK32 option -aa.
• WINDOWCOMPAT specifies a Windows-compatible character-mode executable, and is equivalent to the ILINK32 option -ap.
SECTIONS Statement
Lets you set attributes for one or more section in the image file. you can use this You can use this statement to override the
default attributes for each different type of section.
SECTIONS<section_name> [CLASS '<ClassName>'] <attributes>
• SECTIONS marks the beginning of a list of section definitions.
• After the SECTIONS keyword, each section definition must be listed on a separate line. Note that the SECTIONS keyword
can be on the same line as the first definition or on a preceding line. In addition, the .DEF file can contain one or more
SECTIONS statements. The SEGMENTS keyword is supported as a synonym for SECTIONS.
• <ClassName> is case sensitive. The CLASS keyword is supported for compatibility but is ignored.
• <Attributes> is one or more of the following: EXECUTE, READ, SHARED, and WRITE.
SEGMENTS Statement
Defines the attributes of additional code and data sections. The SEGMENTS keyword is supported as a synonym for
SECTIONS. The syntax is:
SEGMENTS
[<MinAlloc>]
[SHARED | NONSHARED]
[PRELOAD | LOADONCALL]
• <SegmentName> is a character string that names the new segment. It can be any name, including the standard segment
names _TEXT and _DATA, which represent the standard code and data segments.
• <ClassName> (optional) is the class name of the specified segment. If no class name is specified, ILINK32 uses the class
name CODE.
• <MinAlloc> (optional) is an integer that specifies the minimum allocation size for the segment. ILINK32 ignores this value.
• SHARED means one copy of the segment is shared among all processes.
• NONSHARED (the default for .EXEs and .DLLs) means a copy of the segment is loaded for each process needing to use the
data segment.
• PRELOAD means that the segment is loaded immediately.
• LOADONCALL means that the segment is loaded when it is accessed or called (this is ignored by ILINK32). The Resource
Compiler may override the LOADONCALL option and preload segments instead.
STACKSIZE Statement
Defines the number of bytes the application needs for its local stack. An application uses the local stack whenever it makes
function calls.
STACKSIZE <Reserve>[, <Commit>]
• <Reserve> can be a decimal or hex value, the default of which is 1MB. To help with backward (16-bit) compatibility, the linker
3 uses the default value of 1MB if you specify in the .DEF file a reserve value less than 64K.
• <Commit> is a decimal or hex value. The commit size is optional, and if not specified defaults to 8K. The minimum commit
size you can specify is 4K. In addition, the specified or default commit size must always be smaller or equal to the reserve
size.
Reserved memory refers to the maximum amount of memory that can be allocated either in physical memory or in the paging
file. In other words, reserved memory specifies the maximum possible stack size.
The operating system guarantees that the specified amount of memory will be reserved and, if necessary, allocated.
202
3.1 C++ Reference RAD Studio Command Line Utilities
The meaning of committed memory varies among operating systems. In Windows NT, commited memory refers to the amount of
physical memory allocated for the stack at application load/initialization time. Committed memory causes space to be
allocated either in physical memory or in the paging file. A higher commit value saves time when the application needs more
stack space, but increases memory requirements and possible startup time.
You can override any stack reserve or commit size specified in the .DEF file with the ILINK32 -S or -Sc command-line options. -S
lets you specify a stack reserve size less than the 64K minimum allowed in the .DEF file.
Note: Do not use the STACKSIZE statement when compiling .DLLs.
STUB Statement
Appends a DOS executable file specified by FileName to the beginning of the module. The executable stub displays a warning
message and terminates if the user attempts to run the executable stub in the wrong environment (running a Windows
application under DOS, for example).
STUB '<FileName>'
• <FileName> is the name of the DOS executable file to be appended to the module. The name must have the DOS file name
format. If the file named by FileName is not in the current irectory, ILINK32 searches for the file in the directories specified by
the PATH environment variable.
C++Builder adds a built-in stub to the beginning of a Windows application unless a different stub is specified with the STUB
statement. You should not use the STUB statement to include WINSTUB.EXE because the linker does this automatically.
SUBSYSTEM Statement
Lets you specify the Windows subsystem and subsystem version number for the application being linked.
SUBSYSTEM [<subsystem>,]<subsystemID>
• <Subsystem> (optional) can be any one of the following values: WINDOWS, WINDOWAPI, WINDOWCOMPAT. If you do not
specify a subsystem, the linker defaults to a WINDOWS subsystem.
• <SubsystemID> must use the format d.d where d is a decimal number. For example, if you want to specify Windows 4.0, you
could use either one of the following two SUBSYSTEM statements: SUBSYSTEM 4.0 SUBSYSTEM WINDOWS 4.0
You can override any SUBSYSTEM statement in a .DEF file using the -a and -V ILINK32 command-line options.
See Also
ILINK32 ( see page 174)
To use precompiled header files, specify the various -H options in your BCC32 command.
203
Command Line Utilities RAD Studio 3.1 C++ Reference
Do not When you enable this option, the compiler does not generate or use precompiled headers.
H generate or Default = Do not generate or use (-H-)
use
-Hc Cache When you enable this option, the compiler caches the precompiled headers it generates. This
precompiled is useful when you are precompiling more than one header file. To use this option, you must
headers also enable the Generate and Use (-H) precompiled header option. Default = Off.
-He Generate When you enable this option, the compiler generates a file or files that contain debug type
external type information for all the symbols contained in the precompiled headers. The filenames end with
files .#xx extension, where xx is 00 for the first file generated and is incremented for each additional
(precompiled type-information file required. Using this option dramatically decreases the size of your .OBJ
headers) files, because debug type information is centralized and is not duplicated in each .OBJ file.
Default = On.
-H=<filename> Precompiled Use this option to specify the name of your precompiled header file. When you set this option,
header the compiler generates and uses the precompiled header file that you specify.
filename
-Hh=<xxx> or Stop This option terminates compiling the precompiled header after processing the file specified as
-H\”<xxx>\” precompiling xxx. You can use this option to reduce the disk space required for precompiled headers.
after header The -Hh syntax is generally easier to use than the -H syntax. Examples:
file option
-Hh=myhdr.h
-H\"myhdr.h\"
-Hh="C:\Program Files\myhdr.h"
-H\"C:\Program Files\myhdr.h\"
When you use this option, the file you specify must be included from a source file for the
compiler to generate a precompiled header file.
You can also use #pragma hdrstop in your source file to specify when to stop the generation of
precompiled headers.
You cannot specify a header file that is included from another header file. For example, you
cannot list a header included by windows.h because doing this would cause the precompiled
header file to be closed before the compilation of windows.h was completed.
See Also
ILINK32.EXE ( see page 174)
• Links the resources by fixing up string tables and message tables and then binding these linked resources into the
executable.
• Is called by ILINK32 and is used for 32-bit resources.
See Also
3
BRC32.EXE ( see page 163)
204
3.1 C++ Reference RAD Studio Command Line Utilities
TDUMP breaks apart a file structurally and uses the file's extension to determine the output display format. TDUMP recognizes
many file formats, including .EXE, .OBJ, and .LIB files. If TDUMP doesn't recognize an extension, it produces a hexadecimal
dump of the file. You can control the output format by using the TDUMP command-line options when you start the program.
TDUMP's ability to peek at a file's inner structure displays not only a file's contents, but also how a file is constructed. Moreover,
because TDUMP verifies that a file's structure matches its extension, you can also use TDUMP to test file integrity.
• <inputfile> is the file whose structure you want to display (or “dump”).
• <listfile> is an optional output filename (you can also use the standard DOS redirection command (>).
• <options> are any of the TDUMP command line options.
To display command line help, enter:
tdump
You can use either the / or the - switch character. For example, these two commands are equivalent:
TDUMP -e1 -v demo.exe
TDUMP /el /v demo.exe
TDUMP Options
Option Description
-a, -a7 TDUMP automatically adjusts its output display according to the file type. You can force a file to be displayed as ASCII
by including the -a or -a7 option.
-a produces an ASCII file display, which shows the offset and the contents in displayable ASCII characters. A
character that is not displayable (like a control character) appears as a period.
-a7 converts high-ASCII characters to their low-ASCII equivalents. This is useful if the file you are dumping sets
high-ASCII characters as flags (WordStar files do this).
-b# Allows you to display information beginning at a specified offset. For example, if you want a dump of MYFILE starting
from offset 100, you would use: TDUMP -b100 MYFILE
-C Causes TDUMP to dump information found in COFF format files (.OBJ and .LIB). This option is useful when linking
with Microsoft .OBJ and .LIB files.
-d Causes TDUMP to dump any CodeGear 32-bit debug information found in the .OBJ file. If you do not specify this
option, TDUMP displays raw data only.
205
Command Line Utilities RAD Studio 3.1 C++ Reference
-e, -el, All four options force TDUMP to display the file as an executable (.EXE) file.
-er, An .EXE file display consists of information contained within a file that is used by the operating system when loading a
-ex file. If symbolic debugging information is present (Turbo Debugger or Microsoft CodeView), TDUMP displays it.
TDUMP displays information for DOS executable files, NEW style executable files ( Microsoft Windows and OS/2
.EXEs and DLLs ), Linear Executable files, and Portable Executable (PE) files used by Windows NT and Windows
95/98 and Windows 2000.
• -e Displays file as Executable (EXE/DLL, DOS, Win16, OS/2, PE)
• -ea[:v] Displays All Exports unsorted, or (:v) sort by RVA (default dumps only named exports, sorting on the
name) a[:v] Displays All Exports unsorted, or (:v) sort by RVA (default dumps only named exports, sorting on the
name)
• -ed Disables EXE debug information
• -ee[=x] Lists Exports only from EXE/DLL (optional x lists matches only)
• -el Suppresses line numbers in the display
• -eiID Includes only .EXE table ID (HDR, OBJ, FIX, NAM, ENT)
• -em[=x] Lists Imports only from EXE/DLL (optional x lists matches only)
• -em.[x] Lists Imported modules only from EXE/DLL (optional x search string)
• -ep Disables EXE PE header display
• -er Prevents the relocation table from displaying
• -ex Prevents the display of New style executable information. This means TDUMP only displays information for
the DOS "stub" program
-h Displays the dump file in hexadecimal (hex) format. Hex format consists of a column of offset numbers, 16 columns of
hex numbers, and their ASCII equivalents (a period appears where no displayable ASCII character occurs).
If TDUMP doesn't recognize the input file's extension, it displays the file in hex format (unless an option is used to
indicate another format).
-i Specifies the debug table(s) to use.
-l, -li, Displays the output file in library (.LIB) file format. A library file is a collection of object files (see the -o option for more
-le on object files). The library file dump displays library-specific information, object files, and records in the object file.
The -li option tells TDUMP to display a short form of "impdef" records when dumping import libraries. You can also
specify a search string using the following syntax:
-li=<string>
For example, this command:
tdump —li=codeptr import32.lib
results in the following output:
Impdef:(ord) KERNEL32.0336=ISBADCODEPTR
This output shows that the function is exported by ordinal, whose ordinal value is 336 (decimal). In addition, the output
displays the module and function name.
If you enter the following command:
tdump —li=walk import32.lib
3 TDUMP displays:
Impdef:(name) KERNEL32.????=HEAPWALK
This shows the output of a function exported by name.
-le Tells TDUMP to display a short form of the "expdef" records when dumping OBJ files. You can also specify a search
string using the following syntax: -le=<string>
-m Leaves C++ names occurring in object files, executable files, and Turbo Debugger symbolic information files in
"mangled" format. This option is helpful in determining how the C++ compiler "mangles" a given function name and its
arguments.
206
3.1 C++ Reference RAD Studio Command Line Utilities
o, -oc, • -o displays the file as an object (.OBJ) file. An object file display contains descriptions of the command records
-oi, that pass commands and data to the linker, telling it how to create an .EXE file. The display format shows each
-ox record and its associated data on a record-by-record basis.
• -oc causes TDUMP to perform a cyclic redundancy test (CRC) on each encountered record. The display differs
from the -o display only if an erroneous CRC check is encountered (the TDUMP CRC value differs from the
record's CRC byte).
• -oi<id> includes only specified record types in the object module dump. Replace <id> with the name of the record
to be displayed. For instance: TDUMP -oiPUBDEF MYMODULE.OBJ produces an object module display for
MYMODULE.OBJ that displays only the PUBDEF records.
The -ox and -oi options are helpful in finding errors that occur during linking. By examining the spelling and case of
the EXTDEF symbol and the PUBDEF symbol, you can resolve many linking problems. For instance, if you
receive an "unresolved external" message from the linker, use TDUMP -oiEXTDEF to display the external
definitions occurring in the module causing the error. Then, use TDUMP -oiPUBDEF on the module containing the
public symbol the linker could not match.
Another use for the -oi switch is to check the names and sizes of the segments generated in a particular module. For
instance: TDUMP -oiSEGDEF MYMODULE.OBJ displays the names, attributes, and sizes of all of the segments
in MYMODULE.
Note: To get a list of record types for -oi and -ox, use the command line options -oi? and -ox?.
207
Command Line Utilities RAD Studio 3.1 C++ Reference
-s, Tells TDUMP to display strings. By default -s displays all strings in a given file. You can specify a string, or part of a
-su, string, using the following syntax:
-s[xx] -s=<string>
For example, the command:
TDUMP -s=black GoGame.exe
results in the following output of all strings containing 'black':
56840: IDI_BLACK
81965: Capture Black
85038: black.bmp
The optional string argument is case insensitive. To specify several words of a string, use quotes. For example:
TDUMP -s="game of go" GoGame.exe
The -su option is used in the same manner, with an optional string argument, and tells TDUMP to display Unix-style
strings, meaning with no offset.
For example, the command:
TDUMP -su=black GoGame.exe
results in the following output:
IDI_BLACK
Capture Black
black.bmp
For the -s[xx] switch, xx can be:
• # - minimum string length to look for (default: 4)
• b# - Beginning file offset (-b# is the same as -sb#)
• e# - Ending file offset
• f - Format (wrap) long strings
• s - Search string with case sensitivity (default: no)
• u - unix format: no offset (or decimal offsets, -h for hex)
• =x - search string = x
-um Displays mangled names as unmangled. You do not need to reformat the text to edit out only the mangled names
before using this option. You can pass output that has mangled names anywhere in the text, and only the mangled
names will be affected.
-v Verbose display. If used with an .OBJ or .LIB file, TDUMP produces a hexadecimal dump of the record's contents
without any comments about the records.
If you use TDUMP on a Turbo Debugger symbol table, it displays the information tables in the order in which it
encounters them. TDUMP doesn't combine information from several tables to give a more meaningful display on a
per-module basis.
-x Specifies the debug table(s) to exclude.
The libraries included with the CodeGear C++ compiler were built with TLIB. You can use TLIB to build your own libraries, or to
modify the CodeGear C++ libraries, your libraries, libraries furnished by other programmers, or commercial libraries you've
purchased.
208
3.1 C++ Reference RAD Studio Command Line Utilities
When TLIB modifies an existing library, TLIB creates a copy of the original library and gives it a .BAK extension.
Element Description
<libname> The DOS path name of the library you want to create or manage. Every TLIB command must be given a
libname. Wildcards are not allowed. TLIB assumes an extension of .LIB if none is given. Use only the .LIB
extension because both BCC32 and the IDE require the .LIB extension in order to recognize library files. Note: If
the named library does not exist and there are add operations, TLIB creates the library.
<options> TLIB accepts five general options (C, L, P, O, and 8) as well as five default action options (a, d, e, u, and x). See
the headings immediately following this table for details about the TLIB <options> and about the default action
options.
<operations> Describes the actions you want TLIB to do and consists of a sequence of two-character operation codes. If you
only want to examine the contents of the library, do not give any operations. For more information, see the
heading later in this topic.
@<respfile> The path and name of the response file you want to include. You can specify more than one response file. For
more details, see the heading later in this topic.
<listfile> The name of the text file that TLIB will produce to hold a listing of the library contents. The listfile name (if given),
must be preceded by a comma. No listing is produced if you don't give a file name. The listing is an alphabetical
list of each module. The entry for each module contains an alphabetical list of each public symbol defined in that
module. The default extension for the listfile is .LST.
209
Command Line Utilities RAD Studio 3.1 C++ Reference
Normally, when TLIB checks for duplicate symbols in the library, uppercase and lowercase letters are not treated differently (for
example, the symbols lookup and LOOKUP are treated as duplicates). You can use the /C option to add a module to a library
that includes symbols differing only in case.
Don't use /C if you plan to use the library with other linkers or let other people use the library.
TLIB normally rejects symbols that differ only in case because some linkers aren't case-sensitive. ILINK32 has no problem
distinguishing uppercase and lowercase symbols. As long as you use your library only with ILINK32, you can use the TLIB /C
option without any problems.
All modules in the library must start on a page boundary. For example, in a library with a page size of 32 (the lowest possible
page size higher than the default 16), an average of 16 bytes will be lost per object module in padding. If you attempt to create a
library that is too large for the given page size, TLIB will issue an error message and suggest that you use /P with the next
available higher page size.
Symbol Description
/a Add the module to the library.
/d Remove the module from the library.
/e Extract the module without removing it.
/u Replace the module in the library.
/x Extract the module and remove it.
210
3.1 C++ Reference RAD Studio Command Line Utilities
• Contain more than one line of text; use the ampersand character (&) at the end of a line to indicate that another line follows.
• Include a partial list of commands. You can combine options from the the command line with options in a response file.
• Be used with other response files in a single TLIB command line. 3
TLIB Examples
These simple examples demonstrate some of the different things you can do with TLIB:
Example 1
To create a library named MYLIB.LIB with modules X.OBJ, Y.OBJ, and Z.OBJ, type:
tlib mylib +x +y +z
211
Command Line Utilities RAD Studio 3.1 C++ Reference
Example 2
To create a library named MYLIB.LIB and get a listing in MYLIB.LST too, type:
tlib mylib +x +y +z, mylib.lst
Example 3
To replace module X.OBJ with a new copy, add A.OBJ and delete Z.OBJ from MYLIB.LIB, type:
tlib mylib -+x +a -z
Example 5
To extract module Y.OBJ from MYLIB.LIB and get a listing in MYLIB.LST, type:
tlib mylib *y, mylib.lst
Example 6
To create a new library named ALPHA, with modules A.OBJ, B.OBJ, ..., G.OBJ using a response file:
1. First create a text file, ALPHA.RSP, with: +a.obj +b.obj +c.obj & +d.obj +e.obj +f.obj & +g.obj
2. Then use the TLIB command, which produces a listing file named ALPHA.LST: tlib alpha @alpha.rsp, alpha.lst
Example 7
To update modules Y.OBJ and Z.OBJ and delete modules A.OBJ and B.OBJ from MYLIB.LIB:
tlib mylib /u Y.obj Z.obj /d A.obj B.obj
If TOUCH cannot find a file that matches the name you specify, it creates a zero-length file with the correct date stamp. To
suppress automatic file creation, use the -c option.
Because TOUCH is a 32-bit executable, it accepts long file names. In addition, you can use file names that contain the wildcard
characters * and ? to “touch” more than a single file at a time. Use the -s option to update matching files in all subdirectories.
Before you use TOUCH, make sure your system's internal clock is set correctly.
TOUCH Options
TOUCH.EXE supports several command line options.
3 TOUCH Options
Option Description
-c Don't generate file if it doesn't already exist.
-d<mm>-<dd>-<yy> Sets the date of the file to the specified date.
-r<filename> Sets the time and date of file to match those of <filename>.
-h Displays help information (same as typing TOUCH without options or filenames.
212
3.1 C++ Reference RAD Studio Command Line Utilities
See Also
Using MAKE ( see page 183)
3.1.1.23 TRIGRAPH
Trigraphs are three-character sequences that replace certain characters used in the C language that are not available on some
keyboards. Translating trigraphs in the compiler would slow compilation down considerably, so CodeGear C++ provides a filter
named TRIGRAPH.EXE to handle trigraph sequences.
TRIGRAPH Options
TRIGRAPH has three command options:
Trigraph Character
??= #
??( [
??) ]
??/ \
??' ^
??< {
??> }
??- ~
RC is the command-line version of the standard Microsoft SDK resource compiler. It accepts a resource script file (.RC) as input
and produces a resource object file (.RES) as output.
Both C++Builder 2009 and Delphi 2009 give you a choice of resource compilers. On the Project Options Resource
Compiler dialog box, you can select either of the following:
213
Command Line Utilities RAD Studio 3.1 C++ Reference
• To use Windows types or constants with RC, you need to explicitly #include <winresrc.h> for both C++ and Delphi.
• RC does not handle image data inline as BRCC32 does. To use an image with RC, you need to save the image and refer to
the image inline.
• RC handles line continution differently than BRCC32. The simplest change is to combine strings with embedded newlines (\n).
• For RC, the order of command elements requires that all command options must come first, before the name of the resource
file.
• RC does not allow trailing commas after the string in a STRINGLIST.
• RC treats strings as C-style strings. This means that you need to do either of the following:
• Escape a single backslash (\) in filenames by using a double backslash (\\).
• Use a forward slash (/) in place of a single backslash (\).
• For RC, specifying #include <dirname> does not search the current directory. To search the current directory, use
#include "dirname".
• To embed a double-quote character in a string, use two consecutive double-quote characters ("") instead of using the
backslash escape character.
• RCDATA and byte values are handled differently. For example:
• BRCC32 treats '11 aa 22 bb' as a string of bytes.
• For RC, you would need to specify 0xaa11 0xbb22.
See Also
BRC32.EXE ( see page 163)
Note: WSDLIMP ignores any definitions in the WSDL document for which it can't generate code. That is, it can only import Web
Services that use SOAP or document literal encoding.
214
3.1 C++ Reference RAD Studio Command Line Utilities
Proxy/Server Authentication:
-user:userName -pass:Password [-proxy:Proxy]
WSDLIMP.EXE imports a WSDL document, generating the code that lets your application call on the Web Service that the
WSDL document describes. This is the command-line version of the Web Services importer, which is available on the Web
Services tab of the new items dialog.
You can configure the output using the WSDLIMP command-line options when you start the program. These options let you
specify whether the importer generates Object Pascal or C++ code, whether you want to generate implementation classes
because you are writing a server, and how to handle various types of definitions in the WSDL document.
<URL> is the URL for accessing a WSDL document that is published on the Web.
Options Description
-C Generate C++ code to represent the definitions in the WSDL file. You must use either this option or the –P
option, but not both.
-P Generate Object Pascal code to represent the definitions in the WSDL file. You must use either this option or
the –C option, but not both.
-S Generate implementation classes for the APIs that the WSDL document defines. This option is used when you
want to write a server that implements the Web Service that the WSDL document describes.
-Oa When the importer encounters a type that maps to a class with no members, change the imported code to an 3
array. This option exists because in some cases when the WSDL document does not make consistent use of
schema definitions, the importer has problems importing array types, which results in a type that is represented
by a class with no members. This option is always safe to use unless the WSDL document describes a Web
Service that uses document literal encoding. Document literal encoding can also give rise to an empty class
when a method has no return value.
-Oi Ignore ill-formed schemas when importing the WSDL document and attempt to import the Web Service
anyway. This allows the importer to handle cases where the WSDL document is not completely well-formed but
the intent is clear.
215
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
-Oo Treat methods with a single output parameter as functions, mapping the single output parameter to the return
value.
-Oq Do not generate a header comment at the top of each generated file. The header comments indicate what
options were used, list any warnings about the generated code, and so on.
-Oi Generate type definitions for the two types that represent the input and output of a call when the Web Service
uses document literal encoding. This option is only used with the –Ou+ option. When you do not specify –Ou+,
the two type definitions are always generated.
-Ou+ Unwind the literal parameters of document literal encoding to generate method calls. When this option is
selected, the importer converts the two types that
-Ov Unwind the literal parameters of document literal encoding to generate method calls. When this option is
selected, the importer converts the two types that
-Ov Generate code comments (verbose information).
-R:<namelist> Map strings in the WSDL document to the WideString type. WideStrings are more robust, because they can
handle extended characters, but they are not as efficient as using AnsiStrings (the default).
-D<path> Specifies the directory where WSDLIMP writes the files that it generates.
@<path> Specifies a text file where each line lists a URL or WSDL file to import. You can optionally add
'=OutputFileName' after the URL or file name to specify where to place the generated code for each imported
WSDL document.
See Also
Using the Web Services Importer ( see page 2302)
Topics
Name Description
E2066: Invalid MOM inheritance (C++) ( see page 256) The compiler issues this error if the currently compiled class doesn't have the
same MOM (Microsoft Object Model) related flags set as its direct parent.
This compiler error message is deprecated.
E2525: You must define _PCH_STATIC_CONST before including xstring to use You attempted to use a feature defined in xstring, part of the Dinkumware
this feature (C++) ( see page 257) standard C++ library. The C++ compiler could not generate a precompiled
header because there is a constant (defined in xstring) in the header. If you want
to include xstring, you should first set the define _PCH_STATIC_CONST.
E2526: Property 'name' uses another property as getter/setter; Not allowed (C++) Properties typically have both a getter and a setter, but a property cannot serve
( see page 257) as either the getter or setter of another property.
E2008: Published property access functions must use __fastcall calling The calling convention for access functions of a property (read, write, and stored)
convention (C++) ( see page 257) declared in a __published section must be __fastcall. This also applies to hoisted
properties.
E2122: Function call terminated by unhandled exception 'value' at address 'addr' This message is emitted when an expression you are evaluating while debugging
(C++) ( see page 257) includes a function call that terminates with an unhandled exception. For
3 example, if in the debugger's evaluate dialog, you request an evaluation of the
expression foo()+1 and the execution of the function foo() causes a GP fault, this
evaluation produces the above error message.
You may also see this message in the watches window because it also displays
the results of evaluating an expression.
E2506: Explicit specialization of 'specifier' is ambiguous: must specify template In the following code, explicit template arguments are necessary:
arguments (C++) ( see page 257)
216
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2483: Array dimension 'specifier' could not be determined (C++) ( see page If, during instantiation of a type, an array dimension cannot be
258) computed—usually this is due to some other error which would be
reported—then this error will result.
For example, if an array dimension is dependent upon a template parameter but
an error occurs while it is being parsed and the template argument being
substituted does not yield a legal constant expression, this error is displayed.
E2509: Value out of range (C++) ( see page 258) The inline assembler has detected a numeric overflow in one of your
expressions. Make sure all of your numbers can fit in 32 bits.
E2510: Operand size mismatch (C++) ( see page 258) Help is not available for this item.
E2050: __declspec(delphireturn) class 'class' must have exactly one data This is an internal compiler error. A class marked as a delphireturn class has
member (C++) ( see page 258) more than one non-static data member.
E2530: Unrecognized option, or no help available (C++) ( see page 258) You have entered a command element that the C++ compiler cannot parse, or
the option you entered has no associated help. Try again.
E2527: Option 'name' cannot be set via 'name' (C++) ( see page 258) An attempt was made in a source file to set an option that cannot be set after
either parsing or compiling of the file starts. Instead, set this option on the
command line or in a .cfg file.
For example, if a source file contains a #pragma option push —v, you need
to remove the push or set /unset this option either on the command line or in a
.cfg file.
E2528: Option 'name' must be set before compilation begins (C++) ( see page An attempt was made in a source file to set an option that must be set before
258) compiling starts. Instead, set this option on the command line, in a .cfg file, or
at the top of the source file before the line int foo(); .
E2074: Value after -g or -j should be between 0 and 255 inclusive (C++) ( see Both the -g and the -j command line options can be followed by an optional
page 259) number. The compiler expects this number to be between 0 and 255 inclusive.
E2492: Properties may only be assigned using a simple statement, e.g. \"prop = Assignments to properties should be made in simple assignment statements. If
value;\" (C++) ( see page 259) property assignments could become Lvalues, which happens when property
assignments are embedded in larger statements, the getter is called to create the
Lvalue, with all the side effects that getter causes. The compiler allows only one
call to either the getter or the setter in a statement.
For example:
E2505: Explicit instantiation requires an elaborated type specifier (i.e.,"class The following code is illegal:
foo<int>") (C++) ( see page 259)
E2100: Invalid template declarator list (C++) ( see page 259) It is illegal for a declarator list to follow a template class declaration. For example:
E2102: Cannot use template 'template' without specifying specialization The generic form of a template must be referenced using specialization
parameters (C++) ( see page 260) parameters. For example, for a template class named foo, taking two template
parameters, then a legal reference might have the form
E2107: Invalid use of template 'template' (C++) ( see page 260) This error results when attempting to use a template template parameter in any
way other than to reference a template specialization, or to pass that parameter
in turn as a template template argument to another template. For example:
E2105: 'template' qualifier must specify a member template name (C++) ( see When parsing code that depends in some way upon a template parameter, it is
page 260) sometimes impossible to know whether a member name will resolve to a
template function name, or a regular parameter. In the following code, a
'template' qualifier is required in order to know if the '<' (less-then) operator
should be parsed as the beginning character of a template argument list, or as a
regular less-than operator:
E2066: Information not available (C++) ( see page 261) Help is not available for this item.
E2471: pragma checkoption failed: options are not as expected (C++) ( see You can use #pragma checkoption to check that certain switches are in the state
page 261) that you expect. If #pragma checkoption detects that a switch is not in the
expected state, the compiler displays this error.
You can use the following syntax:
E2504: 'dynamic' can only be used with non-template member functions (C++) You tried to use dynamic with a template member function. Dynamic functions
( see page 261) are allowed for classes derived from TObject. Dynamic functions occupy a slot in
every object that defines them, not in any descendants. That is, dynamic
functions are virtual functions stored in sparse virtual tables. If you call a dynamic
function, and that function is not defined in your object, the virtual tables of its
ancestors are searched until the function is found.
E2191: '__far16' may only be used with '__pascal' or '__cdecl' (C++) ( see This is an internal compiler error. The compiler emits this message if the keyword
page 261) __far16 is mixed with one of the keywords __pascal or __cdecl, all in the same 3
declaration.
E2199: Template friend function 'function' must be previously declared (C++) ( Not used
see page 262)
217
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2502: Error resolving #import: problem (C++) ( see page 262) Where problem can be any of the following relating to problems with the various
attributes of #include ( see page 692):
unexpected import directive value attribute 'attribute'A value was supplied for the
indicated attribute. None was expected.
missing ')' in import directive attribute 'attribute'The value for the indicated
attribute was incorrectly specified : a closing parenthesis is missing.
unrecognized import directive attribute 'attribute'The indicated token is not a
legitimate attribute for the #import directive.
invalid values for raw_property_prefixes attributeThe values for the
raw_property_prefixes attribute were incorrectly specified.
unexpected duplicate property 'property'The indicated #import attribute was
specified more than once -- this is an... more ( see page 262)
E2501: Unable to open import file 'filename' (C++) ( see page 262) This error occurs when you use:
E2494: Unrecognized __declspec modifier (C++) ( see page 262) A _declspec modifier was given that is not valid.
E2493: Invalid GUID string (C++) ( see page 263) The GUID string does not have the form of a Globally Unique Identifier.
E2499: Invalid __declspec(uuid(GuidString)) format (C++) ( see page 263) This error happens when you used the wrong format to define your GuidString.
GUIDs are defined for structs in the following way:
E2496: Invalid call to uuidof(struct type|variable) (C++) ( see page 263) The uuidof operator was given an incorrect argument.
E2511: Unterminated macro argument (C++) ( see page 263) A macro argument that was started on the line listed has not been properly
terminated
E2489: Maximum option context replay depth exceeded; check for recursion If this error is triggered, it means that recursive template instantiation has gone
(C++) ( see page 263) too deep. Check for compile-time recursion in your program, and limit it to no
more than 256 levels.
E2488: Maximum token reply depth exceeded; check for recursion (C++) ( see If this error is triggered, it means that recursive template instantiation has gone
page 263) too deep. Check for compile-time recursion in your program, and limit it to no
more than 256 levels.
E2491: Maximum VIRDEF count exceeded; check for recursion (C++) ( see Too many VIRDEF symbols were allocated. The compiler imposes a limit to the
page 263) number of VIRDEFs allowed per translation unit. Currently this limit is in the order
of 16384 VIRDEFs.
One way this could happen is if a program has more than 16384 functions.
E2230: In-line data member initialization requires an integral constant expression Static const class members, which are initialized in the body of the class, have to
(C++) ( see page 264) be initialized with a constant expression of integral type.
E2241: VCL style classes need virtual destructors (C++) ( see page 264) Destructors defined in VCL style classes have to be virtual.
E2524: Anonymous structs/unions not allowed to have anonymous members in The C++ compiler requires that the members of an anonymous struct or union be
C++ (C++) ( see page 264) named.
E2246: x is not abstract public single inheritance class hierarchy with no data Internal compiler error. In some cases, the compiler will enforce restrictions on a
(C++) ( see page 264) class hierarchy. In this case, the restrictions would be that all classes are abstract
classes, and all classes only have one parent.
E2249: = expected (C++) ( see page 264) The compiler expected an equal sign in the position where the error was reported
but there was none. This is usually a syntax error or typo.
E2267: First base must be VCL class (C++) ( see page 264) Internal compiler error. In some cases, the compiler will enforce restrictions on a
class hierarchy. In this case, the restrictions would be that the first parent of a
class is a Delphi style class.
E2472: Cannot declare a member function via instantiation (C++) ( see page If a declaration within a template class acquires a function type through a type
265) dependent on a template-parameter and this results in a declaration that does
not use the syntactic form of a function declarator to have function type, the
program is ill-formed. For example:
E2515: Cannot explicitly specialize a member of a generic template class (C++) You are trying to make a generic template into a specialized member. For
( see page 265) example, the following code is illegal:
E2474: 'function' cannot be declared as static or inline (C++) ( see page 265) You attempted to declare a symbol as static or inline and this type of symbol
cannot be defined as static or inline. Certain functions, like 'main' and 'WinMain'
cannot be declared static or inline. 'main' is the entrypoint of console applications,
and 'WinMain' is the entry point of Windows applications.
For example, this error is displayed in the following cases:
E2498: Need previously defined struct GUID (C++) ( see page 266) This happens when you use the __uuidof operator without including a header
3 that defines the GUID struct. So the following program code would display this
error:
E2295: Too many candidate template specializations from 'specifier' (C++) ( When reference a class template specialization, it is possible that more than one
see page 266) possible candidate might result from a single reference. This can only really
happen among class partial specializations, when more than one partial
specialization is contending for a possible match:
E2475: 'function' cannot be a template function (C++) ( see page 266) Certain functions, like 'main' and 'WinMain' cannot be declared as a template
function. 'main' is the entrypoint of console applications, and 'WinMain' is the
entry point of Windows applications.
For example:
218
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2299: Cannot generate template specialization from 'specifier' (C++) ( see This error will result if an attempt is made to reference a template class or
page 267) function in a manner which yields no possible candidate specializations. For
example:
E2300: Could not generate a specialization matching type for 'specifier' (C++) ( This error is no longer generated by the compiler.
see page 267)
E2497: No GUID associated with type:'type' (C++) ( see page 267) A variable or type was used in a context requiring a GUID, but the type does not
have a GUID associated with it. GUIDs are associated with types using
_declspec (uuid(GUID)).
E2522: Non-const function 'function' called for const object (C++) ( see page Data type mismatch resulting in an erroneous function call. The object of the call
267) (a non-const function) should be a const object.
E2523: Non-volatile function 'name' called for volatile object (C++) ( see page Data type mismatch. The error is the result of an erroneous function call. The
267) object of the call (a non-volatile function) should be a volatile object.
E2513: Cannot emit RTTI for 'parameter' in 'function' (C++) ( see page 267) The compiler issues this error if it cannot generate RTTI information for the return
type of a parameter. See Runtime type information for more information.
E2512: Cannot emit RTTI for return type of 'function' (C++) ( see page 267) The compiler issues this error if the it cannot generate RTTI information for the
return type of a function. See Runtime type information for more information.
E2507: 'class' is not a direct base class of 'class' (C++) ( see page 268) The first type is not a direct base class of the second type. A direct base class
refers to the immediate derivations of that class, and not the derivations of its
subclasses.
E2529: Path 'path' exceeds maximum size of 'n' (C++) ( see page 268) In looking up include files, the C++ compiler has encountered a file whose path
name contains more characters than are allowed in the Windows maximum.
Rename the path to a shorter name.
E2495: Redefinition of uuid is not identical (C++) ( see page 268) GUID's attached to structs have to be the same across multiple declarations and
definitions of the same struct. So the following example would cause this error:
E2500: __declspec(selectany) is only for initialized and externally visible You cannot use __declspec(selectany) with static variables, unitialized variables,
variables (C++) ( see page 268) etc.
E2482: String constant expected (C++) ( see page 268) The compiler expected a string constant at this location but did not receive one.
This error is no longer generated by the compiler.
E2481: Unexpected string constant (C++) ( see page 268) There are times when the compiler does not expect a string constant to appear in
the source input. For example:
E2386: Cannot involve parameter 'parameter' in a complex partial specialization When declaring or defining a template class partial specialization, it is illegal to
expression (C++) ( see page 268) involve any of the non-type template parameters in complex expressions. They
may only be referenced by name. For example:
E2387: Partial specializations may not specialize dependent non-type A partial specialization may not use a template parameter in its specialization
parameters ('parameter') (C++) ( see page 269) argument list which is dependent on another type parameter. For example:
E2388: Argument list of specialization cannot be identical to the parameter list of When declaring a partial specialization, its specialization argument list must differ
primary template (C++) ( see page 269) in some way from its basic parameter list. For example:
template<class T>
E2389: Mismatch in kind of substitution argument and template parameter When referencing a template specialization, all type parameters must be satisfied
'parameter' (C++) ( see page 269) using type arguments, all non-type parameters require non-type arguments, and
all template template parameters require either a template name, or another
template template argument. Mismatching these requirements in any way will
trigger the above error. For example:
E2480: Cannot involve template parameters in complex partial specialization A partial specialization cannot reference other template parameters in a nonvalue
arguments (C++) ( see page 269) argument expression, unless it is simply a direct reference to the template
parameter. For example:
E2392: Template instance 'template' is already instantiated (C++) ( see page There are two ways to trigger this error. If –A is enabled (ANSI compliant mode),
270) then attempting to explicitly instantiate a template specialization which has
already been instantiated (either implicitly or explicitly) will cause this error.
Regardless of –A, attempting to explicitly specialize a template specialization
which has already been either implicit or explicitly instantiated will always trigger
this error. For example:
E2393: Cannot take the address of non-type, non-reference template parameter A template parameter has no address, and is not associated with any real
'parameter' (C++) ( see page 270) "object". Therefore, to take its address, or attempt to assign to it, has no
meaning. For example:
E2399: Cannot reference template argument 'arg' in template class 'class' this The compiler no longer generates this error.
way (C++) ( see page 270) 3
E2397: Template argument cannot have static or local linkage (C++) ( see Only integral constant expressions, and the address of global variables with
page 270) external linkage, may be used as template arguments. For example:
E2485: Cannot use address of array element as non-type template argument Non-type template arguments may only be of integral type, or the address of a
(C++) ( see page 271) global variable. They cannot be the address of an array element. For example:
E2402: Illegal base class type: formal type 'type' resolves to 'type' (C++) ( see When instantiating a template class definition, if it is found that a declared base
page 271) class does not resolve to an accessible class type, this error will result. For
example:
E2403: Dependent call specifier yields non-function 'name' (C++) ( see page The compiler no longer generates this error.
271)
219
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2404: Dependent type qualifier 'qualifier' has no member type named 'name' If a template declaration references a member of a dependent type, it is only
(C++) ( see page 271) possible to alert the user to the non-existence of this member during type
instantiation for a given set of template arguments. For example:
E2405: Dependent template reference 'identifier' yields non-template symbol If a template specialization reference within a template declaration yields a
(C++) ( see page 271) reference to a non-template during type instantiation, the above error will result.
For example:
E2406: Dependent type qualifier 'qualifier' is not a class or struct type (C++) ( If a dependent name reference within a template declaration results in a
see page 272) non-struct member qualification at instantiation time, the above error will result.
For example:
E2407: Dependent type qualifier 'qualifier' has no member symbol named 'name' If a template declaration references a member of a dependent type, it is only
(C++) ( see page 272) possible to alert the user to the non-existence of this member during type
instantiation for a given set of template arguments. For example:
E2408: Default values may be specified only in primary class template Template functions, and class partial specializations, may not use default
declarations (C++) ( see page 272) expressions in their template parameter lists. Only primary template declarations
may do this. For example:
E2409: Cannot find a valid specialization for 'specifier' (C++) ( see page 272) This error is no longer generated by the compiler.
E2410: Missing template parameters for friend template 'template' (C++) ( see If a friend template is declared, but no template parameters are specified, this
page 273) error will result. For example:
E2486: Cannot use address of class member as non-type template argument Non-type template arguments may only be of integral type, or the address of a
(C++) ( see page 273) global variable. They cannot be the address of a class member. For example:
E2411: Declaration of member function default parameters after a specialization If a member function of a class template is declared, and then a specialization of
has already been expanded (C++) ( see page 273) that class implicitly instantiated, and later that member function defined with
default parameters specified, the above error will result. For example:
E2412: Attempting to bind a member reference to a dependent type (C++) ( The compiler no longer generates this error.
see page 273)
E2414: Destructors cannot be declared as template functions (C++) ( see page Destructors cannot be templates. For example:
273)
E2473: Invalid explicit specialization of 'specifier' (C++) ( see page 274) Attempting to explicitly specialize a static data member or any non-template will
cause this error.
E2490: Specialization within template classes not yet implemented (C++) ( see Explicit and partial specialization of member template classes and functions
page 274) within template classes and nested template classes, is not supported.
E2416: Invalid template function declaration (C++) ( see page 274) The compiler no longer generates this error.
E2417: Cannot specify template parameters in explicit specialization of 'specifier' The compiler no longer generates this error.
(C++) ( see page 274)
E2418: Maximum instantiation depth exceeded; check for recursion (C++) ( The compiler only supports 256 levels of instantiation before it will trigger this
see page 274) error. The main problem is in controlling stack depth, because the parser uses
recursive functions to manage type instantiation. Here is an example that would
produce such an error:
E2420: Explicit instantiation can only be used at global scope (C++) ( see page Explicit instantiation cannot be specified at any level other than namespace or
274) global scope. For example:
E2422: Argument kind mismatch in redeclaration of template parameter If a template is declared at one point in the translation unit, and then redeclared
'parameter' (C++) ( see page 275) with template parameters of a different kind at another location, this error will
result. For example:
E2423: Explicit specialization or instantiation of non-existing template 'template' Attempting to explicit specialize or instantiate a template which does not exist is
(C++) ( see page 275) clearly illegal. For example:
E2479: Cannot have both a template class and function named 'name' (C++) ( No other function or type may have the same name as a template class. For
see page 275) example:
E2484: The name of template class 'class' cannot be overloaded (C++) ( see Attempting to declare a function that overrides the name of a template class will
page 275) cause this error. For example:
E2426: Explicit specialization of 'specifier' requires 'template<>' declaration (C++) According to the standard, explicit specialization of any template now always
( see page 275) require the "template<>" declarator syntax. For example:
E2487: Cannot specify default function arguments for explicit specializations An explicit specialization of a function may not declare default function
(C++) ( see page 276) arguments. For example:
E2427: 'main' cannot be a template function (C++) ( see page 276) 'main' cannot be declared as a template function. 'main' is the entry point of a
console application, and it should be declared as a regular __cdecl function.
3 This error message should not occur because it has been replaced with another
one (E2475).
E2429: Not a valid partial specialization of 'specifier' (C++) ( see page 276) Internal compiler error.
E2430: Number of template parameters does not match in redeclaration of If a template is redeclared with a different number of template parameters, this
'specifier' (C++) ( see page 276) error will result. For example:
E2477: Too few template parameters were declared for template 'template' (C++) If a member declaration or definition occurs outside of a template class, and that
( see page 276) outer declaration uses a different number of template parameters than the parent
class, this error will result. For example:
E2478: Too many template parameters were declared for template 'template' If a member declaration or definition occurs outside of a template class, and that
(C++) ( see page 277) outer declaration uses a different number of template parameters than the parent
class, this error will result. For example:
220
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2431: Non-type template parameters cannot be of floating point, class, or void Non-type template parameters are restricted as to what type they may be.
type (C++) ( see page 277) Floating point, class and void types are illegal. For example:
E2434: Template declaration missing template parameters ('template<...>') (C++) In a context where at least one template parameter is clearly required, if none are
( see page 277) found this error will result. For example:
E2435: Too many template parameter sets were specified (C++) ( see page If a member template is being defined outside of its parent class, and too many
277) template parameter sets are declared, this error will result. For example:
E2436: Default type for template template argument 'arg' does not name a If a template template parameter is to have a default type, that type must either
primary template class (C++) ( see page 277) be a generic template class name, or another template template parameter.
E2437: 'typename' should be followed by a qualified, dependent type name (C++) Whenever the "typename" keyword is used in a template declaration or definition,
( see page 278) it should always name a dependent type. For example:
E2438: Template template arguments must name a class (C++) ( see page A template template parameter must always declare a new class name. For
278) example:
E2439: 'typename' is only allowed in template declarations (C++) ( see page The "typename" keyword must only be used within template declarations and
278) definitions.
E2440: Cannot generate specialization from 'specifier' because that type is not The compiler no longer generates this error.
yet defined (C++) ( see page 278)
E2441: Instantiating 'specifier' (C++) ( see page 278) Whenever a compiler error occurs while instantiating a template type, the context
of what was being instantiated at that point in time will be reported to the user, in
order to aid in detection of the problem.
E2503: Missing or incorrect version of TypeLibImport.dll (C++) ( see page 279) This error occurs when the compiler is trying to access TypeLibImport.dll but it
either can't find it, it was corrupted, or you have the wrong version of it installed
on your computer. You can reinstall it from the product CD.
E2470: Need to include header <typeinfo> to use typeid (C++) ( see page 279) When you use the 'typeid' function, you have to include the <typeinfo> header,
otherwise you will get syntax errors.
For example, consider a test case with the following code:
E2514: Cannot (yet) use member overload resolution during template You are trying to overload a member during template instantiation. You cannot
instantiation (C++) ( see page 279) have calls to overloaded constant functions within array bounds initializers, for
example.
E2508: 'using' cannot refer to a template specialization (C++) ( see page 279) The using keyword cannot refer to a template specialization.
E2462: 'virtual' can only be used with non-template member functions (C++) ( The 'virtual' keyword can only be applied to regular member functions, not to
see page 279) member template functions.
Consider a test case with the following code:
W8086: Incorrect use of #pragma alias "aliasName"="substituteName" (C++) ( The directive #pragma alias is used to tell the linker that two identifier names are
see page 280) equivalent. You must put the two names in quotes.
You will receive this warning if you don't use pragma alias correctly. For example,
the following two lines both generate this warning:
W8099: Static main is not treated as an entry point (C++) ( see page 280) The main function has been created as static, and as such cannot be used as a
valid entry point.
Consider:
W8093: Incorrect use of #pragma codeseg [seg_name] ["seg_class"] [group] The #pragma codeseg directive can be used to set or reset the name, class, and
(C++) ( see page 280) group of a segment. You have to follow the exact syntax mentioned in the
warning message, and all names are optional.
So these are all legal:
W8094: Incorrect use of #pragma comment( <type> [,"string"] ) (C++) ( see The directive #pragma comment can be used to emit linker comment records.
page 280) In this message, <type> can be any of the following:
• user
• lib
• exestr
• linker
The type should be there but the string is optional.
W8085: Function 'function' redefined as non-inline (C++) ( see page 281) This warning is used to indicate when a certain function, which has been
declared inline in one location, is redefined in another location to be non-inline. 3
W8105: %s member '%s' in class without constructors (C++) ( see page 281) A class that contains constant or reference members (or both) must have at least
one user-defined constructor.
Otherwise, there would be no way to ever initialize such members.
W8095: Incorrect use of #pragma message( "string" ) (C++) ( see page 281) You can use pragma message to emit a message to the command line or to the
message window. You would get this warning if you use the incorrect syntax, so
W8098: Multi-character character constant (C++) ( see page 281) This warning is issued when the compiler detects a multi-character integer
constant, such as:
221
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
W8096: Incorrect use of #pragma code_seg(["seg_name"[,"seg_class"]]) (C++) Pragma code_seg is similar to pragma codeseg, but with this one you can only
( see page 281) modify the name and the class of a code segment. If you use the wrong syntax,
you get this warning.
The following examples show the correct usage:
W8083: Pragma pack pop with no matching pack push (C++) ( see page 282) Each #pragma pack(pop) should have a matching preceding #pragma
pack(push) in the same translation unit. Pairs of 'push' and 'pop' can be nested.
For example:
W8097: Not all options can be restored at this time (C++) ( see page 282) Your program has a #pragma pop at a place where it can't restore options.
For example:
W8084: Suggest parentheses to clarify precedence (C++) ( see page 282) This warning indicates that several operators used in one expression might
cause confusion about the applicable operator precedence rules. The warning
helps create code that is more easy to understand and potentially less
ambiguous.
For example, compile the following code using the –w command line option:
W8092: 'type' argument 'specifier' passed to 'function' is not an iterator: 'type' An argument that is not an iterator is being used with an STL algorithm that
iterator required (C++) ( see page 282) requires an iterator.
W8087: 'operator::operator==' must be publicly visible to be contained by a 'type' A type that is being used with an STL container has a private 'operator=='.
(C++) ( see page 283)
W8090: 'type::operator<' must be publicly visible to be used with 'type' (C++) ( A type that is being used with an STL container has a private 'operator<'. The
see page 283) type you're trying to use must be made public.
W8089: 'type::operator<' must be publicly visible to be contained by a 'type' The type that is being used for an STL container has a private 'operator<'. The
(C++) ( see page 283) type that is being contained (type::operator) must be a public type.
For example, if you were trying to instantiate a class type "vector<blah>", the
error would be:
W8091: 'type' argument 'specifier' passed to 'function' is a 'iterator category' An incorrect iterator category is being used with an STL algorithm.
iterator: 'iterator category' iterator required (C++) ( see page 283)
W8076: Template instance 'specifier' is already instantiated (C++) ( see page You are trying to explicitly instantiate a template that was already implicitly
283) instantiated.
If –A is not enabled and an attempt is made to explicitly instantiate a
specialization which has already been either implicitly or explicitly instantiated,
this error will result.
W8077: Explicitly specializing an explicitly specialized class member makes no Internal error. This warning is no longer generated by the compiler.
sense (C++) ( see page 283) The following code is illegal:
Informational messages (C++) ( see page 284) The compiler displays status information while compiling if you have checked
"Show general messages" on the Compiler page of the Project Options dialog
box. Most of the messages are self-explanatory and state information about
compiling and linking; for example:
E2196: Cannot take address of member function 'function' (C++) ( see page An expression takes the address of a class member function, but this member
284) function was not found in the program being debugged. The evaluator issues this
message.
F1002: Unable to create output file 'filename' (C++) ( see page 284) This error occurs if the work disk is full or write protected.
This error also occurs if the output directory does not exist.
Solutions
If the disk is full, try deleting unneeded files and restarting the compilation.
If the disk is write-protected, move the source files to a writeable disk and restart
the compilation.
F1003: Error directive: 'message' (C++) ( see page 284) This message is issued when an #error directive is processed in the source
file.
'message' is the text of the #error directive.
F1004: Internal compiler error (C++) ( see page 284) An error occurred in the internal logic of the compiler. This error shouldn't occur
in practice, but is generated in the event that a more specific error message is
not available.
F1006: Bad call of intrinsic function (C++) ( see page 284) You have used an intrinsic function without supplying a prototype. You may have
supplied a prototype for an intrinsic function that was not what the compiler
expected.
3 F1007: Irreducible expression tree (C++) ( see page 285) An expression on the indicated line of the source file caused the code generator
to be unable to generate code. Avoid using the expression. Notify CodeGear if an
expression consistently reproduces this error.
F1009: Unable to open input file 'filename' (C++) ( see page 285) This error occurs if the source file can't be found.
Check the spelling of the name. Make sure the file is on the specified disk or
directory.
Verify that the proper directory paths are listed. If multiple paths are required, use
a semicolon to separate them.
222
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
F1011: Register allocation failure (C++) ( see page 285) Possible Causes
An expression on the indicated line of the source file was so complicated that the
code generator could not generate code for it.
Solutions
Simplify the expression. If this does not solve the problem, avoid the expression.
Notify CodeGear if an expression can consistently reproduce this error.
F1012: Compiler stack overflow (C++) ( see page 285) The compiler's stack has overflowed. This can be caused by a number of things,
among them deeply nested statements in a function body (for example, if/else) or
expressions with a large number of operands. You must simplify your code if this
message occurs. Adding more memory to your system will not help.
F1013: Error writing output file (C++) ( see page 285) A DOS error that prevents the C++ IDE from writing an .OBJ, .EXE, or temporary
file.
Solutions
Make sure that the Output directory in the Directories dialog box is a valid
directory.
Check that there is enough free disk space.
F1000: Compiler table limit exceeded (C++) ( see page 285) One of the compiler's internal tables overflowed.
This usually means that the module being compiled contains too many function
bodies.
This limitation will not be solved by making more memory available to the
compiler. You need to simplify the file being compiled.
F1005: Include files nested too deep (C++) ( see page 286) This message flags (directly or indirectly) recursive #include directives.
F1008: Out of memory (C++) ( see page 286) The total working storage is exhausted.
This error can occur in the following circumstances:
223
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2014: Member is ambiguous: 'member1' and 'member2' (C++) ( see page You must qualify the member reference with the appropriate base class name.
287) In C++ class 'class', member 'member' can be found in more than one base
class, and it was not qualified to indicate which one you meant.
This applies only in multiple inheritance, where the member name in each base
class is not hidden by the same member name in a derived class on the same
path.
The C++ language rules require that this test for ambiguity be made before
checking for access rights (private, protected, public).
It is possible to get this message even though only one (or... more ( see page
287)
E2015: Ambiguity between 'function1' and 'function2' (C++) ( see page 287) Both of the named overloaded functions could be used with the supplied
parameters.
This ambiguity is not allowed.
E2017: Ambiguous member name 'name' (C++) ( see page 287) Whenever a structure member name is used in inline assembly, such a name
must be unique. (If it is defined in more than one structure, all of the definitions
must agree as to its type and offset within the structures). In this case, an
ambiguous member name has been used.
For example:
E2019: 'identifier' cannot be declared in an anonymous union (C++) ( see page The compiler found a declaration for a member function or static member in an
288) anonymous union.
Such unions can only contain data members.
E2020: Global anonymous union not static (C++) ( see page 288) In C++, a global anonymous union at the file level must be static.
E2022: Array size too large (C++) ( see page 288) The declared array is larger than 64K and the 'huge' keyword was not used.
If you need an array of this size, either use the 'huge' modifier, like this:
E2024: Cannot modify a const object (C++) ( see page 288) This indicates an illegal operation on an object declared to be const, such as an
assignment to the object.
E2025: Assignment to 'this' not allowed, use X::operator new instead (C++) ( In early versions of C++, the only way to control allocation of class of objects was
see page 288) by assigning to the 'this' parameter inside a constructor.
This practice is no longer allowed, because a better, safer, and more general
technique is to define a member function operator new instead.
For example:
E2026: Assembler statement too long (C++) ( see page 288) Inline assembly statements can't be longer than 480 bytes.
E2001: Constructors and destructors not allowed in __automated section (C++) Only member function declarations are allowed in __automated sections.
( see page 289)
E2002: Only __fastcall functions allowed in __automated section (C++) ( see The calling convention for functions declared in an __automated section must be
page 289) __fastcall.
E2003: Data member definition not allowed in __automated section (C++) ( see Only member function declarations are allowed in __automated sections.
page 289)
E2004: Only read or write clause allowed in property declaration in __automated Storage specifiers stored, default, and nodefault are not allowed in property
section (C++) ( see page 289) declarations in __automated sections.
E2005: Redeclaration of property not allowed in __automated section (C++) ( If you declare a property in an __automated section it has be a new declaration.
see page 290) Property hoisting is not allowed.
E2027: Must take address of a memory location (C++) ( see page 290) Your source file used the address-of operator (&) with an expression that can't be
used that way; for example, a register variable.
E2028: operator -> must return a pointer or a class (C++) ( see page 290) The C++ operator -> function must be declared to either return a class or a
pointer to a class (or struct or union).
In either case, it must be something to which the -> operator can be applied.
E2029: 'identifier' must be a previously defined class or struct (C++) ( see page You are attempting to declare 'identifier' to be a base class, but either it is not a
290) class or it has not yet been fully defined.
Correct the name or rearrange the declarations.
E2030: Misplaced break (C++) ( see page 290) The compiler encountered a break statement outside a switch or looping
construct.
You can only use break statements inside of switch statements or loops.
E2031: Cannot cast from 'type1' to 'type2' (C++) ( see page 290) A cast from type 'ident1' to type 'ident2' is not allowed.
3 In C++, you cannot cast a member function pointer to a normal function pointer.
For example:
E2033: Misplaced continue (C++) ( see page 291) The compiler encountered a continue statement outside a looping construct.
E2034: Cannot convert 'type1' to 'type2' (C++) ( see page 291) An assignment, initialization, or expression requires the specified type conversion
to be performed, but the conversion is not legal.
In C++, the compiler will convert one function pointer to another only if the
signature for the functions are the same. Signature refers to the arguments and
return type of the function. For example:
E2036: Conversion operator cannot have a return type specification (C++) ( This C++ type conversion member function specifies a return type different from
see page 292) the type itself.
A declaration for conversion function operator can't specify any return type.
224
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2037: The constructor 'constructor' is not allowed (C++) ( see page 292) Constructors of the form
E2039: Misplaced decimal point (C++) ( see page 292) The compiler encountered a decimal point in a floating-point constant as part of
the exponent.
E2041: Incorrect use of default (C++) ( see page 292) The compiler found no colon after the default keyword.
E2042: Declare operator delete (void*) or (void*, size_t) (C++) ( see page 293) E2043 Declare operator delete[] (void*) or (void*, size_t)Compiler error
Declare the operator delete with one of the following:
1.A single void* parameter, or
2.A second parameter of type size_t
If you use the second version, it will be used in preference to the first version.
The global operator delete can only be declared using the single-parameter form.
E2044: operator delete must return void (C++) ( see page 293) E2044 operator delete[] must return voidCompiler error
This C++ overloaded operator delete was declared in some other way.
Declare the operator delete with one of the following:
1.A single void* parameter, or
2.A second parameter of type size_t
If you use the second version, it will be used in preference to the first version.
The global operator delete can only be declared using the single-parameter form.
E2045: Destructor name must match the class name (C++) ( see page 293) In a C++ class, the tilde (~) introduces a declaration for the class destructor.
The name of the destructor must be same as the class name.
In your source file, the ~ preceded some other name.
E2048: Unknown preprocessor directive: 'identifier' (C++) ( see page 293) The compiler encountered a # character at the beginning of a line. The directive
name that followed the # was not one of the following:
225
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2060: Illegal use of floating point (C++) ( see page 295) Floating-point operands are not allowed in these operators
• constant expressions
• the address of a global extern or static variable plus or
minus a constant
E2064: Cannot initialize 'type1' with 'type2' (C++) ( see page 296) You are attempting to initialize an object of type 'type1' with a value of type
'type2' which is not allowed.
The rules for initialization are essentially the same as for assignment.
E2068: 'identifier' is not a non-static data member and can't be initialized here Only data members can be initialized in the initializers of a constructor.
(C++) ( see page 296) This message means that the list includes a static member or function member.
Static members must be initialized outside of the class, for example:
E2069: Illegal use of member pointer (C++) ( see page 296) Pointers to class members can only be passed as arguments to functions, or
used with the following operators:
• assignment operators
• comparison operators
• .*
• —>*
• ?: conditional (ternary) operator
• && logical AND ( see page 531) operator
• || logical OR ( see page 559) operator
The compiler has encountered a member pointer being used
with a different operator.
In order to call a member function pointer, one must supply
an instance of the class for it to call upon.
For example:
E2071: operator new must have an initial parameter of type size_t (C++) ( see E2071 Operator new[] must have an initial parameter of type size_tCompiler error
page 297) Operator new can be declared with an arbitrary number of parameters.
It must always have at least one, the amount of space to allocate.
E2072: Operator new[] must return an object of type void (C++) ( see page 297) This C++ overloaded operator new was declared in some other way.
3 E2075: Incorrect 'type' option: option (C++) ( see page 297) An error has occurred in either the configuration file or a command-line option.
The compiler may not have recognized the configuration file parameter as legal;
check for a preceding hyphen (-), or the compiler may not have recognized the
command-line parameter as legal.
This error can also occur if you use a #pragma option in your code with an
invalid option.
226
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2076: Overloadable operator expected (C++) ( see page 297) Almost all C++ operators can be overloaded.
These are the only ones that can't be overloaded:
• addition(+)
• subtraction(-)
• assignment(=)
• comparison(==)
• indirection(*)
• arrow(->)
3
Your source file used a pointer with some other operator.
Example
E2088: Bad syntax for pure function definition (C++) ( see page 300) Pure virtual functions are specified by appending "= 0" to the declaration, like
this:
227
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2089: Identifier 'identifier' cannot have a type qualifier (C++) ( see page 300) A C++ qualifier class::identifier can't be applied here.
A qualifier is not allowed on the following:
• typedef names
• function declarations (except definitions at the file level)
• on local variables or parameters of functions
• on a class member--except to use its own class as a
qualifier (redundant but legal).
E2090: Qualifier 'identifier' is not a class or namespace name (C++) ( see page The C++ qualifier in the construction qual::identifier is not the name of a struct or
300) class.
E2092: Storage class 'storage class' is not allowed here (C++) ( see page 300) The given storage class is not allowed here.
Probably two storage classes were specified, and only one can be given.
E2096: Illegal structure operation (C++) ( see page 300) Structures can only be used with dot (.), address-of (&) or assignment (=)
operators, or be passed to or from a function as parameters.
The compiler encountered a structure being used with some other operator.
E2104: Invalid use of template keyword (C++) ( see page 300) You can only use a template class name without specifying its actual arguments
inside a template definition.
Using a template class name without specifying its actual arguments outside a
template definition is illegal.
E2108: Improper use of typedef 'identifier' (C++) ( see page 301) Your source file used a typedef symbol where a variable should appear in an
expression.
Check for the declaration of the symbol and possible misspellings.
E2109: Not an allowed type (C++) ( see page 301) Your source file declared some sort of forbidden type; for example, a function
returning a function or array.
E2110: Incompatible type conversion (C++) ( see page 301) The cast requested can't be done.
E2113: Virtual function 'function1' conflicts with base class 'base' (C++) ( see A virtual function has the same argument types as one in a base class, but differs
page 301) in one or more of the following:
• Return type
• Calling convention
• Exception specification (throw list)
E2114: Multiple base classes require explicit class names (C++) ( see page In a C++ class constructor, if there is more than one immediate base class, each
301) base class constructor call in the constructor header must include the base class
name.
E2115: Bit field too large (C++) ( see page 301) This error occurs when you supply a bit field with more than 16 bits.
E2116: Bit fields must contain at least one bit (C++) ( see page 301) You can't declare a named bit field to have 0 (or less than 0) bits.
You can declare an unnamed bit field to have 0 bits.
This is a convention used to force alignment of the following bit field to a byte
boundary (or to a word boundary.
W8005: Bit fields must be signed or unsigned int (C++) ( see page 302) In ANSI C, bit fields may only be signed or unsigned int (not char or long, for
example).
E2119: User break (C++) ( see page 302) You typed a Ctrl+Break while compiling in the IDE.
(This is not an error, just a confirmation.)
E2111: Type 'typename' may not be defined here (C++) ( see page 302) Class and enumeration types may not be defined in a function return type, a
function argument type, a conversion operator type, or the type specified in a
cast.
You must define the given type before using it in one of these contexts.
Note:This error message is often the result of a missing semicolon (;) for a
class declaration. You might want to verify that all the class declarations
preceding the line on which the error occurred end with a semicolon.
3 E2121: Function call missing ) (C++) ( see page 302) The function call argument list had some sort of syntax error, such as a missing
or mismatched right parenthesis.
E2123: Class 'class' may not contain pure functions (C++) ( see page 302) The class being declared cannot be abstract, and therefore it cannot contain any
pure functions.
E2126: Case bypasses initialization of a local variable (C++) ( see page 302) In C++ it is illegal to bypass the initialization of a local variable.
This error indicates a case label that can transfer control past this local variable.
E2127: Case statement missing : (C++) ( see page 302) A case statement must have a constant expression followed by a colon.
The expression in the case statement either was missing a colon or had an extra
symbol before the colon.
228
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2128: Case outside of switch (C++) ( see page 302) The compiler encountered a case statement outside a switch statement.
This is often caused by mismatched braces.
E2129: Character constant too long (or empty) (C++) ( see page 303) Character constants can only be one or two characters long.
E2133: Unable to execute command 'command' (C++) ( see page 303) The linker or assembler cannot be found, or possibly the disk is bad.
E2134: Compound statement missing closing brace (C++) ( see page 303) The compiler reached the end of the source file and found no closing brace.
This is most commonly caused by mismatched braces.
E2137: Destructor for 'class' required in conditional expression (C++) ( see If the compiler must create a temporary local variable in a conditional expression,
page 303) it has no good place to call the destructor because the variable might or might
not have been initialized.
The temporary can be explicitly created, as with classname(val, val), or implicitly
created by some other code.
You should recast your code to eliminate this temporary value.
E2135: Constructor/Destructor cannot be declared 'const' or 'volatile' (C++) ( A constructor or destructor has been declared as const or volatile.
see page 303) This is not allowed.
E2138: Conflicting type modifiers (C++) ( see page 303) This occurs when a declaration is given that includes more than one addressing
modifier on a pointer or more than one language modifier for a function.
Only one language modifier (for example, __cdecl, __pascal, or
__fastcall) can be given for a function.
E2136: Constructor cannot have a return type specification (C++) ( see page C++ constructors have an implicit return type used by the compiler, but you can't
303) declare a return type or return a value.
E2038: Cannot declare or define 'identifier' here: wrong namespace (C++) ( You tried to declare a template in an illegal place or a namespace member
see page 304) outside of its namespace.
E2154: Cannot define 'identifier' using a namespace alias (C++) ( see page You cannot use a namespace alias to define a namespace member outside of its
304) namespace.
E2421: Cannot use local type 'identifier' as template argument (C++) ( see A local type was used in an actual template type argument, which is illegal.
page 304)
E2035: Conversions of class to itself or base class not allowed (C++) ( see You tried to define a conversion operator to the same class or a base class.
page 304)
E2139: Declaration missing ; (C++) ( see page 304) Your source file contained a struct or union field declaration that was not followed
by a semicolon.
Check previous lines for a missing semicolon.
E2140: Declaration is not allowed here (C++) ( see page 304) Declarations can't be used as the control statement for while, for, do, if, or switch
statements.
E2141: Declaration syntax error (C++) ( see page 304) Your source file contained a declaration that was missing a symbol or had an
extra symbol added to it.
Check for a missing semicolon or parenthesis on that line or on previous lines.
E2142: Base class 'class' contains dynamically dispatchable functions (C++) ( This error occurs when a class containing a DDVT function attempts to inherit
see page 304) DDVT functions from multiple parent classes.
Currently, dynamically dispatched virtual tables do not support the use of multiple
inheritance.
E2143: Matching base class function 'function' has different dispatch number If a DDVT function is declared in a derived class, the matching base class
(C++) ( see page 305) function must have the same dispatch number as the derived function.
E2144: Matching base class function 'function' is not dynamic (C++) ( see page If a DDVT function is declared in a derived class, the matching base class
305) function must also be dynamic.
E2145: Functions 'function1' and 'function2' both use the same dispatch number This error indicates a dynamically dispatched virtual table (DDVT) problem.
(C++) ( see page 305)
E2146: Need an identifier to declare (C++) ( see page 305) In this context, an identifier was expected to complete the declaration.
This might be a typedef with no name, or an extra semicolon at file level.
In C++, it might be a class name improperly used as another kind of identifier.
E2147: 'identifier' cannot start a parameter declaration (C++) ( see page 305) An undefined 'identifier' was found at the start of an argument in a function
declarator.
Often the type name is misspelled or the type declaration is missing. This is
usually caused by not including the appropriate header file.
E2150: Type mismatch in default argument value (C++) ( see page 305) The default parameter value given could not be converted to the type of the
parameter.
3
The message "Type mismatch in default argument value" is used when the
parameter was not given a name.
When compiling C++ programs, this message is always preceded by another
message that explains the exact reason for the type mismatch.
That other message is most often "Cannot convert 'type1' to 'type2'" but the
mismatch could be due to another reason.
E2152: Default expression may not use local variables (C++) ( see page 306) A default argument expression is not allowed to use any local variables or other
parameters.
229
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2153: Define directive needs an identifier (C++) ( see page 306) The first non-whitespace character after a #define must be an identifier.
The compiler found some other character.
E2155: Too many default cases (C++) ( see page 306) The compiler encountered more than one default statement in a single switch.
E2156: Default outside of switch (C++) ( see page 306) The compiler encountered a default statement outside a switch statement.
This is most commonly caused by mismatched braces.
E2158: Operand of 'delete' must be non-const pointer (C++) ( see page 306) It is illegal to delete a variable that is not a pointer. It is also illegal to delete a
pointer to a constant.
For example:
E2159: Trying to derive a far class from the huge base 'base' (C++) ( see page This error is no longer generated by the compiler.
306)
E2160: Trying to derive a far class from the near base 'base' (C++) ( see page If a class is declared (or defaults to) near, all derived classes must also be near.
306)
E2161: Trying to derive a huge class from the far base 'base' (C++) ( see page This error is no longer generated by the compiler.
307)
E2162: Trying to derive a huge class from the near base 'base' (C++) ( see This error is no longer generated by the compiler.
page 307)
E2163: Trying to derive a near class from the far base 'base' (C++) ( see page If a class is declared (or defaults to) far, all derived classes must also be far.
307)
E2164: Trying to derive a near class from the huge base 'base' (C++) ( see This error is no longer generated by the compiler.
page 307)
E2165: Destructor cannot have a return type specification (C++) ( see page C++ destructors never return a value, and you can't declare a return type or
307) return a value.
E2166: Destructor for 'class' is not accessible (C++) ( see page 307) The destructor for this C++ class is protected or private, and can't be accessed
here to destroy the class.
If a class destructor is private, the class can't be destroyed, and thus can never
be used. This is probably an error.
A protected destructor can be accessed only from derived classes.
This is a useful way to ensure that no instance of a base class is ever created,
but only classes derived from it.
E2167: 'function' was previously declared with the language 'language' (C++) ( Only one language modifier (cdecl pascal) can be given for a function.
see page 307) This function has been declared with different language modifiers in two locations.
E2168: Division by zero (C++) ( see page 308) Your source file contains a divide or remainder in a constant expression with a
zero divisor.
E2169: 'identifier' specifies multiple or duplicate access (C++) ( see page 308) A base class can be declared public or private, but not both.
This access specifier can appear no more than once for a base class.
E2170: Base class 'class' is included more than once (C++) ( see page 308) A C++ class can be derived from any number of base classes, but can be directly
derived from a given class only once.
E2171: Body has already been defined for function 'function' (C++) ( see page A function with this name and type was previously supplied a function body.
308) A function body can only be supplied once.
One cause of this error is not declaring a default constructor which you
implement. For example:
E2172: Duplicate case (C++) ( see page 308) Each case of a switch statement must have a unique constant expression value.
E2175: Too many storage classes in declaration (C++) ( see page 308) A declaration can never have more than one storage class, either Auto, Register,
Static, or Extern.
E2176: Too many types in declaration (C++) ( see page 309) A declaration can never have more than one basic type. Examples of basic types
are:
• char
• class
• int
• float
3 • double
• struct
• union
• enum
• typedef name
E2179: virtual specified more than once (C++) ( see page 309) The C++ reserved word "virtual" can appear only once in one member function
declaration.
230
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2007: Dispid only allowed in __automated sections (C++) ( see page 309) The definition of dispids is only permitted in __automated sections.
Divide error (C++) ( see page 309) You tried to divide an integer by zero, which is illegal.
E2182: Illegal parameter to __emit__ (C++) ( see page 309) There are some restrictions on inserting literal values directly into your code with
the __emit__ function.
For example, you cannot give a local variable as a parameter to __emit__.
E2183: File must contain at least one external declaration (C++) ( see page This compilation unit was logically empty, containing no external declarations.
309) ANSI C and C++ require that something be declared in the compilation unit.
E2184: Enum syntax error (C++) ( see page 310) An enum declaration did not contain a properly formed list of identifiers.
E2185: The value for 'identifier' is not within the range of 'type-name' (C++) ( You have attempted to assign a value that is out of the range of the specified
see page 310) type.
E2186: Unexpected end of file in comment started on line 'number' (C++) ( see The source file ended in the middle of a comment.
page 310) This is normally caused by a missing close of comment (*/).
E2187: Unexpected end of file in conditional started on line 'number' (C++) ( The source file ended before the compiler (or MAKE) encountered #endif.
see page 310) The #endif either was missing or misspelled.
Every #if statement needs a matching #endif statement.
E2188: Expression syntax (C++) ( see page 310) This is a catch-all error message when the compiler parses an expression and
encounters a serious error.
Possible Causes
This is most commonly caused by one of the following:
231
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2195: Cannot evaluate function call (C++) ( see page 312) The error message is issued if someone tries to explicitly construct an object or
call a virtual function.
In integrated debugger expression evaluation, calls to certain functions (including
implicit conversion functions, constructors, destructors, overloaded operators,
and inline functions) are not supported.
E2198: Not a valid expression format type (C++) ( see page 312) Invalid format specifier following expression in the debug evaluate or watch
window. A valid format specifier is an optional repeat value followed by a format
character (c, d, f[n], h, x, m, p, r, or s).
E2200: Functions may not be part of a struct or union (C++) ( see page 312) This C struct or union field was declared to be of type function rather than pointer
to function.
Functions as fields are allowed only in C++.
Floating point error: Divide by 0 OR Floating point error: Domain OR Floating These fatal errors result from a floating-point operation for which the result is not
point error: Overflow (C++) ( see page 312) finite:
232
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2209: Unable to open include file 'filename' (C++) ( see page 314) The compiler could not find the named file.
Possible Causes
233
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2233: Cannot initialize a class member here (C++) ( see page 317) Individual members of structs, unions, and C++ classes can't have initializers.
A struct or union can be initialized as a whole using initializers inside braces.
A C++ class can only be initialized by the use of a constructor.
E2232: Constant/Reference member 'member' in class without constructors A class that contains constant or reference members (or both) must have at least
(C++) ( see page 317) one user-defined constructor.
Otherwise, there would be no way to ever initialize such members.
E2229: Member 'member' has the same name as its class (C++) ( see page A static data member, enumerator, member of an anonymous union, or nested
317) type cannot have the same name as its class.
Only a member function or a non-static member can have a name that is identical
to its class.
E2234: Memory reference expected (C++) ( see page 317) The built-in assembler requires a memory reference.
You probably forgot to put square brackets around an index register operand.
E2231: Member 'member' cannot be used without an object (C++) ( see page This means that you have written class::member where 'member' is an ordinary
318) (non-static) member, and there is no class to associate with that member.
For example, it is legal to write this:
E2235: Member function must be called or its address taken (C++) ( see page A reference to a member function must be called, or its address must be taken
318) with & operator.
In this case, a member function has been used in an illegal context.
For example:
O2237: DPMI programs must use the large memory model (C++) ( see page The compiler no longer issues this error.
318)
E2238: Multiple declaration for 'identifier' (C++) ( see page 318) This identifier was improperly declared more than once.
This might be caused by conflicting declarations such as:
• int a; double a;
• a function declared two different ways, or
• a label repeated in the same function, or
• some declaration repeated other than an extern function
or a simple variable
This can also happen by inadvertently including the same
header file twice. For example, given:
E2239: 'identifier' must be a member function (C++) ( see page 319) Most C++ operator functions can be members of classes or ordinary
non-member functions, but these are required to be members of classes:
• operator =
• operator ->
• operator ( )
• type conversions
This operator function is not a member function but should
be.
E2240: Conversion of near pointer not allowed (C++) ( see page 319) A near pointer cannot be converted to a far pointer in the expression evaluation
box when a program is not currently running. This is because the conversion
needs the current value of DS in the user program, which doesn't exist.
E2243: Array allocated using 'new' may not have an initializer (C++) ( see page When initializing a vector (array) of classes, you must use the constructor that
319) has no arguments.
This is called the default constructor, which means that you can't supply
constructor arguments when initializing such a vector.
E2244: 'new' and 'delete' not supported (C++) ( see page 319) The integrated debugger does not support the evaluation of the new and delete
3 operators.
E2245: Cannot allocate a reference (C++) ( see page 319) You have attempted to create a reference using the new operator.
This is illegal, because references are not objects and can't be created through
new.
E2309: Inline assembly not allowed (C++) ( see page 320) Your source file contains inline assembly language statements and you are
compiling it from within the integrated environment.
You must use the BCC command to compile this source file from the DOS
command line.
E2250: No base class to initialize (C++) ( see page 320) This C++ class constructor is trying to implicitly call a base class constructor, but
this class was declared with no base classes.
Check your declarations.
234
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2254: : expected after private/protected/private (C++) ( see page 320) When used to begin a private, protected, or public section of a C++ class, the
reserved words "private," "protected," and "public" must be followed by a colon.
E2255: Use :: to take the address of a member function (C++) ( see page 320) If f is a member function of class c, you take its address with the syntax
E2256: No : following the ? (C++) ( see page 320) The question mark (?) and colon (:) operators do not match in this expression.
The colon might have been omitted, or parentheses might be improperly nested
or missing.
E2257: , expected (C++) ( see page 320) A comma was expected in a list of declarations, initializations, or parameters.
This problem is often caused by a missing syntax element earlier in the file or
one of its included headers.
E2258: Declaration was expected (C++) ( see page 320) A declaration was expected here but not found.
This is usually caused by a missing delimiter such as a comma, semicolon, right
parenthesis, or right brace.
E2259: Default value missing (C++) ( see page 321) When a C++ function declares a parameter with a default value, all of the
following parameters must also have default values.
In this declaration, a parameter with a default value was followed by a parameter
without a default value.
E2260: Default value missing following parameter 'parameter' (C++) ( see page All parameters following the first parameter with a default value must also have
321) defaults specified.
E2263: Exception handling not enabled (C++) ( see page 321) A 'try' block was found with the exception handling disabled.
E2264: Expression expected (C++) ( see page 321) An expression was expected here, but the current symbol can't begin an
expression.
This message might occur where the controlling expression of an if or while
clause is expected or where a variable is being initialized.
This message is often due to a symbol that is missing or has been added.
E2266: No file names given (C++) ( see page 321) The command line contained no file names. You must specify a source file name.
E2265: No file name ending (C++) ( see page 321) The file name in an #include statement was missing the correct closing quote
or angle bracket.
E2271: Goto statement missing label (C++) ( see page 321) The goto keyword must be followed by an identifier.
E2272: Identifier expected (C++) ( see page 321) An identifier was expected here, but not found.
In C, an identifier is expected in the following situations:
235
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2279: Cannot find default constructor to initialize member 'identifier' (C++) ( When the following occurs
see page 323) 1.A C++ class 'class1' contains a member of class 'class2,'
and
2.You want to construct an object of type 'class1' (but not from another object of
type 'class1'). There must be a constructor class2::class2() so that the member
can be constructed.
This constructor without parameters is called the default constructor.
The compiler will supply a default constructor automatically unless you have
defined any constructor for class 'class2'.
In that case, the compiler will not supply the default constructor automatically (
you must supply one.
E2310: Only member functions may be 'const' or 'volatile' (C++) ( see page Something other than a class member function has been declared const or
323) volatile.
E2311: Non-virtual function 'function' declared pure (C++) ( see page 323) Only virtual functions can be declared pure, because derived classes must be
able to override them.
E2283: Use . or -> to call 'function' (C++) ( see page 323) You attempted to call a member function without providing an object. This is
required to call a member function.
E2284: Use . or -> to call 'member', or & to take its address (C++) ( see page A reference to a non-static class member without an object was encountered.
323) Such a member can't be used without an object, or its address must be taken
with the & operator.
E2285: Could not find a match for 'argument(s)' (C++) ( see page 323) No C++ function could be found with parameters matching the supplied
arguments. Check parameters passed to function or overload function for
parameters that are being passed.
E2286: Overloaded function resolution not supported (C++) ( see page 324) In integrated debugger expression evaluation, resolution of overloaded functions
or operators is not supported, not even to take an address.
E2287: Parameter 'number' missing name (C++) ( see page 324) In a function definition header, this parameter consisted only of a type specifier
'number' with no parameter name.
This is not legal in C.
(It is allowed in C++, but there's no way to refer to the parameter in the function.)
E2288: Pointer to structure required on left side of -> or ->* (C++) ( see page Nothing but a pointer is allowed on the left side of the arrow (->) in C or C++.
324) In C++ a -> operator is allowed.
E2290: 'code' missing ] (C++) ( see page 324) This error is generated if any of the following occur:
236
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2314: Call of nonfunction (C++) ( see page 325) The name being called is not declared as a function.
This is commonly caused by incorrectly declaring the function or misspelling the
function name.
E2321: Declaration does not specify a tag or an identifier (C++) ( see page 325) This declaration doesn't declare anything.
This may be a struct or union without a tag or a variable in the declaration. C++
requires that something be declared.
For example:
E2297: 'this' can only be used within a member function (C++) ( see page 326) In C++, "this" is a reserved word that can be used only within class member
functions.
E2316: 'identifier' is not a member of 'struct' (C++) ( see page 326) You are trying to reference 'identifier' as a member of 'struct', but it is not a
member.
Check your declarations.
E2317: 'identifier' is not a parameter (C++) ( see page 326) In the parameter declaration section of an old-style function definition, 'identifier'
is declared but not listed as a parameter. Either remove the declaration or add
'identifier' as a parameter.
E2319: 'identifier' is not a public base class of 'classtype' (C++) ( see page 326) The right operand of a .*, ->*, or ::operator was not a pointer to a member of a
class that is either identical to (or an unambiguous accessible base class of) the
left operand's class type.
E2320: Expression of scalar type expected (C++) ( see page 326) The !, ++, and -- operators require an expression of scalar type.
Only these types are allowed:
• char
• short
• int
• long
• enum
• float
• double
• long double
• pointer
E2302: No type information (C++) ( see page 327) The integrated debugger has no type information for this variable. Ensure that
you've compiled the module with debug information. If it has, the module may
have been compiled by another compiler or assembler.
E2303: Type name expected (C++) ( see page 327) One of these errors has occurred:
237
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2282: Namespace name expected (C++) ( see page 328) The name of a namespace symbol was expected.
E2334: Namespace member 'identifier' declared outside its namespace (C++) ( Namespace members must be declared inside their namespace. You can only
see page 328) use explicit qualification to define a namespace member (for example, to give a
body for a function declared in a namespace). The declaration itself must be
inside the namespace.
E2325: Illegal octal digit (C++) ( see page 329) The compiler found an octal constant containing a non-octal digit (8 or 9).
E2329: Invalid combination of opcode and operands (C++) ( see page 329) The built-in assembler does not accept this combination of operands.
Possible causes
238
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2343: Type mismatch in parameter 'parameter' in call to 'function' (C++) ( see Your source file declared the named function with a prototype, and the named
page 331) parameter could not be converted to the declared parameter type.
When compiling C++ programs, this message is always preceded by another
message that explains the exact reason for the type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the
mismatch might be due to many other reasons.
E2345: Access can only be changed to public or protected (C++) ( see page A C++ derived class can modify the access rights of a base class member, but
331) only to public or protected.
A base class member can't be made private.
E2349: Nonportable pointer conversion (C++) ( see page 331) An implicit conversion between a pointer and an integral type is required, but the
types are not the same size. You must use an explicit cast.
This conversion might not make any sense, so be sure this is what you want to
do.
E2350: Cannot define a pointer or reference to a reference (C++) ( see page It is illegal to have a pointer to a reference or a reference to a reference.
332)
E2352: Cannot create instance of abstract class 'class' (C++) ( see page 332) Abstract classes (those with pure virtual functions) can't be used directly, only
derived from.
When you derive an abstract base class, with the intention to instantiate
instances of this derived class, you must override each of the pure virtual
functions of the base class exactly as they are declared.
For example:
E2354: Two operands must evaluate to the same type (C++) ( see page 332) The types of the expressions on both sides of the colon in the conditional
expression operator (?:) must be the same, except for the usual conversions.
These are some examples of usual conversions
• char to int
• float to double
• void* to a particular pointer
In this expression, the two sides evaluate to different types
that are not automatically converted.
This might be an error or you might merely need to cast one
side to the type of the other.
When compiling C++ programs, this message is always
preceded by another message that explains the exact
reason for the type mismatch.... more ( see page 332)
E2355: Recursive template function: 'x' instantiated 'y' (C++) ( see page 333) The compiler has detected a recursive template function instance. For example:
E2356: Type mismatch in redeclaration of 'identifier' (C++) ( see page 333) Your source file redeclared a variable with a different type than was originally
declared for the variable.
Possible Causes
This can occur if a function is called and subsequently declared to return
something other than an integer.
Solutions
If this has happened, you must declare the function before the first call to it.
E2357: Reference initialized with 'type1', needs lvalue of type 'type2' (C++) ( A reference variable that is not declared constant must be initialized with an
see page 333) lvalue of the appropriate type.
In this case, the initializer either wasn't an lvalue, or its type didn't match the
reference being initialized.
E2358: Reference member 'member' needs a temporary for initialization (C++) You provided an initial value for a reference type that was not an lvalue of the
( see page 333) referenced type.
This requires the compiler to create a temporary for the initialization.
Because there is no obvious place to store this temporary, the initialization is
illegal.
3
239
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2360: Invalid register combination (e.g. [BP+BX]) (C++) ( see page 334) The built-in assembler detected an illegal combination of registers in an
instruction.
These are valid index register combinations:
• [BX]
• [BP]
• [SI]
• [DI]
• [BX+SI]
• [BX+DI]
• [BP+SI]
• [BP+DI]
Other index register combinations are not allowed.
E2361: 'specifier' has already been included (C++) ( see page 334) This type specifier occurs more than once in this declaration.
Delete or change one of the occurrences.
E2362: Repeat count needs an lvalue (C++) ( see page 334) The expression before the comma (,) in the Watch or Evaluate window must be
an accessible region of storage. For example, expressions like this one are not
valid:
E2363: Attempting to return a reference to local variable 'identifier' (C++) ( see This C++ function returns a reference type, and you are trying to return a
page 334) reference to a local (auto) variable.
This is illegal, because the variable referred to disappears when the function exits.
You can return a reference to any static or global variable, or you can change the
function to return a value instead.
E2364: Attempting to return a reference to a local object (C++) ( see page 334) You attempted to return a reference to a temporary object in a function that
returns a reference type. This may be the result of a constructor or a function call.
This object will disappear when the function returns, making the reference illegal.
E2365: Member pointer required on right side of .* or ->* (C++) ( see page 335) The right side of a C++ dot-star (.*) or an arrow star (->*) operator must be
declared as a pointer to a member of the class specified by the left side of the
operator.
In this case, the right side is not a member pointer.
E2366: Can't inherit non-RTTI class from RTTI base OR E2367 Can't inherit When virtual functions are present, the RTTI attribute of all base classes must
RTTI class from non-RTTI base (C++) ( see page 335) match that of the derived class.
E2368: RTTI not available for expression evaluation (C++) ( see page 335) Expressions requiring RTTI are not supported by the expression evaluator in the
integrated debugger. This error message is only issued by the expression
evaluator (if you try to Inspect, Watch, or Evaluate), not by the compiler.
E2371: sizeof may not be applied to a bit field (C++) ( see page 335) sizeof returns the size of a data object in bytes, which does not apply to a bit field.
E2372: sizeof may not be applied to a function (C++) ( see page 335) sizeof can be applied only to data objects, not functions.
You can request the size of a pointer to a function.
E2373: Bit field cannot be static (C++) ( see page 335) Only ordinary C++ class data members can be declared static, not bit fields.
E2374: Function 'function' cannot be static (C++) ( see page 335) Only ordinary member functions and the operators new and delete can be
declared static.
Constructors, destructors and other operators must not be static.
Stack overflow (C++) ( see page 335) This error is reported when you compile a function with the Test Stack Overflow
option on, but there is not enough stack space to allocate the function's local
variables.
This error can also be caused by the following:
• infinite recursion, or
• an assembly language procedure that does not maintain
3 the stack project
• a large array in a function
E2376: statement missing (C++) ( see page 336) In a do, for, if, switch, or while statement, the compiler found no left parenthesis
after the while keyword or test expression.
E2377: statement missing ) (C++) ( see page 336) In a do, for, if, switch, or while statement, the compiler found no right parenthesis
after the while keyword or test expression.
E2378: do-while or for statement missing ; (C++) ( see page 336) In a do or for statement, the compiler found no semicolon after the right
parenthesis.
240
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2379: Statement missing ; (C++) ( see page 336) The compiler encountered an expression statement without a semicolon following
it.
E2380: Unterminated string or character constant (C++) ( see page 336) The compiler found no terminating quote after the beginning of a string or
character constant.
E2381: Structure size too large (C++) ( see page 336) Your source file declared a structure larger than 64K.
E2382: Side effects are not allowed (C++) ( see page 336) Side effects such as assignments, ++, or -- are not allowed in the debugger
watch window. A common error is to use x = y (not allowed) instead of x == y to
test the equality of x and y.
E2383: Switch selection expression must be of integral type (C++) ( see page The selection expression in parentheses in a switch statement must evaluate to
336) an integral type (char, short, int, long, enum).
You might be able to use an explicit cast to satisfy this requirement.
E2433: Specialization after first use of template (C++) ( see page 337) An ANSI C++ rule requires that a specialization for a function template be
declared before its first use. This error message is only issued when the ANSI
conformance option (-A) is active.
E2384: Cannot call near class member function with a pointer of type 'type' (C++) Also E2385 Cannot call near class member function 'function' with a pointer of
( see page 337) type 'type'
Member functions of near classes can't be called via a member pointer.
This also applies to calls using pointers to members.
(Remember, classes are near by default in the tiny, small, and medium memory
models.)
Either change the pointer to be near, or declare the class as far.
E2390: Type mismatch in parameter 'number' in template class name 'template' The actual template argument value supplied for the given parameter did not
(C++) ( see page 337) exactly match the formal template parameter type.
When compiling C++ programs, this message is always preceded by another
message that explains the exact reason for the type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the
mismatch might be due to many other reasons.
E2391: Type mismatch in parameter 'parameter' in template class name The actual template argument value supplied for the given parameter did not
'template' (C++) ( see page 337) exactly match the formal template parameter type.
When compiling C++ programs, this message is always preceded by another
message that explains the exact reason for the type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the
mismatch might be due to many other reasons.
E2394: Too few arguments passed to template 'template' (C++) ( see page 337) A template class name was missing actual values for some of its formal
parameters.
E2395: Too many arguments passed to template 'template' (C++) ( see page A template class name specified too many actual values for its formal parameters.
338)
E2396: Template argument must be a constant expression (C++) ( see page A non-type template class argument must be a constant expression of the
338) appropriate type.
This includes constant integral expressions and addresses of objects or functions
with external linkage or members.
E2401: Invalid template argument list (C++) ( see page 338) This error indicates that an illegal template argument list was found.
In a template declaration, the keyword template must be followed by a list of
formal arguments enclosed within < and > delimiters.
E2400: Nontype template argument must be of scalar type (C++) ( see page A nontype formal template argument must have scalar type; it can have an
338) integral, enumeration, or pointer type.
E2415: Template functions may only have 'type-arguments' (C++) ( see page A function template was declared with a non-type argument.
338) This is not allowed with a template function, as there is no way to specify the
value when calling it.
E2425: 'member' is not a valid template type member (C++) ( see page 338) A member of a template with some actual arguments that depend on the formal
arguments of an enclosing template was found not to be a member of the
specified template in a particular instance.
E2428: Templates must be classes or functions (C++) ( see page 338) The declaration in a template declaration must specify either a class type or a
function.
E2432: 'template' qualifier must name a template class or function instance' When defining a template class member, the actual arguments in the template
(C++) ( see page 339) class name used as the left operand for the :: operator must match the formal 3
arguments of the template class.
E2442: Two consecutive dots (C++) ( see page 339) Because an ellipsis contains three dots (...), and a decimal point or member
selection operator uses one dot (.), two consecutive dots cannot legally occur in a
C program.
E2443: Base class 'class' is initialized more than once (C++) ( see page 339) In a C++ class constructor, the list of initializations following the constructor
header includes base class 'class' more than once.
E2444: Member 'member' is initialized more than once (C++) ( see page 339) In a C++ class constructor, the list of initializations following the constructor
header includes the same member name more than once.
241
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2445: Variable 'identifier' is initialized more than once (C++) ( see page 339) This variable has more than one initialization. It is legal to declare a file level
variable more than once, but it can have only one initialization (even if two are
the same).
E2446: Function definition cannot be a typedef'ed declaration (C++) ( see page In ANSI C, a function body cannot be defined using a typedef with a function
339) Type.
Redefine the function body.
E2132: Templates and overloaded operators cannot have C linkage (C++) ( You tried to use a linkage specification with a template or overloaded operator.
see page 339) The most common cause for this error message is having the declaration
wrapped in an extern "C" linkage specification.
E2447: 'identifier' must be a previously defined enumeration tag (C++) ( see This declaration is attempting to reference 'ident' as the tag of an enum type, but
page 340) it has not been so declared.
Correct the name, or rearrange the declarations.
E2448: Undefined label 'identifier' (C++) ( see page 340) The named label has a goto in the function, but no label definition.
E2449: Size of 'identifier' is unknown or zero (C++) ( see page 340) This identifier was used in a context where its size was needed.
A struct tag might only be declared (the struct not defined yet), or an extern array
might be declared without a size.
It's illegal then to have some references to such an item (like sizeof) or to
dereference a pointer to this type.
Rearrange your declaration so that the size of 'identifier' is available.
E2450: Undefined structure 'structure' (C++) ( see page 340) The named structure was used in the source file, probably on a pointer to a
structure, but had no definition in the source file.
This is probably caused by a misspelled structure name or a missing declaration.
E2451: Undefined symbol 'identifier' (C++) ( see page 340) The named identifier has no declaration.
Possible Causes
242
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2468: Value of type void is not allowed (C++) ( see page 342) A value of type void is really not a value at all, so it can't appear in any context
where an actual value is required.
Such contexts include the following:
243
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2052: Dynamic function 'function' conflicts with base class 'class' (C++) ( see Some of the modifiers of this dynamic function conflict with the definition of the
page 345) same function in the base class. The two functions should have the same
modifiers. The following modifiers (among others) can cause conflicts:
• __export
• __import
• declspec(naked)
• declspec(package)
• __fastcall
E2057: Exception specification not allowed here (C++) ( see page 345) Function pointer type declarations are not allowed to contain exception
specifications.
E2058: Exception handling variable may not be used here (C++) ( see page An attempt has been made to use one of the exception handling values that are
346) restricted to particular exception handling constructs, such as
GetExceptionCode().
E2065: Using namespace symbol 'symbol' conflicts with intrinsic of the same If you define a function in a namespace, which has a name that might be
name (C++) ( see page 346) replaced by a call to an intrinsic when -Oi is on, it is not permitted to have a
"using" declaration which refers to that member.
For example, calls to "strcmp" are replaced by the intrinsic "__strcmp__" when
-Oi is on. This means that the declaration "using N::strcmp;" would become
"using N::__strcmp__", since the token replacement happens before the
compiler's parser ever sees the tokens.
An error displays in this case, because the compiler doesn't know how to process
"N::__strcmp__".
E2067: 'main' must have a return type of int (C++) ( see page 346) In C++, function main has special requirements, one of which is that it cannot be
declared with any return type other than int.
E2073: Nothing allowed after pragma option pop (C++) ( see page 346) The #pragma option pop can only be followed by comments, blanks, or end of
line.
E2091: Functions cannot return arrays or functions (C++) ( see page 346) A function was defined to return an array or a function. Check to see if either the
intended return was a pointer to an array or function (and perhaps the * is
missing) or if the function definition contained a request for an incorrect datatype.
E2093: Operator 'operator' not implemented in type 'type' for arguments of the The operator you are calling is not defined in this class. When you have an
same type (C++) ( see page 346) expression: x + x, where x is of type class X, the operator + has to be defined in
class X and be accessible.
E2094: Operator 'operator' not implemented in type 'type' for arguments of type The operator you are calling is not defined in this class. When you have an
'type' (C++) ( see page 346) expression: x + x, where x is of type class X, the operator + has to be defined in
class X and be accessible.
E2097: Explicit instantiation only allowed at file or namespace scope (C++) ( The explicit instantiation operator "template" can only be used within global or
see page 347) namespace scope. It cannot be used to qualify a local class or a class member,
for example.
E2098: Explicit specialization declarator "template<>" now required (C++) ( see When specializing a function, such as providing the definition for "foo<int>", so
page 347) that foo behaves specially which called for the "int" argument, now requires that
the declaration begin with an explicit specialization operator.
E2099: Explicit specialization only allowed at file or namespace scope (C++) ( The explicit specialization operator template<> can only be used within global or
see page 347) namespace scope. It cannot be used to qualify a local class or a class member,
for example.
E2101: 'export' keyword must precede a template declaration (C++) ( see page The 'export' keyword can only occur before the keyword "template" ina template
347) declaration. It cannot be used anywhere else.
E2103: Explicit instantiation must be used with a template class or function (C++) The explicit instantiation operator "template" can only be used to refer to
( see page 347) templates. It cannot be used with non-templates.
E2106: Explicit specialization must be used with a template class or function The explicit specialization operator template<> can only be used in front of a
(C++) ( see page 347) template class or function. Using it with a normal class means nothing, and
hence generates an error.
E2112: Unknown unit directive: 'directive' (C++) ( see page 347) You cannot use this name as a unit directive. Instead use one of the following
unit directives: weak, smart_init, or deny.
3 E2118: Bit fields must have integral type (C++) ( see page 348) In C++, bit fields must have an integral type. This includes enumerations.
E2120: Cannot call 'main' from within the program (C++) ( see page 348) C++ does not allow recursive calls of main( ).
E2125: Compiler could not generate copy constructor for class 'class' OR Sometimes the compiler is required to generate a member function for the user.
Compiler could not generate default constructor for class 'class' OR Compiler Whenever such a member function can't be generated due to applicable
could not generate operator = for class 'class' (C++) ( see page 348) language rules, the compiler issues one of these error messages.
E2130: Circular property definition (C++) ( see page 348) Indicates that a property definition relies directly or indirectly on itself.
E2131: Objects of type 'type' cannot be initialized with { } (C++) ( see page 348) Ordinary C structures can be initialized with a set of values inside braces.
C++ classes can only be initialized with constructors if the class has constructors,
private members, functions, or base classes that are virtual.
244
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2148: Default argument value redeclared for parameter 'parameter' (C++) ( When a parameter of a C++ function is declared to have a default value, this
see page 348) value can't be changed, redeclared, or omitted in any other declaration for the
same function.
E2149: Default argument value redeclared (C++) ( see page 349) When a parameter of a C++ function is declared to have a default value, this
value can't be changed, redeclared, or omitted in any other declaration for the
same function.
E2151: Type mismatch in default value for parameter 'parameter' (C++) ( see The default parameter value given could not be converted to the type of the
page 349) parameter.
The message "Type mismatch in default argument value" is used when the
parameter was not given a name.
When compiling C++ programs, this message is always preceded by another
message that explains the exact reason for the type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the
mismatch might be due to many other reasons.
E2157: Deleting an object requires exactly one conversion to pointer operator If a person uses the 'delete' operator on an object (note: not a pointer to an
(C++) ( see page 349) object, but an object itself), the standard requires that object to define exactly one
"conversion to pointer operator" which will yield the pointer that gets freed. For
example:
E2173: Duplicate handler for 'type1', already had 'type2' (C++) ( see page 349) It is not legal to specify two handlers for the same type.
E2174: The name handler must be last (C++) ( see page 349) In a list of catch handlers, if the specified handler is present, it must be the last
handler in the list (that is, it cannot be followed by any more catch handlers).
E2177: Redeclaration of #pragma package with different arguments (C++) ( You can have multiple #pragma package statements in a source file as long as
see page 350) they have the same arguments. This error occurs if the compiler encounters
more than one #pragma package with different arguments in each.
E2178: VIRDEF name conflict for 'function' (C++) ( see page 350) The compiler must truncate mangled names to a certain length because of a
name length limit that is imposed by the linker. This truncation may (in very rare
cases) cause two names to mangle to the same linker name. If these names
happen to both be VIRDEF names, the compiler issues this error message. The
simplest workaround for this problem is to change the name of 'function' so that
the conflict is avoided.
E2180: Dispid number already used by identifier (C++) ( see page 350) Dispids must be unique and the compiler checks for this.
E2181: Cannot override a 'dynamic/virtual' with a 'dynamic/virtual' function (C++) When you declare a function dynamic, you cannot override this function in a
( see page 350) derived class with a virtual function of the same name and type. Similarly when
the function is declared virtual, you cannot override it with a dynamic one in a
derived class.
E2202: Goto into an exception handler is not allowed (C++) ( see page 350) It is not legal to jump into a try block, or an exception handler that is attached to a
try block.
E2205: Illegal type type in __automated section (C++) ( see page 350) Only certain types are allowed in __automated sections.
E2242: Specifier requires Delphi style class type (C++) ( see page 351) The stored, default, and nodefault storage specifiers are only allowed within
property declarations of Delphi style class types.
E2247: 'member' is not accessible (C++) ( see page 351) You are trying to reference C++ class member 'member,' but it is private or
protected and can't be referenced from this function.
This sometimes happens when you attempt to call one accessible overloaded
member function (or constructor), but the arguments match an inaccessible
function.
The check for overload resolution is always made before checking for
accessibility.
If this is the problem, try an explicit cast of one or more parameters to select the
desired accessible function.
Virtual base class constructors must be accessible within the scope of the most
derived class. This is because C++ always constructs virtual base classes...
more ( see page 351)
E2248: Cannot find default constructor to initialize array element of type 'class' When declaring an array of a class that has constructors, you must either
(C++) ( see page 351) explicitly initialize every element of the array, or the class must have a default
constructor.
The compiler will define a default constructor for a class unless you have defined
any constructors for the class.
E2251: Cannot find default constructor to initialize base class 'class' (C++) ( Whenever a C++ derived class 'class2' is constructed, each base class 'class1' 3
see page 352) must first be constructed.
If the constructor for 'class2' does not specify a constructor for 'class1' (as part of
'class2's' header), there must be a constructor class1::class1() for the base class.
This constructor without parameters is called the default constructor.
The compiler will supply a default constructor automatically unless you have
defined any constructor for class 'class1'.
In that case, the compiler will not supply the default constructor
automatically--you must supply one.
E2252: 'catch' expected (C++) ( see page 352) In a C++ program, a 'try' block must be followed by at least one 'catch' block.
245
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2253: Calling convention must be attributed to the function type, not the closure The calling convention is in the wrong place in the closure declaration. For
(C++) ( see page 352) example,
E2261: Use of dispid with a property requires a getter or setter (C++) ( see This property needs either a getter or a setter.
page 353)
E2262: '__except' or '__finally' expected following '__try' (C++) ( see page 353) In C, a '__try block' must be followed by a '__except' or '__finally' handler block.
E2270: > expected (C++) ( see page 353) A new-style cast (for example, dynamic_cast) was found with a missing closing
">".
E2273: 'main' cannot be declared as static or inline (C++) ( see page 353) You cannot make main static or inline. For example, you cannot use static int
main() or inline int main().
E2281: Identifier1 requires definition of Identifier2 as a pointer type (C++) ( see To use Identifier1, there needs to be a definition for Identifier2, which is a type.
page 353) Example where __classid is the first identifier and TClass, which can be found in
clx.h, is the second one:
E2289: __published or __automated sections only supported for Delphi classes The compiler needs to generate a special kind of vtable for classes containing
(C++) ( see page 353) __published and __automated sections. Therefore, these sections are only
supported for Delphi style classes.
E2298: Cannot generate 'function' from template function 'template' (C++) ( see A call to a template function was found, but a matching template function cannot
page 354) be generated from the function template.
E2301: Cannot use templates in closure arguments -- use a typedef (C++) ( When declaring a closure type, the arguments passed to that closure must be of
see page 354) a simple type. Templates are not accepted. To pass a reference to an object of
template type to a closure, you must declare a typedef, which counts as a simple
type name.
E2307: Type 'type' is not a defined class with virtual functions (C++) ( see page A dynamic_cast was used with a pointer to a class type that is either undefined,
354) or doesn't have any virtual member functions.
E2315: 'Member' is not a member of 'class', because the type is not yet defined The member is being referenced while the class has not been fully defined yet.
(C++) ( see page 354) This can happen if you forward declare class X, declare a pointer variable to X,
and reference a member through that pointer; for example:
E2318: 'type' is not a polymorphic class type (C++) ( see page 354) This error is generated if the -RT compiler option (for runtime type information) is
disabled and either
dynamic_cast was used with a pointer to a class
or
you tried to delete a pointer to an object of a class that has a virtual destructor
E2323: Illegal number suffix (C++) ( see page 355) A numeric literal is followed by a suffix that is not recognized by the compiler.
E2326: Use __declspec(spec1[, spec2]) to combine multiple __declspecs (C++) When you want to use several __declspec modifiers, the compiler will complain if
( see page 355) you don't combine them into one __declspec. For example:
E2328: Classes with properties cannot be copied by value (C++) ( see page This error occurs if you attempt to use the default assignment operator. For
355) example, the following code generates this error given two labels on a form:
E2331: Number of allowable option contexts exceeded (C++) ( see page 355) You have interspersed too many source-code option changes (using #pragma
option) between template declarations. For example:
E2332: Variable 'variable' has been optimized and is not available (C++) ( see You have tried to inspect, watch, or otherwise access a variable which the
page 355) optimizer removed.
This variable is never assigned a value and has no stack location.
E2476: Cannot overload 'function' (C++) ( see page 356) You cannot overload the specified function. This error is displayed if you tried to
declare a function with the same name as another function, but the redeclaration
is not legal. For example, if both functions have the 'extern "C"' linkage type, only
one 'extern "C"' function can have a given name.
E2346: 'x' access specifier of property 'property' must be a member function Only member functions or data members are allowed in access specifications of
(C++) ( see page 356) properties.
E2347: Parameter mismatch in access specifier 'specifier' of property 'property' The parameters of the member function used to access a property don't match
(C++) ( see page 356) the expected parameters.
E2348: Storage specifier not allowed for array properties (C++) ( see page 356) Array properties cannot have a storage specification.
E2351: Static data members not allowed in __published or __automated sections Only nonstatic data members and member functions are allowed in __published
(C++) ( see page 357) or __automated sections.
E2353: Class 'classname' is abstract because of 'member = 0' (C++) ( see This message is issued immediately after the "Cannot create instance of abstract
page 357) class 'classname' error message and is intended to make it easier to figure out
why a particular class is considered abstract by the compiler.
3 For example, consider the following example of an illegal attempt to instantiate
an abstract class:
E2359: Reference member 'member' initialized with a non-reference parameter An attempt has been made to bind a reference member to a constructor
(C++) ( see page 357) parameter. Since the parameter will cease to exist the moment the constructor
returns to its caller, this will not work correctly.
E2369: Cannot use the result of a property assignment as an rvalue' (C++) ( The result of a property assignment is an lvalue. This implies for instance that
see page 358) chained assignments of properties is not allowed; for example, x = y = 5, where
both x and y are properties. Certain embedded assignments of properties can
also produce errors; for example, x != ( y = z ), where y is a property.
246
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
E2370: Simple type name expected (C++) ( see page 358) To ensure interoperability between Delphi and C++, there are restrictions on the
type names mentioned in the parameter lists of published closure types. The
parameter types have to be simple type names with optional const modifier and
pointer or reference notation.
So when declaring a closure type, the arguments passed to that closure must be
of a simple type. For example, templates are not accepted. To pass a reference
to an object of template type to a closure, you must declare a typedef, which
counts as a simple type name.
E2398: Template function argument 'argument' not used in argument types (C++) The given argument was not used in the argument list of the function.
( see page 358) The argument list of a template function must use all of the template formal
arguments; otherwise, there is no way to generate a template function instance
based on actual argument types.
E2419: Error while instantiating template 'template' (C++) ( see page 358) An error occurred during the instantiation of a particular template. This message
always follows some other error message that indicates what actually went
wrong. This message is displayed to help track down which template instantiation
introduced the problem.
E2424: Template class nesting too deep: 'class' (C++) ( see page 358) The compiler imposes a certain limit on the level of template class nesting. This
limit is usually only exceeded through a recursive template class dependency.
When this nesting limit is exceeded, the compiler issues this error message for all
of the nested template classes. This usually makes it easy to spot the recursion.
This error message is always followed by the fatal error "Out of memory".
E2457: Delphi style classes must be caught by reference (C++) ( see page 359) You can only catch a Delphi style object by pointer.
E2458: Delphi classes have to be derived from Delphi classes (C++) ( see You cannot derive a Delphi style class from a non-Delphi style class.
page 359)
E2459: Delphi style classes must be constructed using operator new (C++) ( Delphi style classes cannot be statically defined. They have to be constructed on
see page 359) the heap.
E2460: Delphi style classes require exception handling to be enabled (C++) ( If you are using Delphi style classes in your program, you cannot turn off
see page 360) exception handling (compiler option -x-) when compiling your source code.
E2463: 'base' is an indirect virtual base class of 'class' (C++) ( see page 360) You can't create a pointer to a C++ member of a virtual base class.
You have attempted to create such a pointer (either directly, or through a cast)
and access an inaccessible member of one of your base classes.
Null pointer assignment (C++) ( see page 360) When a small or medium memory model program exits, a check is made to
determine if the contents of the first few bytes within the program's data segment
have changed. These bytes would never be altered by a working program. If they
have been changed, this message is displayed to inform you that (most likely) a
value was stored to an uninitialized pointer.
The program might appear to work properly in all other respects; however, this is
a serious bug which should be attended to immediately. Failure to correct an
uninitialized pointer can lead to unpredictable behavior (including locking the...
more ( see page 360)
E2268: Call to undefined function 'function' (C++) ( see page 360) Your source file declared the current function to return some type other than
void in C++ (or int in C), but the compiler encountered a return with no value.
All int functions are exempt in C because in old versions of C, there was no
void type to indicate functions that return nothing.
E2375: Assembler stack overflow (C++) ( see page 360) The assembler ran out of memory during compilation. Review the portion of code
flagged by the error message to ensure that it uses memory correctly.
Initializing enumeration with type (C++) ( see page 360) You're trying to initialize an enum variable to a different type. For example,
<name> is not a valid identifier (C++) ( see page 361) The identifier name is invalid. Ensure that the first character is a letter or an
underscore (_). The characters that follow must be letters, digits, or underscores,
and there can not be any spaces in the identifier.
Example for "Temporary used ..." error messages (C++) ( see page 361) In this example, function f requires a reference to an int, and c is a char:
Application is running (C++) ( see page 361) The application you tried to run is already running.
For Windows, make sure the message loop of the program has properly
terminated.
Printf/Scanf floating-point formats not linked (C++) ( see page 361) Floating-point formats contain formatting information that is used to manipulate
floating-point numbers in certain runtime library functions, such as scanf() and
atof(). Typically, you should avoid linking the floating-point formats (which take up
about 1K) unless they are required by your application. However, you must 3
explicitly link the floating-point formats for programs that manipulate fields in a
limited and specific way.
Refer to the following list of potential causes (listed from most common to least
common) to determine how to resolve this error:
247
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
W8000: Ambiguous operators need parentheses (C++) ( see page 362) (Command-line option to display warning: -wamb)
This warning is displayed whenever two shift, relational, or bitwise-Boolean
operators are used together without parentheses.
Also, an addition or subtraction operator that appears without parentheses with a
shift operator will produce this warning.
W8060: Possibly incorrect assignment (C++) ( see page 362) (Command-line option to suppress warning: -w-pia)
This warning is generated when the compiler encounters an assignment operator
as the main operator of a conditional expression (part of an if, while, or do-while
statement).
This is usually a typographical error for the equality operator.
If you want to suppress this warning, enclose the assignment in parentheses and
compare the whole thing to zero explicitly.
For example, this code
W8002: Restarting compile using assembly (C++) ( see page 362) (Command-line option to suppress warning: -w-asc)
The compiler encountered an asm with no accompanying or #pragma inline
statement.
The compile restarts using assembly language capabilities.
Default = On
W8003: Unknown assembler instruction (C++) ( see page 362) (Command-line option to suppress warning: -w-asm)
The compiler encountered an inline assembly statement with a disallowed
opcode or an unknown token. Check the spelling of the opcode or token.
Note:You will get a separate error message from the assembler if you entered
illegal assembler source code.
This warning is off by default.
W8052: Base initialization without a class name is now obsolete (C++) ( see (Command-line option to suppress warning: -w-obi)
page 362) Early versions of C++ provided for initialization of a base class by following the
constructor header with just the base class constructor parameter list.
It is now recommended to include the base class name.
This makes the code much clearer, and is required when you have multiple base
classes.
Old way
E2117: Bit fields must be signed or unsigned int (C++) ( see page 363) (Command-line option to display warning: -wbbf)
In ANSI C, bit fields may not be of type signed char or unsigned char.
When you're not compiling in strict ANSI mode, the compiler allows these
constructs, but flags them with this warning.
W8064: Call to function with no prototype (C++) ( see page 363) (Command-line option to suppress warning: -w-pro)
This message is given if the "Prototypes required" warning is enabled and you
call a function without first giving a prototype for that function.
W8065: Call to function 'function' with no prototype (C++) ( see page 363) This message is given if the "Prototypes required" warning is enabled and you
call function 'function' without first giving a prototype for that function.
W8009: Constant is long (C++) ( see page 363) (Command-line option to display warning: -wcln)
The compiler encountered one of the following:
248
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
W8010: Continuation character \ found in // comment (C++) ( see page 364) (Command-line option to suppress warning: -w-com)
This warning message is issued when a C++ // comment is continued onto the
next line with backslash line continuation.
The intention is to warn about cases where lines containing source code
unintentionally become part of a comment because that comment happened to
end in a backslash.
If you get this warning, check carefully whether you intend the line after the //
comment to be part of the comment. If you don't, either remove the backslash or
put some other character after it. If you do, it's probably better coding style to
start the... more ( see page 364)
W8080: 'identifier' is declared but never used (C++) ( see page 364) (Command-line option to display warning: -wuse)
The specified identifier was never used. This message can occur in the case of
either local or static variables. It occurs when the source file declares the named
local or static variable as part of the block just ending, but the variable was never
used.
In the case of local variables, this warning occurs when the compiler encounters
the closing brace of the compound statement or function. In the case of static
variables, this warning occurs when the compiler encounters the end of the
source file.
For example:
W8014: Declaration ignored (C++) ( see page 365) (Command-line option to suppress warning: -w-dig)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
Default = On
W8068: Constant out of range in comparison (C++) ( see page 365) (Command-line option to suppress warning: -w-rng)
Your source file includes a comparison involving a constant sub-expression that
was outside the range allowed by the other sub-expression's type.
For example, comparing an unsigned quantity to -1 makes no sense.
To get an unsigned constant greater than 32,767 (in decimal), you should either
249
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
W8007: Hexadecimal value contains more than three digits (C++) ( see page (Command-line option to suppress warning = -w-big)
366) Under older versions of C, a hexadecimal escape sequence could contain no
more than three digits.
The ANSI standard allows any number of digits to appear as long as the value
fits in a byte.
This warning results when you have a long hexadecimal escape sequence with
many leading zero digits (such as \x00045).
Older versions of C would interpret such a string differently.
W8024: Base class 'class1' is also a base class of 'class2' (C++) ( see page (Command-line option to suppress warning: -w-ibc)
366) A class inherits from the same base class both directly and indirectly. It is best to
avoid this non-portable construct in your program code.
W8022: 'function1' hides virtual function 'function2' (C++) ( see page 367) (Command-line option to suppress warning: -w-hid)
A virtual function in a base class is usually overridden by a declaration in a
derived class.
In this case, a declaration with the same name but different argument types
makes the virtual functions inaccessible to further derived classes.
W8023: Array variable 'identifier' is near (C++) ( see page 367) (Command-line option to suppress warning: -w-ias)
When you use set the Far Data Threshold option, the compiler automatically
makes any global variables that are larger than the threshold size be far.
When the variable is an initialized array with an unspecified size, its total size is
not known when the compiler must decide whether to make it near or far, so the
compiler makes it near.
The compiler issues this warning if the number of initializers given for the array
causes the total variable size to exceed the data size threshold.
If the fact that the compiler made the variable... more ( see page 367)
W8061: Initialization is only partially bracketed (C++) ( see page 367) (Command-line option to display warning: -wpin)
When structures are initialized, braces can be used to mark the initialization of
each member of the structure. If a member itself is an array or structure, nested
pairs of braces can be used. This ensures that the compiler's idea and your idea
of what value goes with which member are the same. When some of the optional
braces are omitted, the compiler issues this warning.
W8038: constant member 'identifier' is not initialized (C++) ( see page 367) (Command-line option to suppress warning: -w-nci)
This C++ class contains a constant member 'member' that doesn't have an
initialization.
Note that constant members can be initialized only; they can't be assigned to.
W8071: Conversion may lose significant digits (C++) ( see page 367) (Command-line option to display warning: -wsig)
For an assignment operator or some other circumstance, your source file
requires a conversion from a larger integral data type to a smaller integral data
type where the conversion exists.
Because the integral data type variables don't have the same size, this kind of
conversion might alter the behavior of a program.
W8043: Macro definition ignored (C++) ( see page 368) (Command-line option to suppress warning: -w-nma)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
W8017: Redefinition of 'x' is not identical (C++) ( see page 368) (Command-line option to suppress warning: -w-dup)
Your source file redefined the macro 'ident' using text that was not exactly the
same as the first definition of the macro.
The new text replaces the old.
W8079: Mixing pointers to different 'char' types (C++) ( see page 368) (Command-line option to display warning: -wucp)
You converted a signed char pointer to an unsigned char pointer, or vice versa,
without using an explicit cast. (Strictly speaking, this is incorrect, but it is often
harmless.)
W8067: Both return and return with a value used (C++) ( see page 368) (Command-line option to suppress warning: -w-ret)
The current function has return statements with and without values.
This is legal C, but almost always generates an error.
Possibly a return statement was omitted from the end of the function.
3 W8048: Use qualified name to access member type 'identifier' (C++) ( see (Command-line option to suppress warning: -w-nst)
page 368) In previous versions of the C++ specification, typedef and tag names declared
inside classes were directly visible in the global scope.
In the latest specification of C++, these names must be prefixed with
class::qualifier if they are to be used outside of their class scope.
The compiler issues this warning whenever a name is uniquely defined in a
single class. The compiler permits this usage without class::. This allows older
versions of code to compile.
250
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
W8039: Constructor initializer list ignored (C++) ( see page 368) (Command-line option to suppress warning: -w-ncl)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
W8040: Function body ignored (C++) ( see page 369) (Command-line option to suppress warning: -w-nfd)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
W8042: Initializer for object 'x' ignored (C++) ( see page 369) (Command-line option to suppress warning: -w-nin)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
W8044: #undef directive ignored (C++) ( see page 369) (Command-line option to suppress warning: -w-nmu)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
W8037: Non-const function 'function' called for const object (C++) ( see page (Command-line option to suppress warning = -w-ncf)
369) A non-const member function was called for a const object.
(This is an error, but was reduced to a warning to give existing programs a
chance to work.)
W8051: Non-volatile function 'function' called for volatile object (C++) ( see (Command-line option to suppress warning: -w-nvf)
page 369) In C++, a class member function was called for a volatile object of the class type,
but the function was not declared with volatile following the function header. Only
a volatile member function can be called for a volatile object.
For example, if you have
W8019: Code has no effect (C++) ( see page 370) (Command-line option to suppress warning: -w-eff)
This warning is issued when the compiler encounters a statement with some
operators that have no effect.
For example, the statement
W8057: Parameter 'parameter' is never used (C++) ( see page 370) (Command-line option to suppress warning: -w-par)
The named parameter, declared in the function, was never used in the body of
the function.
This might or might not be an error and is often caused by misspelling the
parameter.
This warning can also occur if the identifier is redeclared as an automatic (local)
variable in the body of the function.
The parameter is masked by the automatic variable and remains unused.
W8070: Function should return a value (C++) ( see page 370) (Command-line option to suppress warning: -w-rvl)
This function was declared (maybe implicitly) to return a value.
The compiler found a return statement without a return value, or it reached the
end of the function without finding a return statement.
Either return a value or change the function declaration to return void.
W8047: Declaration of static function function ignored (C++) ( see page 370) (Command-line option to suppress warning: -w-nsf)
An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.
W8041: Negating unsigned value (C++) ( see page 370) (Command-line option to suppress warning: -w-ngu)
Basically, it makes no sense to negate an unsigned value because the result will
still be unsigned.
W8054: Style of function definition is now obsolete (C++) ( see page 371) (Command-line option to suppress warning = -w-ofp)
In C++, this old C style of function definition is illegal:
W8025: Ill-formed pragma (C++) ( see page 371) (Command-line option to suppress warning: -w-ill)
A pragma does not match one of the pragmas expected by the compiler.
W8063: Overloaded prefix operator 'operator' used as a postfix operator (C++) (Command-line option to suppress warning: -w-pre)
( see page 371) The C++ specification allows you to overload both the prefix and postfix versions
of the ++ and -- operators.
Whenever the prefix operator is overloaded, but is used in a postfix context, the
compiler uses the prefix operator and issues this warning.
This allows older code to compile.
W8015: Declare 'type' prior to use in prototype (C++) ( see page 371) (Command-line option to suppress warning: -w-dpu) 3
When a function prototype refers to a structure type that has not previously been
declared, the declaration inside the prototype is not the same as a declaration
outside the prototype.
For example,
W8069: Nonportable pointer conversion (C++) ( see page 372) (Command-line option to suppress warning: -w-rpt)
A nonzero integral value is used in a context where a pointer is needed or where
an integral value is needed; the sizes of the integral type and pointer are the
same.
Use an explicit cast if this is what you really meant to do.
251
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
W8066: Unreachable code (C++) ( see page 372) (Command-line option to suppress warning: -w-rch)
A break, continue, goto, or return statement was not followed by a label or the
end of a loop or function.
The compiler checks while, do, and for loops with a constant test condition, and
attempts to recognize loops that can't fall through.
W8029: Temporary used for parameter '???' (C++) ( see page 372) (Command-line option to suppress warning: -w-lvc)
In C++, a variable or parameter of reference type must be assigned a reference
to an object of the same type. If the types do not match, the actual value is
assigned to a temporary of the correct type, and the address of the temporary is
assigned to the reference variable or parameter.
The warning means that the reference variable or parameter does not refer to
what you expect, but to a temporary variable, otherwise unused.
In the following example, function f requires a reference to an int, and c is a char:
W8031: Temporary used for parameter 'parameter' OR W8029 Temporary used (Command-line option to suppress warning: -w-lvc)
for parameter 'number' OR W8030 Temporary used for parameter 'parameter' in In C++, a variable or parameter of reference type must be assigned a reference
call to 'function' OR W8032 Temporary used for parameter 'number' in call to to an object of the same type.
'function' (C++) ( see page 372) If the types do not match, the actual value is assigned to a temporary of the
correct type, and the address of the temporary is assigned to the reference
variable or parameter.
The warning means that the reference variable or parameter does not refer to
what you expect, but to a temporary variable, otherwise unused.
W8032: Temporary used for parameter 2 in call to '???' (C++) ( see page 373) (Command-line option to suppress warning: -w-lvc)
In C++, a variable or parameter of reference type must be assigned a reference
to an object of the same type. If the types do not match, the actual value is
assigned to a temporary of the correct type, and the address of the temporary is
assigned to the reference variable or parameter.
The warning means that the reference variable or parameter does not refer to
what you expect, but to a temporary variable, otherwise unused.
In the following example, function f requires a reference to an int, and c is a char:
W8028: Temporary used to initialize 'identifier' (C++) ( see page 373) (Command-line option to suppress warning: -w-lin)
In C++, a variable or parameter of reference type must be assigned a reference
to an object of the same type.
If the types do not match, the actual value is assigned to a temporary of the
correct type, and the address of the temporary is assigned to the reference
variable or parameter.
The warning means that the reference variable or parameter does not refer to
what you expect, but to a temporary variable, otherwise unused.
Example
In this example, function f requires a reference to an int, and c is a char:
W8074: Structure passed by value (C++) ( see page 373) (Command-line option to display warning: -wstv)
This warning is generated any time a structure is passed by value as an
argument.
It is a frequent programming mistake to leave an address-of operator (&) off a
structure when passing it as an argument.
Because structures can be passed by value, this omission is acceptable.
This warning provides a way for the compiler to warn you of this mistake.
W8011: Nonportable pointer comparison (C++) ( see page 374) (Command-line option to suppress warning: -w-cpt)
Your source file compared a pointer to a non-pointer other than the constant 0.
You should use a cast to suppress this warning if the comparison is proper.
W8075: Suspicious pointer conversion (C++) ( see page 374) (Command-line option to suppress warning: -w-sus)
The compiler encountered some conversion of a pointer that caused the pointer
to point to a different type.
You should use a cast to suppress this warning if the conversion is proper.
A common cause of this warning is when the C compiler converts a function
pointer of one type to another (the C++ compiler generates an error when asked
to do that). It can be suppressed by doing a typecast. Here is a common
occurrence of it for Windows programmers:
3
W8059: Structure packing size has changed (C++) ( see page 374) (Command-line option to suppress warning: -w-pck)
This warning message is issued when the structure alignment is different after
including a file than it was before including that file.
The intention is to warn you about cases where an include file changes structure
packing, but by mistake doesn't restore the original setting at the end. If this is
intentional, you can give a #pragma nopackwarning directive at the end of an
include file to disable the warning for this file.
The warning can be disabled altogether by #pragma warn -pck.
252
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
W8045: No declaration for function 'function' (C++) ( see page 374) (Command-line option to display warning: -wnod)
This message is given if you call a function without first declaring that function.
In C, you can declare a function without presenting a prototype, as in
W8073: Undefined structure 'structure' (C++) ( see page 375) (Command-line option to display warning = -wstu)
Your source file used the named structure on some line before where the error is
indicated (probably on a pointer to a structure) but had no definition for the
structure.
This is probably caused by a misspelled structure name or a missing declaration.
W8013: Possible use of 'identifier' before definition (C++) ( see page 375) (Command-line option to display warning: -wdef)
Your source file used the variable 'identifier' in an expression before it was
assigned a value.
The compiler uses a simple scan of the program to determine this condition.
If the use of a variable occurs physically before any assignment, this warning will
be generated.
Of course, the actual flow of the program can assign the value before the
program uses it.
W8004: 'identifier' is assigned a value that is never used (C++) ( see page 375) (Command-line option to suppress warning: -w-aus)
The variable appears in an assignment, but is never used anywhere else in the
function just ending.
The warning is indicated only when the compiler encounters the closing brace.
The #pragma warn -aus switch has function-level granularity. You cannot turn
off this warning for individual variables within a function; it is either off or on for
the whole function.
W8081: Void functions may not return a value (C++) ( see page 375) (Command-line option to suppress warning: -w-voi)
Your source file declared the current function as returning void, but the compiler
encountered a return statement with a value. The value of the return statement
will be ignored.
W8078: Throw expression violates exception specification (C++) ( see page (Command-line option to suppress warning: -w-thr)
376) This warning happens when you add an exception specification to a function
definition and you throw a type in your function body that is not mentioned in your
exception specification.
The following program would generate this warning:
W8021: Handler for 'type1' hidden by previous handler for 'type2' (C++) ( see (Command-line option to suppress warning: -w-hch)
page 376) This warning is issued when a handler for a type 'D' that is derived from type 'B'
is specified after a handler for B', since the handler for 'D' will never be invoked.
W8056: Integer arithmetic overflow (C++) ( see page 376) The compiler detected an overflow condition in an integer math expression.
For example:
W8035: User-defined message (C++) ( see page 376) The error message for which you have requested Help is a user-defined warning.
In C++ code, user-defined messages are introduced by using the #pragma
message compiler syntax.
Note:In addition to messages that you introduce with the #pragma message
compiler syntax, user-defined warnings can be introduced by third party libraries.
Should you require Help about a third party warning, please contact the vendor of
the header file that issued the warning.
W8049: Use '> >' for nested templates Instead of '>>' (C++) ( see page 376) (Command-line option to suppress warning: -w-ntd)
Whitespace is required to separate the closing ">" in a nested template name,
but since it is an extremely common mistake to leave out the space, the compiler
accepts a ">>" with this warning.
W8026: Functions with exception specifications are not expanded inline (C++) ( Also:Functions taking class by value arguments are not expanded inline
see page 377) (Command-line option to suppress warning: -w-inl)
Exception specifications are not expanded inline: Check your inline code for lines
containing exception specification.
Functions taking class-by-value argument(s) are not expanded inline: When
exception handling is enabled, functions that take class arguments by value
cannot be expanded inline.
Note:Functions taking class parameters by reference are not subject to this
restriction. 3
253
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
W8058: Cannot create pre-compiled header: 'reason' (C++) ( see page 377) (Command-line option to suppress warning: -w-pch)
This warning is issued when pre-compiled headers are enabled but the compiler
could not generate one, for one of the following reasons:
ReasonExplanation
write failedThe compiler could not write to the pre-compiled header file. This
occurs if you specified an invalid location to cache precompiled headers or if the
disk is full.
code in headerOne of the headers contained a non-inline function body.
initialized data in headerOne of the headers contained a global variable definition
(in C, a global variable with an initializer; in C++ any variable not declared as
'extern').
header incompleteThe... more ( see page 377)
W8046: Pragma option pop with no matching option push (C++) ( see page The compiler encountered a #pragma option pop before a previous #pragma
377) option push, or in the case of nesting, there are more occurrences of #pragma
option pop than of #pragma option push.
W8050: No type OBJ file present; disabling external types option. (C++) ( see (Command-line option to suppress warning: -w-nto)
page 377) A precompiled header file references a type object file, but the type object file
cannot be found. This is not a fatal problem but will make your object files larger
than necessary.
W8027: Functions containing 'statement' are not expanded inline (C++) ( see (Command-line option to suppress warning: -w-inl)
page 378) Where:
'statement' can be any of the following:
• Static variables
• Aggregate initializers
• Some return statements
• Local destructors
• Some if statements
• Local classes
• Missing return statements
• Disallowed reserved words listed under "Reserved words"
below.
Reserved words
Functions containing any of these reserved words can't be
expanded inline, even when specified as inline:
W8036: Non-ANSI keyword used: 'keyword' (C++) ( see page 378) (Command-line option to display warning: -wnak)
A non-ANSI keyword (such as '__fastcall') was used when strict ANSI
conformance was requested via the -A option.
W8053: 'ident' is obsolete (C++) ( see page 379) (Command-line option to suppress warning: -w-obs)
Issues a warning upon usage for any "C" linkage function that has been
specified. This will warn about functions that are "obsolete".
Here's an example of it's usage:
W8103: Path 'path' and filename 'filename' exceed maximum size of 'n' (C++) ( (Command-line option to display warning: -wstv)
see page 379) In looking up include files, the C++ compiler has encountered a file whose path
and filename contain more characters than are allowed in the Windows
maximum. Rename the paths and filenames that you can, and shorten their
names wherever possible.
W8062: Previous options and warnings not restored (C++) ( see page 379) The compiler didn't encounter a #pragma option pop after a previous #pragma
option push, or in the case of nesting, there are more occurrences of #pragma
3 option push than of #pragma option pop.
W8055: Possible overflow in shift operation (C++) ( see page 379) The compiler detects cases where the number of bits shifted over is larger than
the number of bits in the affected variable; for example:
W8072: Suspicious pointer arithmetic (C++) ( see page 379) This message indicates an unintended side effect to the pointer arithmetic (or
array indexing) found in an expression.
254
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
W8033: Conversion to 'type' will fail for members of virtual base 'class' (C++) ( (Command-line option to suppress warning: -w-mpc)
see page 380) This warning is issued only if the -Vv option is in use.
The warning may be issued when a member pointer to one type is cast to a
member pointer of another type and the class of the converted member pointer
has virtual bases.
Encountering this warning means that at runtime, if the member pointer
conversion cannot be completed, the result of the cast will be a NULL member
pointer.
W8034: Maximum precision used for member pointer type 'type' (C++) ( see (Command-line option to suppress warning: -w-mpd)
page 380) When a member pointer type is declared, its class has not been fully defined, and
the -Vmd option has been used, the compiler has to use the most general (and
the least efficient) representation for that member pointer type. This can cause
less efficient code to be generated (and make the member pointer type
unnecessarily large), and can also cause problems with separate compilation;
see the -Vm compiler switch for details.
E2537: Cannot create instance of abstract class (C++) ( see page 380) This class is an abstract class, which you cannot instantiate.
E2018: Cannot catch 'identifier' -- ambiguous base class 'identifier' (C++) ( see It is not legal to catch a class that contains more than one copy of a (non-virtual)
page 380) base class. However, you can catch the exception as a more derived type. For
example:
E2550: No arguments can follow a variadic template in an argument list (C++) In an argument list, the variadic template must not be followed by arguments.
( see page 381)
E2538: Static assert failed: '%s' (C++) ( see page 381) See Static Assertions ( see page 498) for details about how to use
static_assert., which is one of the C++0x features.
E2548: ... was unexpected; expression is not a variadic template pattern (C++) This message pertains to the expected syntax of variadic templates.
( see page 381)
E2543: Combination of options 'options' is not permitted (C++) ( see page 381) Eliminate the combination of options.
For example, you cannot combine the C++ compiler options -b- and -bi because
-b- turns off all -b options, including -bi.
E2549: Operand is not a parameter pack (C++) ( see page 381) A parameter pack is required in the indicated location. This message pertains to
variadic templates.
E2544: Function exception specifications do not match (C++) ( see page 381) The throw specifications on two function declaration/definitions which refer to the
same function do not agree. Rewrite the function exception specifications to
match.
E2536: Incomplete type cannot be part of a exception declaration (C++) ( see This error occurs when an incomplete type is used in exception declaration. From
page 381) C++ ISO 14882:1998 15.3.1: "The exception-declaration shall not denote an
incomplete type. The exception-declaration shall not denote a pointer or
reference to an incomplete type, other than void*, const void*, volatile void*, or
const volatile void*. Types shall not be defined in an exception-declaration.
E2535: Incomplete type cannot be part of a throw specification (C++) ( see This error occurs when an incomplete type is used in a throw specification. From
page 382) C++ ISO 14882:1998 15.1.3: "The type of the throw-expression shall not be an
incomplete type, or a pointer or reference to an incomplete type, other than void*,
const void*, volatile void*, or const volatile void*." This includes exception
specifications (15.4.1).
E2532: Constant in new expression requires an initializer (C++) ( see page If the type is const then either an initializer must be present or the non-POD class
382) must have a user-declared constructor. Error in ANSI mode, warning if ANSI
mode is not set.
E2541: Attribute '%s' cannot be set (C++) ( see page 382) This error occurs if the specified attribute cannot be applied to this entity.
E2545: Enum underlying type must be an integral (C++) ( see page 382) Ensure that the underlying type of the enumeration is an integral type.
The underlying type of a scoped enum is fixed to int unless explicitly provided by
the user. The underlying type of a 'classic' enum remains unspecified unless
fixed by the user.
For more information, see Strongly Typed Enums ( see page 498).
E2546: Redeclaration of enum is not identical (C++) ( see page 382) This error occurs if:
255
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
E2534: Integral constant expression expected (C++) ( see page 382) Integral constant expressions are described in section 5.19 of the C++ standard,
and are sometimes referred to as "compile time constants". A working draft for
the C++ standard can be found at
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf.
E2531: Parameter is an incomplete type (C++) ( see page 383) This error occurs when an incomplete type is passed into a type trait function that
does not accept incomplete type parameters. For example:
E2539: Constant expression expected (C++) ( see page 383) You need to supply a constant expression in the indicated location.
For details about using a constant expression in a static assertion, see Static
Assertions ( see page 498).
E2547: ... expected (C++) ( see page 383) An ellipsis (...) is expected in the location indicated.
E2540: String literal expected (C++) ( see page 383) You need to specify a string literal in the position indicated in the error message.
A string literal is the second argument in a static assertion. For details about
using a static assertion, see Static Assertions ( see page 498).
E2552: This feature is not (yet) supported (C++) ( see page 383) Support might be added in a coming release.
E2542: '%s' is marked 'final' and cannot be overriden (C++) ( see page 383) The attribute 'final' applies to class definitions and to virtual member functions
being declared in a class definition. If the attribute is specified for a class
definition, it is equivalent to being specified for each virtual member function of
that class, including inherited member functions. If a virtual member function f in
some class B is marked 'final' and in a class D derived from B, a function D::f
overrides B::f, the program is ill-formed.
E2553: %s mismatch in redeclaration of '%s' (C++) ( see page 383) Attributes specified on a declaration have to be a subset of attributes specified on
a definition.
E2551: Return statement not allowed in __finally block (C++) ( see page 384) Rewrite the __finally block so that it does not contain a return statement.
For more information, see Writing a finally Block in C++ ( see page 2023) and
finally keyword ( see page 550).
W8104: Local Static with constructor dangerous for multi-threaded apps (C++) (Command-line option to suppress warning: -w-mls)
( see page 384) This warning is generated for local static objects with constructors for
multithreaded programs. This situation can cause problems if two threads enter
the containing function at the same time and no critical sections are present,
allowing the constructor to potentially be called more than once.
W8106: %s are deprecated (C++) ( see page 384) You have used an old style syntax or language use that is deprecated -- that is,
no longer recommended and might be phased out in the future.
W8110: Duplicate '%s' attribute directive ignored (C++) ( see page 384) (Command-line option to suppress warning: -w-dat)
This warning is generated if the same attribute was specified more than once for
the same entity.
W8108: Constant in new expression requires an initializer (C++) ( see page (Command-line option to suppress warning: -w-nci)
384) If the type is const then either an initializer must be present or the non-POD class
must have a user-declared constructor. Error in ANSI mode, warning if ANSI
mode is not set.
W8113: Inline function was declared with 'extern template' (C++) ( see page (Command-line option to suppress warning: -w-iex)
384) 'extern template' has no normative effect on inline functions. Implementations are
encouraged to suppress out-of-line copies of inline functions that were declared
with 'extern template'.
W8109: Parameter '%s' is a dependent type (C++) ( see page 385) (Command-line option to enable warning: -wpad)
This warning is generated if a parameter of an intrinsic function is a dependent
type and the dependency cannot be resolved.
W8105: Reference/Constant member 'identifier' in class without constructors (Command-line option to suppress warning: -w-mnc)
(C++) ( see page 385) This warning is generated for a reference or constant member in a class without
constructors if ANSI mode is not set. In ANSI mode this is an error.
W8107: Type name expected (C++) ( see page 385) (Command-line option to enable warning: -wntn)
This warning is generated if the type of a class/union member is omitted in its
declaration and ANSI mode is not set. Always an error in ANSI mode.
W8112: Unresolved dependencies in expression (C++) ( see page 385) (Command-line option to suppress warning: -w-dex)
This warning is generated if dependencies in the expression cannot be resolved.
3
3.1.2.1 E2066: Invalid MOM inheritance (C++)
The compiler issues this error if the currently compiled class doesn't have the same MOM (Microsoft Object Model) related flags
set as its direct parent.
256
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example
struct__declspec(delphiclass) clxclass{int__fastcall Getter1(void); int__cdecl
Getter2(void); __published:int __property ip1 = {read = Getter1}; // OKint __property ip2 =
{read = Getter2}; // Error};
You may also see this message in the watches window because it also displays the results of evaluating an expression.
257
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example, if an array dimension is dependent upon a template parameter but an error occurs while it is being parsed and the
template argument being substituted does not yield a legal constant expression, this error is displayed.
For example, if a source file contains a #pragma option push —v, you need to remove the push or set /unset this option
either on the command line or in a .cfg file.
3
3.1.2.13 E2528: Option 'name' must be set before compilation begins
(C++)
An attempt was made in a source file to set an option that must be set before compiling starts. Instead, set this option on the
command line, in a .cfg file, or at the top of the source file before the line int foo(); .
258
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
For example:
class myClass
{
int X;
public:
int __property x = { read=getx, write=putx };
int getx() { return X; }
void putx(int val) { X = val; }
} OneClass;
int value(int);
int main()
{
return value(OneClass.x = 4); // This causes an error
}
259
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
260
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
261
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
unexpected import directive value attribute 'attribute'A value was supplied for the indicated attribute. None was expected.
missing ')' in import directive attribute 'attribute'The value for the indicated attribute was incorrectly specified : a closing
parenthesis is missing.
unrecognized import directive attribute 'attribute'The indicated token is not a legitimate attribute for the #import directive.
invalid values for raw_property_prefixes attributeThe values for the raw_property_prefixes attribute were incorrectly specified.
unexpected duplicate property 'property'The indicated #import attribute was specified more than once -- this is an error.
unexpected duplicate get method for property 'property'The get method for the indicated property was specified more than once.
unexpected duplicate put method for property 'property'The put method for the indicated property was specified more than once.
unexpected duplicate put-reference method for property 'property'The put-reference method for the indicated property was
specified more than once.
no return value specified for property get method 'method'The indicated property get method does not supply the correct return
type.
no return value specified for property put method 'method'The indicated property put method does not supply the correct return
type.
could not load type library in 'filename'The indicated type library could not be opened.
could not obtain type library nameThe compiler could not obtain obtain a library name for the current type library
See Also
#include ( see page 692)
3 and the file you are trying to import doesn't exist or can't be found by the compiler.
262
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
One way this could happen is if a program has more than 16384 functions.
263
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Example
struct__declspec(delphiclass) vclclass1
{
~vclclass1() {} // Error
};
struct__declspec(delphiclass) vclclass2
{
virtual ~vclclass2() {} // OK
};
264
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
In the example below, the template member 'a' has type 'T'. If the template is instantiated with T as a function type, it implies that
'a' is therefore a member function. This is not allowed and the error message is displayed.
template<T& x> class foo { T a; }
int func(int);
template class foo<func>;
265
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example:
266
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
3.1.2.54 E2512: Cannot emit RTTI for return type of 'function' (C++)
The compiler issues this error if the it cannot generate RTTI information for the return type of a function. See Runtime type
information for more information.
267
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
268
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
template<class T>
class foo;
template<class T>
class foo<T *>; // OK: is more specialized than primary template
template<class T>
class foo<T>; // error: identical to primary template
269
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
270
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
3.1.2.71 E2402: Illegal base class type: formal type 'type' resolves to
'type' (C++)
When instantiating a template class definition, if it is found that a declared base class does not resolve to an accessible class
type, this error will result. For example:
template<class T>
class foo : public T { };
foo<int> x;// error: "int" is not a valid base class
foo<bar> y;// error: "bar" is an unknown type
271
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
272
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
3
3.1.2.83 E2414: Destructors cannot be declared as template
functions (C++)
Destructors cannot be templates. For example:
class foo {
template<class T>
virtual ~foo();// error: don't try this at home!
273
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
};
274
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
class foo { };
template class foo<char>;// OK: at global scope
int main() {
template class foo<int>:// error: local scope
}
275
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
template<class T>
class foo;
template<>
class foo<char>;// OK: "template<>" was provided
class foo<int>;// error: "template<>" required
This error message should not occur because it has been replaced with another one (E2475).
276
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
277
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
template<class T>
class foo;
template<template<class T> class U = foo>
class bar;// OK: "foo" is a qualifying primary template
template<template<class T> class U = int>
class baz;// error: "int" is not a template class
278
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
279
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
You will receive this warning if you don't use pragma alias correctly. For example, the following two lines both generate this
warning:
#pragma alias foo=bar
#pragma alias "foo" = bar
See the “#pragma alias” reference below for information on this pragma's usage.
See Also
#pragma ( see page 696)
Consider:
static void main(int argc, char**argv)
{
}
The above is valid C syntax, but cannot actually be called as the startup routine since it has been declared static.
280
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
• user
• lib
• exestr
• linker
The type should be there but the string is optional.
281
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
#pragma code_seg(foo)
#pragma code_seg(foo, bar)
For example:
#pragma pack( push )
#pragma pack( push )
#pragma pack( pop )
#pragma pack( pop )
#pragma pack( pop ) // This causes an error
3.1.2.125 W8097: Not all options can be restored at this time (C++)
Your program has a #pragma pop at a place where it can't restore options.
For example:
#pragma option push -v
int main()
{
int i;
i = 1;
#pragma option pop
return i;
}
For this example, compile with -v-. The message happens because the first #pragma causes debug info to change state (turns it
on). Then, in the middle of the function where it is useless to toggle the debug info state, the #pragma pop attempts to return to
the former state.
For example, compile the following code using the –w command line option:
int j, k, l;
int main()
{
return j < k & l; // This causes an error
}
3 //
282
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
For example, if you were trying to instantiate a class type "vector<blah>", the error would be:
'blah::operator<' must be publicly visible to be contained by a 'vector'
If –A is not enabled and an attempt is made to explicitly instantiate a specialization which has already been either implicitly or
explicitly instantiated, this error will result.
283
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This error also occurs if the output directory does not exist.
Solutions
If the disk is full, try deleting unneeded files and restarting the compilation.
If the disk is write-protected, move the source files to a writeable disk and restart the compilation.
284
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Check the spelling of the name. Make sure the file is on the specified disk or directory.
Verify that the proper directory paths are listed. If multiple paths are required, use a semicolon to separate them.
An expression on the indicated line of the source file was so complicated that the code generator could not generate code for it.
Solutions
Simplify the expression. If this does not solve the problem, avoid the expression.
Solutions
Make sure that the Output directory in the Directories dialog box is a valid directory.
3
3.1.2.145 F1000: Compiler table limit exceeded (C++)
One of the compiler's internal tables overflowed.
This usually means that the module being compiled contains too many function bodies.
This limitation will not be solved by making more memory available to the compiler. You need to simplify the file being compiled.
285
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
• Not enough virtual memory is available for compiling a particular file. In this case, shut down any other concurrent
applications. You may also try to reconfigure your machine for more available virtual memory, or break up the source file
being compiled into smaller separate components. You can also compile the file on a system with more available RAM.
• The compiler has encountered an exceedingly complex or long expression at the line indicated and has insufficient reserves
to parse it. Break the expression down into separate statements.
Make sure the file is on the specified disk or directory. Verify the proper paths are listed. If multiple paths are required, use a
semicolon to separate them.
286
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Try changing the order of parameters or the type of a parameter in one declaration.
In C++ class 'class', member 'member' can be found in more than one base class, and it was not qualified to indicate which one
you meant.
This applies only in multiple inheritance, where the member name in each base class is not hidden by the same member name
in a derived class on the same path.
The C++ language rules require that this test for ambiguity be made before checking for access rights (private, protected, public).
It is possible to get this message even though only one (or none) of the members can be accessed.
287
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
If you need an array of this size, either use the 'huge' modifier, like this:
int huge array[70000L]; /* Allocate 140000 bytes */
or dynamically allocate it with farmalloc( ) or farcalloc( ), like this:
int huge *array = (int huge *) farmalloc (sizeof (int) * 70000); ?? Allocate 140,000 bytes
This practice is no longer allowed, because a better, safer, and more general technique is to define a member function operator
new instead.
For example:
this = malloc(n);
288
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
clxclass() {}// Error
};
Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
int__cdecl barInt(int);// Error
};
Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
intmemInt;// Error
};
289
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Example
struct__declspec(delphiclass) clxbaseclass
{
int __fastcall Get(void);
void __fastcall Set(int);
int __property ip1 = { read = Get, write = Set };
};
structclxderivedclass : clxbaseclass
{
int __fastcall NewGetter(void);
__automated:
__property ip1;// Error
int __property ip2 = { read = Get, write = Set }; // OK
};
In either case, it must be something to which the -> operator can be applied.
In C++, you cannot cast a member function pointer to a normal function pointer.
290
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
For example:
class A {
public:
int myex();
};
typedef int (*fp)();
test()
{
fp myfp = (fp) &A::myex; //error
return myfp();
}
The reason being that a class member function takes a hidden parameter, the this pointer, thus it behaves very differently than a
normal function pointer.
A static member function behaves as normal function pointer and can be cast.
For example:
class A {
public:
static int myex();
};
typedef int (*fp)();
test()
{
fp myfp = (fp) &A::myex; //ok
return myfp();
}
However, static member functions can only access static data members of the class.
In C
291
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
legal.
In C++, the compiler will convert one function pointer to another only if the signature for the functions are the same. Signature
refers to the arguments and return type of the function. For example:
myex( int );
typedef int ( *ffp )( float );
test()
{
ffp fp = myex; //error
}
Seeing that myex takes an int for its argument, and fp is a pointer to a function which takes a float as argument, the compiler will
not convert it for you.
A declaration for conversion function operator can't specify any return type.
292
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
If you use the second version, it will be used in preference to the first version.
The global operator delete can only be declared using the single-parameter form.
This C++ overloaded operator delete was declared in some other way.
If you use the second version, it will be used in preference to the first version.
The global operator delete can only be declared using the single-parameter form.
3.1.2.182 E2045: Destructor name must match the class name (C++)
In a C++ class, the tilde (~) introduces a declaration for the class destructor.
293
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
The file name was missing the opening quote or angle bracket.
If a macro was used, the resulting expansion text is not surrounded by quote marks.
Example
struct foo {
int x;
int y;
}p = {0,0};
int y;
int main (void)
{
asm mov eax.(foo)x, 1;
asm mov eax.(foo)4, 1; /* Error: Invalid use of dot */
return 0;
}
Possible Causes
3 • An extra semicolon
• Missing braces
• Some syntax error in a previous "if" statement
294
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
You can declare an external Pascal function without the compiler's renaming like this:
extern "C" int pascal func( /*...*/ );
To declare a (possibly overloaded) C++ function as Pascal and allow the usual compiler renaming (to allow overloading), you
can do this:
extern int pascal func( /*...*/ );
Example
3
int main (void)
{
int p;
*p = 10; /* ERROR: Invalid Indirection */
return 0;
}
295
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
• constant expressions
• the address of a global extern or static variable plus or minus a constant
The rules for initialization are essentially the same as for assignment.
This message means that the list includes a static member or function member.
• assignment operators
• comparison operators
• .*
• —>*
• ?: conditional (ternary) operator
• && logical AND ( see page 531) operator
• || logical OR ( see page 559) operator
The compiler has encountered a member pointer being used with a different operator.
In order to call a member function pointer, one must supply an instance of the class for it to call upon.
For example:
3
class A {
public:
myex();
};
typedef int (A::*Amfptr)();
myex()
{
Amfptr mmyex = &A::myex;
return (*mmyex)(); //error
}
296
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This error can also occur if you use a #pragma option in your code with an invalid option.
297
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This operator function was declared outside a class and does not have an explicit parameter of class type.
298
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example declarations
int func(); /* declaration without prototype -- OK */
int func(int, int); /* declaration with prototype -- OK */
int func(int i, int j); /* parameter names in prototype -- OK */
int func(i, j); /* parameter names only -- ILLEGAL */
• addition(+)
• subtraction(-)
• assignment(=)
• comparison(==)
• indirection(*)
• arrow(->)
Your source file used a pointer with some other operator.
3
Example
int main (void)
{
char *p;
p /= 7; /* ERROR: Illegal Use of Pointer */
return 0;
}
299
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
• typedef names
• function declarations (except definitions at the file level)
• on local variables or parameters of functions
• on a class member--except to use its own class as a qualifier (redundant but legal).
Probably two storage classes were specified, and only one can be given.
3 The compiler encountered a structure being used with some other operator.
Using a template class name without specifying its actual arguments outside a template definition is illegal.
300
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
• Return type
• Calling convention
• Exception specification (throw list)
3.1.2.225 E2116: Bit fields must contain at least one bit (C++)
3
You can't declare a named bit field to have 0 (or less than 0) bits.
This is a convention used to force alignment of the following bit field to a byte boundary (or to a word boundary.
301
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
You must define the given type before using it in one of these contexts.
Note:This error message is often the result of a missing semicolon (;) for a class declaration. You might want to verify that all
the class declarations preceding the line on which the error occurred end with a semicolon.
3.1.2.230 E2123: Class 'class' may not contain pure functions (C++)
The class being declared cannot be abstract, and therefore it cannot contain any pure functions.
This error indicates a case label that can transfer control past this local variable.
The expression in the case statement either was missing a colon or had an extra symbol before the colon.
302
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
The temporary can be explicitly created, as with classname(val, val), or implicitly created by some other code.
Only one language modifier (for example, __cdecl, __pascal, or __fastcall) can be given for a function. 3
303
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
304
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Currently, dynamically dispatched virtual tables do not support the use of multiple inheritance.
Often the type name is misspelled or the type declaration is missing. This is usually caused by not including the appropriate
header file.
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is most often "Cannot convert 'type1' to 'type2'" but the mismatch could be due to another reason.
305
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example:
const int x=10;
const int * a = &x;
int * const b = new int;
int &c = *b;
delete a; //illegal - deleting pointer to constant
delete b; //legal
delete c; //illegal - operand not of pointer type
//should use 'delete&c' instead
3.1.2.260 E2159: Trying to derive a far class from the huge base
'base' (C++)
3 This error is no longer generated by the compiler.
3.1.2.261 E2160: Trying to derive a far class from the near base
'base' (C++)
If a class is declared (or defaults to) near, all derived classes must also be near.
306
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
3.1.2.262 E2161: Trying to derive a huge class from the far base
'base' (C++)
This error is no longer generated by the compiler.
3.1.2.263 E2162: Trying to derive a huge class from the near base
'base' (C++)
This error is no longer generated by the compiler.
3.1.2.264 E2163: Trying to derive a near class from the far base
'base' (C++)
If a class is declared (or defaults to) far, all derived classes must also be far.
3.1.2.265 E2164: Trying to derive a near class from the huge base
'base' (C++)
This error is no longer generated by the compiler.
If a class destructor is private, the class can't be destroyed, and thus can never be used. This is probably an error.
This is a useful way to ensure that no instance of a base class is ever created, but only classes derived from it.
3
3.1.2.268 E2167: 'function' was previously declared with the
language 'language' (C++)
Only one language modifier (cdecl pascal) can be given for a function.
This function has been declared with different language modifiers in two locations.
307
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This access specifier can appear no more than once for a base class.
3.1.2.271 E2170: Base class 'class' is included more than once (C++)
A C++ class can be derived from any number of base classes, but can be directly derived from a given class only once.
One cause of this error is not declaring a default constructor which you implement. For example:
class A {
public:
virtual myex();
};
A::A() {} // error
Having not seen you declare the default constructor in the class declaration, the compiler has had to generate one, thus giving
the error message when it sees one. this is a correct example:
class A {
public:
A();
virtual myex();
};
A::A() {}
308
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
• char
• class
• int
• float
• double
• struct
• union
• enum
• typedef name
Example
struct__declspec(delphiclass) clxclass
{
int __fastcall foo1(void) __dispid(42);// Error
__automated:
int __fastcall foo2(void) __dispid(43);// OK
};
309
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
ANSI C and C++ require that something be declared in the compilation unit.
3.1.2.282 E2185: The value for 'identifier' is not within the range of
'type-name' (C++)
You have attempted to assign a value that is out of the range of the specified type.
Possible Causes
310
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Useful Tip:
The IDE has a mechanism for finding a matching curly brace. If you put the cursor on the '{' or '}' character, hold down Ctrl, hit 'Q'
and then '{' or '}', it will position the cursor on the matching brace.
Make certain that the parameters in the call to the function match the parameters of the function prototype.
The file name given in an #include directive was too long for the compiler to process.
311
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
In integrated debugger expression evaluation, calls to certain functions (including implicit conversion functions, constructors,
destructors, overloaded operators, and inline functions) are not supported.
The program prints the error message and calls abort and _exit.
These floating-point errors can be avoided by masking the exception so that it doesn't occur, or by catching the exception with
signal.
3
312
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Solutions
Check the declarations for any array that might be too large. You can also remove variables from the DGROUP.
Here's how:
This error indicates a goto statement that can transfer control past this local variable.
313
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Possible Causes
A class member of reference type must have an initializer provided in all constructors for that class.
This means you can't depend on the compiler to generate constructors for such a class, because it has no way of knowing how
to initialize the references.
Either move the inline definition forward in the file or delete it entirely.
You could eliminate the inline assembly code or, in the case of an inline function, make this a macro, and remove the inline
storage class.
314
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This means that local classes cannot contain any static data members, and all of their member functions must have bodies
defined within the class definition.
315
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This is correct:
#define tri_add(a, b, c) ((a) + (b) + (c))
This is incorrect:
#define tri_add(a b. c) ((a) + (b) + (c))
The compiler encountered some non-identifier character where an argument was expected.
316
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
3.1.2.329 E2229: Member 'member' has the same name as its class
(C++)
A static data member, enumerator, member of an anonymous union, or nested type cannot have the same name as its class.
Only a member function or a non-static member can have a name that is identical to its class.
317
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example:
class A
{
typedef int (A::* infptr)(void);
public:
A();
int myex(void);
int three;
} a;
A::A()
{
infptr one = myex; //illegal - call myex or take address?
infptr two = &A::myex; //correct
three = (a.*one)() + (a.*two)();
}
3.1.2.333 O2237: DPMI programs must use the large memory model
(C++)
The compiler no longer issues this error.
• int a; double a;
• a function declared two different ways, or
• a label repeated in the same function, or
• some declaration repeated other than an extern function or a simple variable
318
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This can also happen by inadvertently including the same header file twice. For example, given:
//a.h
struct A { int a; };
//b.h
#include "a.h"
//myprog.cpp
#include "a.h"
#include "b.h"
myprog.cpp will get two declarations for the struct A. To protect against this, one would write the a.h header file as:
//a.h
#ifndef __A_H
#define __A_H
struct A { int a; };
#endif
This will allow one to safely include a.h several times in the same source code file.
• operator =
• operator ->
• operator ( )
• type conversions
This operator function is not a member function but should be.
This is called the default constructor, which means that you can't supply constructor arguments when initializing such a vector.
The integrated debugger does not support the evaluation of the new and delete operators.
319
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This is illegal, because references are not objects and can't be created through new.
You must use the BCC command to compile this source file from the DOS command line.
(Member function pointers are not true pointer types, and do not refer to any particular instance of a class.)
The colon might have been omitted, or parentheses might be improperly nested or missing.
This is usually caused by a missing delimiter such as a comma, semicolon, right parenthesis, or right brace.
320
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
In this declaration, a parameter with a default value was followed by a parameter without a default value.
This message might occur where the controlling expression of an if or while clause is expected or where a variable is being
initialized.
This message is often due to a symbol that is missing or has been added.
3
3.1.2.354 E2272: Identifier expected (C++)
An identifier was expected here, but not found.
321
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
• as the name of a member in a structure or union (except for bit fields of width 0).
In C++, an identifier is also expected in these situations:
• in a list of base classes from which another class is derived, following a double colon (::), and
• after the reserved word "operator" when no operator symbol is present.
Every template declaration must include the template formal parameters enclosed within < >, immediately following the template
keyword.
Example
struct__declspec(delphiclass) base1 {};
struct__declspec(delphiclass) base2 {};
3 structderived : base1, base2 {}; // Error
322
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
and
2.You want to construct an object of type 'class1' (but not from another object of type 'class1'). There must be a constructor
class2::class2() so that the member can be constructed.
The compiler will supply a default constructor automatically unless you have defined any constructor for class 'class2'.
In that case, the compiler will not supply the default constructor automatically ( you must supply one.
3.1.2.365 E2284: Use . or -> to call 'member', or & to take its address
(C++)
3
A reference to a non-static class member without an object was encountered.
Such a member can't be used without an object, or its address must be taken with the & operator.
323
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
(It is allowed in C++, but there's no way to refer to the parameter in the function.)
• Your source file declared an array in which the array bounds were not terminated by a right bracket.
• The array specifier in an operator is missing a right bracket.
• The operator [ ] was declared as operator [.
• A right bracket is missing from a subscripting expression.
Add the bracket or fix the declaration.
Check for a missing or extra operator or mismatched parentheses.
3
3.1.2.372 E2292: Function should return a value (C++)
Your source file declared the current function to return some type other than int or void, but the compiler encountered a return
with no value. This usually indicates some sort of error.
Functions declared as returning int are exempt because older versions of C did not support void function return types.
324
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This error can occur when you create an instance of a class using empty parentheses, and then try to access a member of that
'object'.
This error can also occur if you try to change the access rights of 'class::constructor.'
This is commonly caused by incorrectly declaring the function or misspelling the function name.
(C++)
This declaration doesn't declare anything.
This may be a struct or union without a tag or a variable in the declaration. C++ requires that something be declared.
For example:
325
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
struct
{
int a
};
//no tag or identifier
• char
• short
• int
• long
3 • enum
• float
• double
• long double
• pointer
326
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
• In declaring a file-level variable or a struct field, neither a type name nor a storage class was given.
• In declaring a typedef, no type for the name was supplied.
• In declaring a destructor for a C++ class, the destructor name was not a type name (it must be the same name as its class).
• In supplying a C++ base class name, the name was not the name of a class.
The constructor, called a copy constructor, takes just one parameter (which is a reference to its class).
However, if you have defined a constructor for class 'class2' that has a parameter of type 'class2&' and has additional
parameters with default values, the copy constructor can't exist and can't be created by the compiler.
You can then define a reference constructor or let the compiler create one.
When a C++ class 'class1' contains a vector (array) of class 'class2', and you want to copy a class of type 'class1', you must use
this assignment operator:
327
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
class2::class2(class2&)
so that the elements of the vector can be copied.
However, if you have defined an operator= for class 'class2' that does not take a parameter of type 'class2&,' the compiler will
not supply it automatically--you must supply one.
Example
struct __declspec(delphiclass) base {};
struct derived : virtual base {}; // Error
Two-byte character constants can be specified by using a second backslash. For example,
\\
represents a two-byte constant.
328
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
member (for example, to give a body for a function declared in a namespace). The declaration itself must be inside the
namespace.
Possible causes
• There are too many or too few operands for this assembler opcode.
• The number of operands is correct, but their types or order do not match the opcode.
For example:
class A
{
A& operator +; ..note missing parenthesis
};
In the example, the function operator '()' is missing, so the operator does not have function type and generates this error.
Unlike nonmember functions, they can't be declared multiple times or at other locations.
3
329
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
In this case, an overloaded function name has been used in some other context, for example, the following code will generate
this error:
class A{
A(){myex;} //calling the function
void myex(int) {} //or taking its address?
void myex(float){}
};
However, the type of the variable or parameter doesn't match any of the overloaded functions with the specified name.
If you wish to override the compiler's assigning a new name by declaring the function extern "C", you can do this for only one of
a set of functions with the same name.
(Otherwise the linker would find more than one global function with the same name.)
However, the given parameter number (counting left to right from 1) could not be converted to the declared parameter type.
3
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
330
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'", but the mismatch might be due to many other reasons.
However, the named parameter could not be converted to the declared parameter type.
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
3
3.1.2.410 E2349: Nonportable pointer conversion (C++)
An implicit conversion between a pointer and an integral type is required, but the types are not the same size. You must use an
explicit cast.
This conversion might not make any sense, so be sure this is what you want to do.
331
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
When you derive an abstract base class, with the intention to instantiate instances of this derived class, you must override each
of the pure virtual functions of the base class exactly as they are declared.
For example:
class A {
public:
virtual myex( int ) = 0;
virtual twoex( const int ) const = 0;
};
class B : public A {
public:
myex( int );
twoex( const int );
};
B b; // error
The error occurs because we have not overridden the virtual function in which twoex can act on const objects of the class. We
have created a new one which acts on non-const objects. This would compile:
class A {
public:
virtual myex( int ) = 0;
virtual twoex( const int ) const = 0;
};
class B : public A {
public:
myex( int );
twoex( const int ) const;
};
B b; // ok
• char to int
• float to double
• void* to a particular pointer
In this expression, the two sides evaluate to different types that are not automatically converted.
332
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This might be an error or you might merely need to cast one side to the type of the other.
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
Possible Causes
This can occur if a function is called and subsequently declared to return something other than an integer.
Solutions
If this has happened, you must declare the function before the first call to it.
In this case, the initializer either wasn't an lvalue, or its type didn't match the reference being initialized.
3
3.1.2.417 E2358: Reference member 'member' needs a temporary for
initialization (C++)
You provided an initial value for a reference type that was not an lvalue of the referenced type.
333
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Because there is no obvious place to store this temporary, the initialization is illegal.
• [BX]
• [BP]
• [SI]
• [DI]
• [BX+SI]
• [BX+DI]
• [BP+SI]
• [BP+DI]
Other index register combinations are not allowed.
This is illegal, because the variable referred to disappears when the function exits.
You can return a reference to any static or global variable, or you can change the function to return a value instead.
3
334
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This object will disappear when the function returns, making the reference illegal.
335
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
• infinite recursion, or
• an assembly language procedure that does not maintain the stack project
• a large array in a function
336
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
(Remember, classes are near by default in the tiny, small, and medium memory models.)
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
337
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This includes constant integral expressions and addresses of objects or functions with external linkage or members.
In a template declaration, the keyword template must be followed by a list of formal arguments enclosed within < and >
delimiters.
This is not allowed with a template function, as there is no way to specify the value when calling it.
338
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
339
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
A struct tag might only be declared (the struct not defined yet), or an extern array might be declared without a size.
It's illegal then to have some references to such an item (like sizeof) or to dereference a pointer to this type.
Possible Causes
For example, a struct tag might only be declared (the struct not defined yet).
It's illegal then to have some references to such an item (like sizeof) or to dereference a pointer to this type.
340
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This message is also issued when a global variable that is declared as __thread (a Win32-only feature) or a static data member
of a template class has the type class with constructor or destructor.
For example:
class myclass
{
public:
341
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Default = displayed
342
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Commonly, compiler failures can be worked around by moving the source code that is currently being compiled. Simple cases
might be switching the order of variable declarations, or functions within the source module. Moving the scope and storage of
variables also helps in many cases.
For linker failures, you can reduce the amount of debugging information that the linker has to work with. Try compiling only one
3
or two modules with debug information instead of an entire project.
Similarly, switching the order in which object modules are handed to the linker can work around the problem. The IDE hands
objects to the linker in the order that they are listed in the project tree. Try moving a source up or down in the list.
343
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
An old programming trick declares an array element of a structure to have zero size, then allocates the space actually needed
with malloc.
You can still use this trick, but you must declare the array element to have (at least) one element if you are compiling in strict
ANSI mode.
Declarations (as opposed to definitions) of arrays of unknown size are still allowed.
Example
char ray[]; /* definition of unknown size -- ILLEGAL */
char ray[0]; /* definition of 0 size -- ILLEGAL */
extern char ray[]; /* declaration of unknown size -- OK */
344
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
A C++ member function declared in a class with a semicolon between the header and the opening left brace also generates this
error.
• __export
• __import
• declspec(naked)
• declspec(package)
3
• __fastcall
345
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example, calls to "strcmp" are replaced by the intrinsic "__strcmp__" when -Oi is on. This means that the declaration "using
N::strcmp;" would become "using N::__strcmp__", since the token replacement happens before the compiler's parser ever sees
the tokens.
An error displays in this case, because the compiler doesn't know how to process "N::__strcmp__".
346
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
347
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
3.1.2.508 E2120: Cannot call 'main' from within the program (C++)
C++ does not allow recursive calls of main( ).
Whenever such a member function can't be generated due to applicable language rules, the compiler issues one of these error
messages.
Example
struct pbase
{
int __property ip1 = {read = ip2, write = ip2};
int __property ip2 = {read = ip1, write = ip1};
};
The above code sample will cause this error message on any usage of ip1 or ip2.
C++ classes can only be initialized with constructors if the class has constructors, private members, functions, or base classes
that are virtual.
3
348
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
The message "Type mismatch in default argument value" is used when the parameter was not given a name.
When compiling C++ programs, this message is always preceded by another message that explains the exact reason for the
type mismatch.
That other message is usually "Cannot convert 'type1' to 'type2'" but the mismatch might be due to many other reasons.
int main() {
delete[] x;
}
Since 'x' is not a pointer, but an object, the compiler will delete 'a', because that is what the pointer conversion operator for the
object yields. Having more than one conversion to pointer operator is illegal, because the compiler would not know which one to
call.
349
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Example
struct__declspec(delphiclass) clxclass
{
__automated:
int __fastcall foo1(void) __dispid(42);// OK
int __fastcall foo2(void) __dispid(42);// Error
};
Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
long__fastcall fooLong(long);// Error: long illegal
};
350
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example
struct regclass
{
int __property ip1 = { stored = false }; // Error
int __property ip2 = { default = 42 }; // Error
int __property ip3 = { nodefault }; // Error
};
struct __declspec(delphiclass) clxclass
{
int __property ip1 = { stored = false }; // OK
int __property ip2 = { default = 42 }; // OK
int __property ip3 = { nodefault }; // OK
};
This sometimes happens when you attempt to call one accessible overloaded member function (or constructor), but the
arguments match an inaccessible function.
The check for overload resolution is always made before checking for accessibility.
If this is the problem, try an explicit cast of one or more parameters to select the desired accessible function.
Virtual base class constructors must be accessible within the scope of the most derived class. This is because C++ always
constructs virtual base classes first, no matter how far down the hierarchy they are. For example:
class A {
public:
A();
};
class B : private virtual A {};
class C : private B {
public:
C();
};
C::C() {} // error, A::A() is not accessible
Since A is private to B, which is private to C, it makes A's constructor not accessible to C. However, the constructor for C must
be able to call the constructors for its virtual base class, A. If B inherits A publicly, the above example would compile.
The compiler will define a default constructor for a class unless you have defined any constructors for the class.
351
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
If the constructor for 'class2' does not specify a constructor for 'class1' (as part of 'class2's' header), there must be a constructor
class1::class1() for the base class.
The compiler will supply a default constructor automatically unless you have defined any constructor for class 'class1'.
In that case, the compiler will not supply the default constructor automatically--you must supply one.
class Base {
public:
Base(int) {}
};
class Derived = public Base {
Derived():Base(1) {}
}
// must explicitly call the Base constructor, or provide a
// default constructor in Base.
Class members with constructors must be initialized in the class' initializer list, for example:
class A {
public
A( int );
};
class B {
public:
A a;
B() : a( 3 ) {}; //ok
};
352
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example where __classid is the first identifier and TClass, which can be found in clx.h, is the second one:
// #include <clx/clx.h> missing
struct __declspec(delphiclass)bar
{
virtual int barbara(void);
};
void *foo(void)
{
return classid(bar); // Error
}
Example
structregclass
{
int mem;
__published:// Error: no Delphi style class
int __property ip = { read = mem, write = mem };
353
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
};
struct__declspec(delphiclass) clxclass
{
int mem;
__published:// OK
int __property ip = { read = mem, write = mem };
};
Example
typedef my_class<int> mci;
typedef void (__closure * func) (const mci& object);
or
you tried to delete a pointer to an object of a class that has a virtual destructor
354
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example
int i = 1234i15; // Error: no i15 suffix
int j = 1234i16; // OK
3
3.1.2.545 E2332: Variable 'variable' has been optimized and is not
available (C++)
You have tried to inspect, watch, or otherwise access a variable which the optimizer removed.
355
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Example
int GlobalGetter(void)
{
return 0;
}
struct pbase
{
intMemberGetter(void) {return 1;}
int __property ip1 = { read = GlobalGetter }; // Error
int __property ip2 = { read = MemberGetter }; // OK
};
Example
structpbase
{
voidSetter1(void){}
voidSetter2(int){}
int __property ip1 = { write = Setter1 }; // Error
int __property ip2 = { write = Setter2 }; // OK
};
3 Example
struct pbase
{
int __property ap[char *] =
{ stored = false }; // Error
};
356
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example
struct__declspec(delphiclass) clxclass
{
__published:
static intstaticDataMember;// Error
};
For example, consider the following example of an illegal attempt to instantiate an abstract class:
struct VB
{
virtualvoid f() = 0;
virtualvoid g() = 0;
virtualvoid h() = 0;
};
struct D1 : virtual VB
{
void f();
};
struct D2 : virtual VB
{
void h();
};
struct DD : D1, D2
{
}
v; // error 'DD' is an abstract class
The above code will cause the following two error messages:
Error TEST.CPP 21: Cannot create instance of abstract class 'DD'
Error TEST.CPP 21: Class 'DD' is abstract because of 'VB::g() = 0'
357
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
So when declaring a closure type, the arguments passed to that closure must be of a simple type. For example, templates are
not accepted. To pass a reference to an object of template type to a closure, you must declare a typedef, which counts as a
simple type name.
Example
struct __declspec(delphiclass) foo
{
typedef void __fastcall (__closure *foo1)(SomeTemplateType<int> *);
typedef SomeTemplateType<int> SimpleTypeName;
typedef void __fastcall (__closure *foo2)(SimpleTypeName *);
published:
__property foo1 prop1; // Error
__property foo2 prop2; // OK
};
The argument list of a template function must use all of the template formal arguments; otherwise, there is no way to generate a
template function instance based on actual argument types.
When this nesting limit is exceeded, the compiler issues this error message for all of the nested template classes. This usually
358
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This error message is always followed by the fatal error "Out of memory".
Example
void foo(TObject *p)
{
try
{
throw(p);
}
catch (TObject o) // Error
{
}
catch (TObject *op) // OK
{
}
}
Example
struct base// base not a Delphi style class
{
intbasemem;
};
struct __declspec(delphiclass) derived : base // or
{
intderivedmem;
};
Example
voidfoo(void) 3
{
Tobject o1; // Error;
Tobject *o2 = new TObject();
}
359
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
You have attempted to create such a pointer (either directly, or through a cast) and access an inaccessible member of one of
your base classes.
The program might appear to work properly in all other respects; however, this is a serious bug which should be attended to
immediately. Failure to correct an uninitialized pointer can lead to unpredictable behavior (including locking the computer up in
the large, compact, and huge memory models).
You can use the integrated debugger to track down null pointers.
3
3.1.2.566 Initializing enumeration with type (C++)
You're trying to initialize an enum variable to a different type. For example,
enum count { zero, one, two } x = 2;
will result in this warning, because 2 is of type int, not type enum count. It is better programming practice to use an enum
identifier instead of a literal integer when assigning to or initializing enum types.
360
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This is an error, but is reduced to a warning to give existing programs a chance to work.
For Windows, make sure the message loop of the program has properly terminated.
PostQuitMessage(0);
Refer to the following list of potential causes (listed from most common to least common) to determine how to resolve this error:
• CAUSE: Floating point set to None. You set the floating-point option to None when it should be set to either Fast or Normal.
• FIX: Set Floating Point to Fast or Normal.
• CAUSE: Either the compiler is over-optimizing or the floating-point formats really do need to be linked. You need the
floating-point formats if your program manipulates floats in a limited and specific way. Under certain conditions, the compiler
will ignore floating-point usage in scanf(). For example, this may occur when trying to read data into a float variable that is part
of an array contained in a structure.
• FIX: Add the following code to one source module:
extern _floatconvert;
#pragma extref _floatconvert 3
CAUSE: You forgot to put the address operator & on the scanf variable expression. For example:
float foo;
scanf("%f", foo);
FIX: Change the code so that the & operator is used where needed. For example, change the above code to the following:
float foo;
scanf("%f", &foo);
361
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This warning is displayed whenever two shift, relational, or bitwise-Boolean operators are used together without parentheses.
Also, an addition or subtraction operator that appears without parentheses with a shift operator will produce this warning.
This warning is generated when the compiler encounters an assignment operator as the main operator of a conditional
expression (part of an if, while, or do-while statement).
If you want to suppress this warning, enclose the assignment in parentheses and compare the whole thing to zero explicitly.
Default = On
The compiler encountered an inline assembly statement with a disallowed opcode or an unknown token. Check the spelling of
the opcode or token.
Note:You will get a separate error message from the assembler if you entered illegal assembler source code.
Early versions of C++ provided for initialization of a base class by following the constructor header with just the base class
362
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
This makes the code much clearer, and is required when you have multiple base classes.
Old way
derived::derived(int i) : (i, 10) { ... }
New way
derived::derived(int i) : base(i, 10) { ... }
In ANSI C, bit fields may not be of type signed char or unsigned char.
When you're not compiling in strict ANSI mode, the compiler allows these constructs, but flags them with this warning.
This message is given if the "Prototypes required" warning is enabled and you call a function without first giving a prototype for
that function.
3
3.1.2.580 W8008: Condition is always true OR W8008 Condition is
always false (C++)
(Command-line option to suppress warning: -w-ccc)
Whenever the compiler encounters a constant comparison that (due to the nature of the value being compared) is always true or
false, it issues this warning and evaluates the condition at compile time.
363
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example:
void proc(unsigned x){
if (x >= 0) /* always 'true' */
{
...
}
}
Since the ranges of signed and unsigned types are different the result of an ordered comparison of an unsigned and a signed
value might have an unexpected result.
Example
#pragma warn +csu
boolfoo(unsigned u, int i)
{
return u < i;
}
This warning message is issued when a C++ // comment is continued onto the next line with backslash line continuation.
The intention is to warn about cases where lines containing source code unintentionally become part of a comment because that
comment happened to end in a backslash.
If you get this warning, check carefully whether you intend the line after the // comment to be part of the comment. If you don't,
either remove the backslash or put some other character after it. If you do, it's probably better coding style to start the next
comment line with // also.
The specified identifier was never used. This message can occur in the case of either local or static variables. It occurs when the
source file declares the named local or static variable as part of the block just ending, but the variable was never used.
In the case of local variables, this warning occurs when the compiler encounters the closing brace of the compound statement or
function. In the case of static variables, this warning occurs when the compiler encounters the end of the source file.
3 For example:
// Need to compile with -w to make this warning show up!
#pragma option -w
int foo()
{
int x;
return 0;
}
364
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
this utility.
Default = On
Your source file includes a comparison involving a constant sub-expression that was outside the range allowed by the other
sub-expression's type.
To get an unsigned constant greater than 32,767 (in decimal), you should either
The C++ IDE issues this warning when you've specified the array size when deleting an array.
With the new C++ specification, you don't need to make this specification. The compiler ignores this construct.
3
3.1.2.588 W8018: Assigning 'type' to 'enumeration' (C++)
(Command-line option to suppress warning: -w-eas)
This is an error in C++, but is reduced to a warning to give existing programs a chance to work.
365
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For example, the following initialization will result in this warning, because 2 is of type int, not type enum count:
enum count zero, one, two x = 2;
It is better programming practice to use an enum identifier instead of a literal integer when assigning to or initializing enum types.
This is an error, but is reduced to a warning to give existing programs a chance to work.
An address-of operator (&) is not needed with function name; any such operators are discarded.
This identifier appeared in a declaration that implicitly or explicitly marked it as global or external, and also in a static declaration.
Under older versions of C, a hexadecimal escape sequence could contain no more than three digits.
The ANSI standard allows any number of digits to appear as long as the value fits in a byte.
This warning results when you have a long hexadecimal escape sequence with many leading zero digits (such as \x00045).
3
3.1.2.593 W8024: Base class 'class1' is also a base class of 'class2'
(C++)
(Command-line option to suppress warning: -w-ibc)
A class inherits from the same base class both directly and indirectly. It is best to avoid this non-portable construct in your
program code.
366
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
In this case, a declaration with the same name but different argument types makes the virtual functions inaccessible to further
derived classes.
When you use set the Far Data Threshold option, the compiler automatically makes any global variables that are larger than the
threshold size be far.
When the variable is an initialized array with an unspecified size, its total size is not known when the compiler must decide
whether to make it near or far, so the compiler makes it near.
The compiler issues this warning if the number of initializers given for the array causes the total variable size to exceed the data
size threshold.
If the fact that the compiler made the variable be near causes problems, make the offending variable explicitly far.
To do this, insert the keyword "far" immediately to the left of the variable name in its definition.
When structures are initialized, braces can be used to mark the initialization of each member of the structure. If a member itself
is an array or structure, nested pairs of braces can be used. This ensures that the compiler's idea and your idea of what value
goes with which member are the same. When some of the optional braces are omitted, the compiler issues this warning.
This C++ class contains a constant member 'member' that doesn't have an initialization.
Note that constant members can be initialized only; they can't be assigned to.
For an assignment operator or some other circumstance, your source file requires a conversion from a larger integral data type
to a smaller integral data type where the conversion exists.
Because the integral data type variables don't have the same size, this kind of conversion might alter the behavior of a program.
367
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
this utility.
Your source file redefined the macro 'ident' using text that was not exactly the same as the first definition of the macro.
You converted a signed char pointer to an unsigned char pointer, or vice versa, without using an explicit cast. (Strictly speaking,
this is incorrect, but it is often harmless.)
3.1.2.602 W8067: Both return and return with a value used (C++)
(Command-line option to suppress warning: -w-ret)
The current function has return statements with and without values.
Possibly a return statement was omitted from the end of the function.
In previous versions of the C++ specification, typedef and tag names declared inside classes were directly visible in the global
scope.
In the latest specification of C++, these names must be prefixed with class::qualifier if they are to be used outside of their class
3 scope.
The compiler issues this warning whenever a name is uniquely defined in a single class. The compiler permits this usage without
class::. This allows older versions of code to compile.
368
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
this utility.
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
this utility.
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
this utility.
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
this utility.
(This is an error, but was reduced to a warning to give existing programs a chance to work.)
In C++, a class member function was called for a volatile object of the class type, but the function was not declared with volatile
following the function header. Only a volatile member function can be called for a volatile object. 3
For example, if you have
class c
{
public:
f() volatile;
g();
};
volatile c vcvar;
369
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This warning is issued when the compiler encounters a statement with some operators that have no effect.
The named parameter, declared in the function, was never used in the body of the function.
This might or might not be an error and is often caused by misspelling the parameter.
This warning can also occur if the identifier is redeclared as an automatic (local) variable in the body of the function.
The compiler found a return statement without a return value, or it reached the end of the function without finding a return
statement.
An error has occurred while using the command-line utility H2ASH. See the online file "tsm_util.txt" for further information about
3 this utility.
Basically, it makes no sense to negate an unsigned value because the result will still be unsigned.
370
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Example
#pragma warn +ngu
unsignedfoo(unsigned u)
{
return-u;
}
A pragma does not match one of the pragmas expected by the compiler.
The C++ specification allows you to overload both the prefix and postfix versions of the ++ and -- operators.
Whenever the prefix operator is overloaded, but is used in a postfix context, the compiler uses the prefix operator and issues this
warning.
When a function prototype refers to a structure type that has not previously been declared, the declaration inside the prototype is
not the same as a declaration outside the prototype.
For example,
int func(struct s *ps); struct s /* ... */ ; 3
Because there is no "struct s" in scope at the prototype for func, the type of parameter ps is pointer to undefined struct s, and is
not the same as the "struct s" that is later declared.
This will result in later warning and error messages about incompatible types, which would be very mysterious without this
warning message.
To fix the problem, you can move the declaration for "struct s" ahead of any prototype that references it, or add the incomplete
type declaration "struct s;" ahead of any prototype that references "structs".
371
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
If the function parameter is a struct, rather than a pointer to struct, the incomplete declaration is not sufficient.
You must then place the struct declaration ahead of the prototype.
A nonzero integral value is used in a context where a pointer is needed or where an integral value is needed; the sizes of the
integral type and pointer are the same.
A break, continue, goto, or return statement was not followed by a label or the end of a loop or function.
The compiler checks while, do, and for loops with a constant test condition, and attempts to recognize loops that can't fall
through.
In C++, a variable or parameter of reference type must be assigned a reference to an object of the same type. If the types do not
match, the actual value is assigned to a temporary of the correct type, and the address of the temporary is assigned to the
reference variable or parameter.
The warning means that the reference variable or parameter does not refer to what you expect, but to a temporary variable,
otherwise unused.
In C++, a variable or parameter of reference type must be assigned a reference to an object of the same type.
372
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
If the types do not match, the actual value is assigned to a temporary of the correct type, and the address of the temporary is
assigned to the reference variable or parameter.
The warning means that the reference variable or parameter does not refer to what you expect, but to a temporary variable,
otherwise unused.
In C++, a variable or parameter of reference type must be assigned a reference to an object of the same type. If the types do not
match, the actual value is assigned to a temporary of the correct type, and the address of the temporary is assigned to the
reference variable or parameter.
The warning means that the reference variable or parameter does not refer to what you expect, but to a temporary variable,
otherwise unused.
In C++, a variable or parameter of reference type must be assigned a reference to an object of the same type.
If the types do not match, the actual value is assigned to a temporary of the correct type, and the address of the temporary is
assigned to the reference variable or parameter.
The warning means that the reference variable or parameter does not refer to what you expect, but to a temporary variable,
otherwise unused.
Example
It is a frequent programming mistake to leave an address-of operator (&) off a structure when passing it as an argument.
373
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This warning provides a way for the compiler to warn you of this mistake.
Your source file compared a pointer to a non-pointer other than the constant 0.
You should use a cast to suppress this warning if the comparison is proper.
The compiler encountered some conversion of a pointer that caused the pointer to point to a different type.
You should use a cast to suppress this warning if the conversion is proper.
A common cause of this warning is when the C compiler converts a function pointer of one type to another (the C++ compiler
generates an error when asked to do that). It can be suppressed by doing a typecast. Here is a common occurrence of it for
Windows programmers:
#define STRICT
#include <windows.h>
LPARAM _export WndProc( HWND , UINT , WPARAM , LPARAM );
test() {
WNDCLASS wc;
wc.lpfnWndProc = WndProc; //warning
}
It is suppressed by making the assignment to lpfnWndProc as follows:
wc.lpfnWndProc = ( WNDPROC ) WndProc;
This warning message is issued when the structure alignment is different after including a file than it was before including that
file.
The intention is to warn you about cases where an include file changes structure packing, but by mistake doesn't restore the
original setting at the end. If this is intentional, you can give a #pragma nopackwarning directive at the end of an include file to
disable the warning for this file.
This message is given if you call a function without first declaring that function.
374
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
int func();
In C++, every function declaration is also a prototype; this example is equivalent to
int func(void);
The declaration can be either classic or modern (prototype) style.
Your source file used the named structure on some line before where the error is indicated (probably on a pointer to a structure)
but had no definition for the structure.
Your source file used the variable 'identifier' in an expression before it was assigned a value.
The compiler uses a simple scan of the program to determine this condition.
If the use of a variable occurs physically before any assignment, this warning will be generated.
Of course, the actual flow of the program can assign the value before the program uses it.
The variable appears in an assignment, but is never used anywhere else in the function just ending.
The warning is indicated only when the compiler encounters the closing brace.
The #pragma warn -aus switch has function-level granularity. You cannot turn off this warning for individual variables within a
function; it is either off or on for the whole function.
Your source file declared the current function as returning void, but the compiler encountered a return statement with a value. 3
The value of the return statement will be ignored.
Example
// This HAS to be in a "C" file. In a "C++" file this would be an error
void foo()
{
return 0; // Can't return a value from a void function
}
375
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
This warning happens when you add an exception specification to a function definition and you throw a type in your function
body that is not mentioned in your exception specification.
This warning is issued when a handler for a type 'D' that is derived from type 'B' is specified after a handler for B', since the
handler for 'D' will never be invoked.
For example:
int X = 0xFFFF * 0xFFFF;
In C++ code, user-defined messages are introduced by using the #pragma message compiler syntax.
Note:In addition to messages that you introduce with the #pragma message compiler syntax, user-defined warnings can be
introduced by third party libraries. Should you require Help about a third party warning, please contact the vendor of the header
file that issued the warning.
3 3.1.2.638 W8049: Use '> >' for nested templates Instead of '>>' (C++)
(Command-line option to suppress warning: -w-ntd)
Whitespace is required to separate the closing ">" in a nested template name, but since it is an extremely common mistake to
leave out the space, the compiler accepts a ">>" with this warning.
376
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Exception specifications are not expanded inline: Check your inline code for lines containing exception specification.
Functions taking class-by-value argument(s) are not expanded inline: When exception handling is enabled, functions that take
class arguments by value cannot be expanded inline.
Note:Functions taking class parameters by reference are not subject to this restriction.
This warning is issued when pre-compiled headers are enabled but the compiler could not generate one, for one of the following
reasons:
ReasonExplanation
write failedThe compiler could not write to the pre-compiled header file. This occurs if you specified an invalid location to cache
precompiled headers or if the disk is full.
initialized data in headerOne of the headers contained a global variable definition (in C, a global variable with an initializer; in
C++ any variable not declared as 'extern').
header incompleteThe pre-compiled header ended in the middle of a declaration, for example, inside a class definition (this often
happens when there is a missing closing brace in a header file).
A precompiled header file references a type object file, but the type object file cannot be found. This is not a fatal problem but will
make your object files larger than necessary.
377
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
Where:
• Static variables
• Aggregate initializers
• Some return statements
• Local destructors
• Some if statements
• Local classes
• Missing return statements
• Disallowed reserved words listed under "Reserved words" below.
Reserved words
Functions containing any of these reserved words can't be expanded inline, even when specified as inline:
asm except
break finally
case for
continue goto
defaults switch
do while
The function is still perfectly legal, but will be treated as an ordinary static (not global) function.
A copy of the function will appear in each compilation unit where it is called.
Description
If an inline function becomes too complex, the compiler is unable to expand it inline. However, because the function is so
complex, expanding it inline is unlikely to provide significant performance enhancements.
You've created an inline function for which the compiler turns off inlining. You can ignore this warning; the function will be
generated out of line.
3
3.1.2.644 W8036: Non-ANSI keyword used: 'keyword' (C++)
(Command-line option to display warning: -wnak)
A non-ANSI keyword (such as '__fastcall') was used when strict ANSI conformance was requested via the -A option.
378
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
Issues a warning upon usage for any "C" linkage function that has been specified. This will warn about functions that are
"obsolete".
In looking up include files, the C++ compiler has encountered a file whose path and filename contain more characters than are
allowed in the Windows maximum. Rename the paths and filenames that you can, and shorten their names wherever possible.
Example
#pragma warn +spa
intarray[10];
intfoo(__int64 index)
{
returnarray[index];
}
379
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
The value of index is 64 bits wide while the address of array is only 32 bits wide.
The warning may be issued when a member pointer to one type is cast to a member pointer of another type and the class of the
converted member pointer has virtual bases.
Encountering this warning means that at runtime, if the member pointer conversion cannot be completed, the result of the cast
will be a NULL member pointer.
When a member pointer type is declared, its class has not been fully defined, and the -Vmd option has been used, the compiler
has to use the most general (and the least efficient) representation for that member pointer type. This can cause less efficient
code to be generated (and make the member pointer type unnecessarily large), and can also cause problems with separate
compilation; see the -Vm compiler switch for details.
try {
}
catch( std::exception & ) { // ambiguous, not caught here
}
3 catch( std::runtime_error & ) { // caught here
}
Note that the compiler might warn you that the second catch cannot be triggered because the first clause should catch all
matching exceptions. But the ambiguous base case is caught by the second clause.
380
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
For example, you cannot combine the C++ compiler options -b- and -bi because -b- turns off all -b options, including -bi.
381
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
The underlying type of a scoped enum is fixed to int unless explicitly provided by the user. The underlying type of a 'classic'
enum remains unspecified unless fixed by the user.
For more information, see Strongly Typed Enums ( see page 498).
382
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf.
For details about using a constant expression in a static assertion, see Static Assertions ( see page 498).
A string literal is the second argument in a static assertion. For details about using a static assertion, see Static Assertions (
see page 498).
383
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference
For more information, see Writing a finally Block in C++ ( see page 2023) and finally keyword ( see page 550).
This warning is generated for local static objects with constructors for multithreaded programs. This situation can cause
problems if two threads enter the containing function at the same time and no critical sections are present, allowing the
constructor to potentially be called more than once.
This warning is generated if the same attribute was specified more than once for the same entity.
If the type is const then either an initializer must be present or the non-POD class must have a user-declared constructor. Error
in ANSI mode, warning if ANSI mode is not set.
'extern template' has no normative effect on inline functions. Implementations are encouraged to suppress out-of-line copies of
inline functions that were declared with 'extern template'.
384
3.1 C++ Reference RAD Studio C++ Language Guide
This warning is generated if a parameter of an intrinsic function is a dependent type and the dependency cannot be resolved.
This warning is generated for a reference or constant member in a class without constructors if ANSI mode is not set. In ANSI
mode this is an error.
This warning is generated if the type of a class/union member is omitted in its declaration and ANSI mode is not set. Always an
error in ANSI mode.
Topics
Name Description
C++ Specifics ( see page 385) This section contains C++ Specific topics.
Keywords, Alphabetical Listing ( see page 513) This section contains Keywords, Alphabetical Listing topics.
Keywords, By Category ( see page 579) This section contains Keywords, By Category topics.
Language Structure ( see page 586) The topics in this section provide a formal definition of C++ language and its
implementation in the CodeGear C++ compiler. They describe the legal ways in
which tokens can be grouped together to form expressions, statements, and 3
other significant units.
Lexical Elements ( see page 660) This section contains Lexical Element topics.
The Preprocessor ( see page 687) This section contains Preprocessor topics.
385
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Classes ( see page 386) This section contains Class topics.
Class Templates Overview ( see page 411) This section contains Class Templates Overview topics.
Compiler Template Switches ( see page 413) This section contains Compiler Template Switch topics.
Constructors And Destructors ( see page 415) This section contains Constructor and Destructor topics.
C++ namespaces ( see page 426) This section contains C++ name space topics.
C++ Scope ( see page 429) This section contains C++ Scope topics.
Exporting And Importing Templates ( see page 432) This section contains Exporting And Importing Template topics.
Function Templates Overview ( see page 433) This section contains Function Templates Overview topics.
The new And delete Operators ( see page 434) This section contains new And delete Operator topics.
New-style Typecasting Overview ( see page 438) This section contains New-style Typecasting Overview topics.
Operator Overloading Overview ( see page 438) This section contains Operator Overloading Overview topics.
Overloading Operator Functions Overview ( see page 441) This section contains Overloading Operator Functions Overview topics.
Polymorphic Classes ( see page 446) This section contains Polymorphic Class topics.
Referencing ( see page 451) This section contains Typeid Operator topics.
Run-time Type Identification (RTTI) ( see page 453) This section contains Run-time Type Identification (RTTI) topics.
The Scope Resolution Operator ( see page 454) This section contains Scope Resolution Operator topics.
Stricter C++ Compiler (C++Builder 2007) ( see page 454) To more closely obey the rules of the C++ ANSI Standard, the C++ compiler
shipping with C++Builder 2007 is stricter than previous versions. Code that did
not generate errors in earlier versions of C++Builder might fail to compile
beginning with C++Builder 2007.
This section lists some of the common areas where the compiler is stricter. Each
case is illustrated with an example showing the problem and how to update the
code to compile with C++Builder 2007. Note that there are often many ways to
bring offending code up to date. The appropriate method depends on the intent
of the original... more ( see page 454)
Templates ( see page 460) This section contains Template topics.
C++0x Features (C++Builder 2009) ( see page 462) C++Builder 2009 implements a number of the new features proposed in the
C++0x standard. This section lists and describes these C++0x features. You can
view the Working Paper draft that was used to guide the implementation of these
features at Draft Working Paper. You can view a summary of the working group
papers at Summary of Working Group Papers.
Unicode for C++ ( see page 500) This section contains Unicode related feature topics for C++.
Handling Delphi Features in C++Builder 2009 ( see page 507) This section contains topics describing how you can handle issues that might
arise when C++Builder 2009 interacts with certain new Delphi features.
3.1.3.1.1 Classes
This section contains Class topics.
Topics
Name Description
C++ Classes ( see page 387) C++ classes offer extensions to the predefined type system. Each class type
represents a unique set of objects and the operations (methods) and conversions
available to create, manipulate, and destroy such objects. Derived classes can
be declared that inherit the members of one or more base (or parent) classes.
In C++, structures and unions are considered classes with certain access
defaults.
A simplified, “first-look” syntax for class declarations is
3 class-key <type-info> class-name
<: base-list> { <member-list> };
class-key is one of class, struct, or union.
The optional type-info indicates a request for runtime type information about
the... more ( see page 387)
Friends Of Classes ( see page 388) This section contains Friends Of Class topics.
386
3.1 C++ Reference RAD Studio C++ Language Guide
Class Member List ( see page 390) The optional member-list is a sequence including, but not exclusive to:
387
C++ Language Guide RAD Studio 3.1 C++ Reference
operations (methods) and conversions available to create, manipulate, and destroy such objects. Derived classes can be
declared that inherit the members of one or more base (or parent) classes.
In C++, structures and unions are considered classes with certain access defaults.
The optional type-info indicates a request for runtime type information about the class. You can compile with the –RT compiler
option, or you can use the __rtti keyword.
The optional base-list lists the base class or classes from which the class class-name will derive (or inherit) objects and methods.
If any base classes are specified, the class class-name is called a derived class. The base-list has default and optional
overriding access specifiers that can modify the access rights of the derived class to members of the base classes.
The optional member-list declares the class members (data and functions) of class-name with default and optional overriding
access specifiers that can affect which functions can access which members.
See Also
Class Types ( see page 404)
388
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Friends Of Classes ( see page 389) A friend F of a class X is a function or class, although not a member function of
X, with full access rights to the private and protected members of X. In all other
respects, F is a normal function with respect to scope, declarations, and
definitions.
Since F is not a member of X, it is not in the scope of X, and it cannot be called
with the x.F and xptr->F selector operators (where x is an X object and xptr is a
pointer to an X object).
If the specifier friend is used with a function declaration... more ( see page 389)
Since F is not a member of X, it is not in the scope of X, and it cannot be called with the x.F and xptr->F selector operators
(where x is an X object and xptr is a pointer to an X object).
If the specifier friend is used with a function declaration or definition within the class X, it becomes a friend of X.
friend functions defined within a class obey the same inline rules as member functions (see Inline functions). friend functions
are not affected by their position within the class or by any access specifiers. For example:
class X {
int i; // private to X
friend void friend_func(X*, int);
/* friend_func is not private, even though it's declared in the private section */
public:
void member_func(int);
};
/* definitions; note both functions access private int i */
void friend_func(X* xptr, int a) { xptr–>i = a; }
void X::member_func(int a) { i = a; }
X xobj;
/* note difference in function calls */
friend_func(&xobj, 6);
xobj.member_func(6);
You can make all the functions of class Y into friends of class X with a single declaration:
class Y; // incomplete declaration
class X {
friend Y;
int i;
void member_funcX();
};
class Y; { // complete the declaration
void friend_X1(X&);
void friend_X2(X*);
.
.
.
};
3
The functions declared in Y are friends of X, although they have no friend specifiers. They can access the private members of X,
such as i and member_funcX.
389
C++ Language Guide RAD Studio 3.1 C++ Reference
}
class Y {
int i;
friend void X::member_funcX();
.
.
.
};
Class friendship is not transitive: X friend of Y and Y friend of Z does not imply X friend of Z. Friendship is not inherited.
See Also
C++ Classes ( see page 387)
Friends Of Classes
• Data declarations (of any type, including enumerations, bit fields and other classes)
• Nested type declarations
• Nested type definitions
• Template declarations
• Template definitions
• Function declarations
3 • Function definitions
• Constructors
• A destructor
Members of a class can optional have storage class specifiers and access modifiers. The objects thus defined are called class
members. The storage class specifiers auto, extern, and register are not allowed. Members can be declared with the static
storage class specifiers.
390
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++ Classes ( see page 387)
Topics
Name Description
Inline Functions ( see page 391) You can declare a member function within its class and define it elsewhere.
Alternatively, you can both declare and define a member function within its class,
in which case it is called an inline function.
The compiler can sometimes reduce the normal function call overhead by
substituting the function call directly with the compiled code of the function body.
This process, called an inline expansion of the function body, does not affect the
scope of the function name or its arguments. Inline expansion is not always
possible or feasible. The inline specifier indicates to the compiler you would like
an... more ( see page 391)
The compiler can sometimes reduce the normal function call overhead by substituting the function call directly with the compiled
code of the function body. This process, called an inline expansion of the function body, does not affect the scope of the function
name or its arguments. Inline expansion is not always possible or feasible. The inline specifier indicates to the compiler you
would like an inline expansion. 3
Note: The compiler can ignore requests for inline expansion.
Explicit and implicit inline requests are best reserved for small, frequently used functions, such as the operator functions that
implement overloaded operators. For example, the following class declaration of func:
int i; // global int
class X {
public:
391
C++ Language Guide RAD Studio 3.1 C++ Reference
An inline function with an exception-specification will never be expanded inline by the compiler. For example,
inline void f1() throw(int)
{
// Warning: Functions with exception specifications are not expanded inline
}
The remaining restrictions apply only when destructor cleanup is enabled.
Note: Destructors are called by default. See Setting exception handling options for information about exception-handling
switches.
An inline function that takes at least one parameter that is of type ’class with a destructor’ will not be expanded inline. Note that
this restriction does not apply to classes that are passed by reference. Example:
struct foo {
foo();
~foo();
};
inline void f2(foo& x)
{
// no warning, f2() can be expanded inline
}
inline void f3(foo x)
{
// Warning: Functions taking class-by-value argument(s) are
// not expanded inline in function f3(foo)
}
An inline function that returns a class with a destructor by value will not be expanded inline whenever there are variables or
temporaries that need to be destructed within the return expression:
struct foo {
foo();
~foo();
};
inline foo f4()
{
return foo();
// no warning, f4() can be expanded inline
}
inline foo f5()
{
foo X;
3 return foo(); // Object X needs to be destructed
// Warning: Functions containing some return statements are
// not expanded inline in function f5()
}
inline foo f6()
{
return ( foo(), foo() ); // temporary in return value
// Warning:Functions containing some return statements are
// not expanded inline in function f6()
}
392
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++ Classes ( see page 387)
Inline Functions
See Also
C++ Classes ( see page 387)
393
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Static Members ( see page 394) The storage class specifier static can be used in class declarations of data and
function members. Such members are called static members and have distinct
properties from nonstatic members. With nonstatic members, a distinct copy
“exists” for each instance of the class; with static members, only one copy exists,
and it can be accessed without reference to any particular object in its class. If x
is a static member of class X, it can be referenced as X::x (even if objects of
class X haven’t been created yet). It is still possible to access x using the normal
member access... more ( see page 394)
394
3.1 C++ Reference RAD Studio C++ Language Guide
cannot access nonstatic members without explicitly specifying an object with . or ->. For example, with the declarations of the
previous example, func might be defined as follows:
void X::func(int i, X* ptr)
{
member_int = i; // which object does member_int
// refer to? Error
ptr->member_int = i; // OK: now we know!
}
Apart from inline functions, static member functions of global classes have external linkage. Static member functions cannot be
virtual functions. It is illegal to have a static and nonstatic member function with the same name and argument types.
The declaration of a static data member in its class declaration is not a definition, so a definition must be provided elsewhere to
allocate storage and provide initialization.
Static members of a class declared local to some function have no linkage and cannot be initialized. Static members of a global
class can be initialized like ordinary global objects, but only in file scope. Static members, nested to any level, obey the usual
class member access rules, except they can be initialized.
class X {
static int x;
static const int size = 5;
class inner {
static float f;
void func(void); // nested declaration
};
public :
char array[size];
};
int X::x = 1;
float X::inner::f = 3.14; // initialization of nested static
void X::inner::func(void) { /* define the nested function */ }
The principal use for static members is to keep track of data common to all objects of a class, such as the number of objects
created, or the last-used resource from a pool shared by all such objects. Static members are also used to
395
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
C++ Classes ( see page 387)
Topics
Name Description
Base And Derived Class Access ( see page 397) When you declare a derived class D, you list the base classes B1, B2, ... in a
comma-delimited base-list:
Member Access Control ( see page 399) Members of a class acquire access attributes either by default (depending on
class key and declaration placement) or by the use of one of the three access
specifiers: public, private, and protected. The significance of these attributes is
as follows:
396
3.1 C++ Reference RAD Studio C++ Language Guide
Member Scope ( see page 400) The expression X::func() in the example in Inline functions and exceptions uses
the class name X with the scope access modifier to signify that func, although
defined “outside” the class, is indeed a member function of X and exists within
the scope of X. The influence of X:: extends into the body of the definition. This
explains why the i returned by func refers to X::i, the char* i of X, rather than the
global int i. Without the X:: modifier, the function func would represent an
ordinary non-class function, returning the global int i.
All member functions, then,... more ( see page 400)
Nested Types ( see page 401) Tag or typedef names declared inside a class lexically belong to the scope of
that class. Such names can, in general, be accessed only by using the xxx::yyy
notation, except when in the scope of the appropriate class.
A class declared within another class is called a nested class. Its name is local to
the enclosing class; the nested class is in the scope of the enclosing class. This
is a purely lexical nesting. The nested class has no additional privileges in
accessing members of the enclosing class (and vice versa).
Classes can be nested in this way to... more ( see page 401)
Note: Since a base class can itself be a derived class, the access attribute question is recursive: you backtrack until you reach
the basemost of the base classes, those that do not inherit.
When declaring D, you can use the access specifier public, protected, or private in front of the classes in the base-list:
class D : public B1, private B2, ... {
.
.
.
}
These modifiers do not alter the access attributes of base members as viewed by the base class, though they can alter the
access attributes of base members as viewed by the derived class.
Note: Unions cannot have base classes, and unions cannot be used as base classes.
The derived class inherits access attributes from a base class as follows:
• public base class: public members of the base class are public members of the derived class. protected members of the
base class are protected members of the derived class. private members of the base class remain private to the base class.
• protected base class: Both public and protected members of the base class are protected members of the derived class.
private members of the base class remain private to the base class.
• private base class: Both public and protected members of the base class are private members of the derived class. private
members of the base class remain private to the base class.
3
Note that private members of a base class are always inaccessible to member functions of the derived class unless friend
declarations are explicitly declared in the base class granting access. For example,
/* class X is derived from class A */
class X : A { // default for class is private A
.
.
.
}
/* class Y is derived (multiple inheritance) from B and C
397
C++ Language Guide RAD Studio 3.1 C++ Reference
B defaults to private B */
class Y : B, public C { // override default for C
.
.
.
}
/* struct S is derived from D */
struct S : D { // default for struct is public D
.
.
.
}
/* struct T is derived (multiple inheritance) from D and E
E defaults to public E */
struct T : private D, E { // override default for D
// E is public by default
.
.
.
}
The effect of access specifiers in the base list can be adjusted by using a qualified-name in the public or protected declarations
of the derived class. For example:
class B {
int a; // private by default
public:
int b, c;
int Bfunc(void);
};
class X : private B { // a, b, c, Bfunc are now private in X
int d; // private by default, NOTE: a is not
// accessible in X
public:
B::c; // c was private, now is public
int e;
int Xfunc(void);
};
int Efunc(X& x); // external to B and X
The function Efunc() can use only the public names c, e, and Xfunc().
• The “adjusted-to-public” c
• The “private-to-X” members from B: b and Bfunc()
• X’s own private and public members: d, e, and Xfunc()
However, Xfunc() cannot access the “private-to-B” member, a.
See Also
C++ Classes ( see page 387)
398
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++ Classes ( see page 387)
399
C++ Language Guide RAD Studio 3.1 C++ Reference
All member functions, then, are in the scope of their class, even if defined outside the class.
Data members of class X can be referenced using the selection operators . and -> (as with C structures). Member functions can
also be called using the selection operators (see The keyword this). For example:
class X {
public:
int i;
char name[20];
X *ptr1;
X *ptr2;
void Xfunc(char*data, X* left, X* right); // define elsewhere
};
void f(void);
{
X x1, x2, *xptr=&x1;
x1.i = 0;
x2.i = x1.i;
xptr–>i = 1;
x1.Xfunc("stan", &x2, xptr);
3 }
If m is a member or base member of class X, the expression X::m is called a qualified name; it has the same type as m, and it is
an lvalue only if m is an lvalue. It is important to note that, even if the class name X is hidden by a non-type name, the qualified
name X::m will access the correct class member, m.
Class members cannot be added to a class by another section of your program. The class X cannot contain objects of class X,
but can contain pointers or references to objects of class X (note the similarity with C’s structure and union types).
400
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++ Classes ( see page 387)
Member Scope
A class declared within another class is called a nested class. Its name is local to the enclosing class; the nested class is in the
scope of the enclosing class. This is a purely lexical nesting. The nested class has no additional privileges in accessing
members of the enclosing class (and vice versa).
Classes can be nested in this way to an arbitrary level, up to the limits of memory. Nested classes can be declared inside some
class and defined later. For example,
struct outer
{
typedef int t; // 'outer::t' is a typedef name
struct inner // 'outer::inner' is a class
{
static int x;
};
static int x;
int f();
class deep; // nested declaration
};
int outer::x; // define static data member 3
int outer::f() {
t x; // 't' visible directly here
return x;
}
int outer::inner::x; // define static data member
outer::t x; // have to use 'outer::t' here
class outer::deep { }; // define the nested class here
With CodeGear C++ 2.0, any tags or typedef names declared inside a class actually belong to the global (file) scope. For
401
C++ Language Guide RAD Studio 3.1 C++ Reference
example:
struct foo
{
enum bar { x }; // 2.0 rules: 'bar' belongs to file scope
// 2.1 rules: 'bar' belongs to 'foo' scope
};
bar x;
The preceding fragment compiles without errors. But because the code is illegal under the 2.1 rules, a warning is issued as
follows:
Warning: Use qualified name to access nested type 'foo::bar'
See Also
C++ Classes ( see page 387)
Nested Types
Redefined functions and operators are said to be overloaded. Operators and functions that are restricted to objects of a certain
class (or related group of classes) are called member functions for that class. C++ offers the overloading mechanism that allows
3 the same function or operator name can be called to perform different tasks, depending on the type or number of arguments or
operands.
See Also
C++ Classes ( see page 387)
402
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Virtual Base Classes ( see page 403) A virtual class is a base class that is passed to more than one derived class, as
might happen with multiple inheritance.
You cannot specify a base class more than once in a derived class:
You cannot specify a base class more than once in a derived class:
class B { ... };
class D : B; B { ... }; //ILLEGAL
However, you can indirectly pass a base class to the derived class more than once:
class X : public B { ... };
class Y : public B { ... };
class Z : public X, public Y { ... }; //OK
In this case, each object of class Z has two sub-objects of class B.
If this causes problems, add the keyword virtual to the base class specifier. For example,
class X : virtual public B { ... };
class Y : virtual public B { ... };
class Z : public X, public Y { ... };
B is now a virtual base class, and class Z has only one sub-object of class B.
3
Constructors for Virtual Base Classes
Constructors for virtual base classes are invoked before any non-virtual base classes.
If the hierarchy contains multiple virtual base classes, the virtual base class constructors invoke in the order they were declared.
Any non-virtual bases are then constructed before the derived class constructor is called.
If a virtual class is derived from a non-virtual base, that non-virtual base will be first, so that the virtual base class can be properly
403
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
C++ Classes ( see page 387)
404
3.1 C++ Reference RAD Studio C++ Language Guide
The same name can be used to denote more than one function, provided they differ in argument type or number of arguments.
See Also
C++ Classes ( see page 387)
405
C++ Language Guide RAD Studio 3.1 C++ Reference
__declspec(<decl-modifier>)
Description
The decl-modifier argument can be delphiclass or pascalimplementation. These arguments should be used only with classes
derived from VCL classes.
• You must use __declspec(delphiclass) for any forward declaration of classes that are directly or indirectly derived from
TObject.
• Use the __declspec(pascalimplementation) modifier to indicate that a class has been implemented in the Delphi language.
This modifier appears in a Delphi portability header file with a .hpp extension.
Note: Another argument, delphireturn
, is used internally to mark C++ classes for VCL-compatible handling in function calls as parameters and return values. The
delphiclass argument is used to create classes that have 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 or multiple inheritance is allowed.
• Must be dynamically allocated by using the global new operator.
• Copy and assignment constructors must be explicitly defined. The compiler does not automatically provide these constructors
for VCL-derived classes.
• Must publicly inherit from another VCL class.
Here is a sample:
TTest = class;
TTest = class
public
// Class methods
class function add(I, J: Integer): Integer;
class function GetClsName: string;
3 // Virtual class method
class function GetClsNameVirt: string; virtual;
406
3.1 C++ Reference RAD Studio C++ Language Guide
// Class static
class function GetStaticCount: Integer; static;
class procedure SetStaticCount(I: Integer); static;
// Class properties
property Count: Integer read GetCount write SetCount; // Non-virtual
property StrProp: string read GetStrProp write SetStrProp; // Virtual g/setters
end;
Here is an example of this usage, attempting to define the same methods and properties as in the Delphi sample above. Note
that some of the Delphi class method features cannot be done properly using this metaclass approach.
// All metaclass types are TMetaClass* in C++
typedef TMetaClass* TTestClass;
// You can overload these virtual setters and getters, but given
// that the call is incorrect, the program fails
// when accessing the property tied to these methods.
virtual UnicodeString __fastcall GetStrProp(TMetaClass* vmt);
virtual void __fastcall SetStrProp(TMetaClass* vmt, UnicodeString N);
407
C++ Language Guide RAD Studio 3.1 C++ Reference
There are several limitations with this way of exposing class methods using an explicit TMetaClass* parameter:
• C++ code cannot properly invoke virtual class methods. C++ calls would have to pass two hidden this parameters: the pointer
to the instance of the object and the explicit TMetaClass* parameter. However, the function expects only one
TMetaClass* parameter.
• Even in cases where the call to a virtual class method succeeds, the C++ code must have an instance of the object to invoke
the method, but a proper class method should be invokable without requiring an object instance.
• C++ code cannot properly access properties whose getters or setters are class methods, because there's no way to provide
the TMetaClass* parameter, which must be explicit.
Class Methods Using __classmethod Keyword
C++Builder 2009 introduces class methods that remove the limitations listed above and provide a simpler and more intuitive
syntax for class methods. Class methods are now declared with the new keyword __classmethod.
Here is how the code above is written using the __classmethod syntax:
// Class references still use TMetaClass*.
typedef TMetaClass* TTestClass;
public:
// The TMetaClass* parameter is now hidden.
// The __classmethod keyword flags methods as class methods.
__classmethod int __fastcall add(int I, int J);
__classmethod UnicodeString __fastcall GetClsName();
// Class properties
__property int Count = {read=GetCount, write=SetCount, nodefault};
__property UnicodeString StrProp = {read=GetStrProp, write=SetStrProp};
};
C++Builder does not provide for a way to declare a class reference other than by TMetaClass*. Hence, class methods are
invoked with a typename or with an instance of a object. Virtual class methods are invoked the same way regular virtual methods
are invoked, except that instead of the this pointer being pushed, the metaclass pointer is the hidden parameter.
408
3.1 C++ Reference RAD Studio C++ Language Guide
The "virtual" mechanism of class methods is analogous to virtual for regular methods. For regular methods, you get
polymorphism only when using a pointer or a reference, because the vtable is then determined at run time. With a value
instance, you don't get polymorphism because the vtable is determine at compile time.
Similarly, for class methods you get polymorphism with an instance but not with a type. To illustrate:
class TBase {
virtual __classmethod void cfunc();
virtual void vfunc();
};
TBase& br = TDerived();
br.vfunc(); //calls TDerived::vfunc;
TBase b;
b.vfunc(); //calls TBase::vfunc
// Class virtual methods
TBase* b = new TDerived();
b->cfunc(); //calls version in TDerived--dynamic
TDerived::cfunc(); //calls version in TDerived--compile time--not dynamic
__classid(TDerived)->cfunc(); //compiler error
Purpose of code Old style “class static” code Updated code using __classmethod
Function class TTest : public System::TObject { public: static int class TTest : public System::TObject { public:
declaration __fastcall add(TMetaClass* vmt, int I, int J); }; __classmethod int __fastcall add(int I, int J); };
Using __classid TTest::add(__classid(TTest), 10, 20); TTest::add(10, 20);
Using derived TTestDerived::add(__classid(TTestDerived), 10, 20); TTestDerived::add(10, 20);
__classid
Using class TTest* p = new TTest(); ... TTest::add(p->ClassType(), TTest* p = new TTest(); ... p->add(10, 20);
instance 10, 20); 3
Using derived TTest* p = new TTestDerived(); ... TTest* p = new TTestDerived(); ... p->add(10, 20);
instance TTest::add(p->ClassType(), 10, 20);
Using class TTest* p = new TTest(); ... p->Count = 20; TTest::Count = 20; //Using class name // Using
property instance TTest* p = new TTest(); ... p->Count =
20;
409
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
C++ Classes ( see page 387)
TMyClass::X = 5;
int y = TMyClass::X;
Delphi also allows plain static methods as getters and setters of properties. Note that these static methods are not class
methods; there is no hidden parameter. For example:
class TTest{
static int __fastcall GetCount();
static void __fastcall SetCount(int I);
3 public:
__property int Count = {read=GetCount, write=SetCount};
};
In this case, you can then use the properties as this:
int c = TTest::Count;
TTest t;
int i = t.Count;
The C++ compiler already supports static properties that map to a member variable. For example:
410
3.1 C++ Reference RAD Studio C++ Language Guide
class TEncoding {
static int Prop;
public:
__property int Count = { read=Prop };
};
int f(TEncoding& t) {
return t.Count;
}
See Also
C++ Classes ( see page 387)
Topics
Name Description
Using Angle Brackets In Templates ( see page 412) Be careful when using the right angle bracket character upon instantiation:
Template Arguments ( see page 412) Multiple arguments are allowed as part of the class template declaration.
Template arguments can also represent values in addition to data types:
Class Templates ( see page 412) A class template (also called a generic class or class generator) lets you define a
pattern for class definitions. Consider the following example of a vector class (a
one-dimensional array). Whether you have a vector of integers or any other type,
the basic operations performed on the type are the same (insert, delete, index,
and so on). With the element type treated as a type parameter to the class, the
system will generate type-safe class definitions on the fly. 3
As with function templates, an explicit template class specialization can be
provided to override the automatic definition for a given type:... more ( see
page 412)
Eliminating Pointers In Templates ( see page 412) Another design technique is to include actual objects, making pointers
unnecessary. This can also reduce the number of virtual function calls required,
since the compiler knows the actual types of the objects. This is beneficial if the
virtual functions are small enough to be effectively inlined. It's difficult to inline
virtual functions when called through pointers, because the compiler doesn't
know the actual types of the objects being pointed to.
411
C++ Language Guide RAD Studio 3.1 C++ Reference
Using Type-safe Generic Lists In Templates ( see page 413) In general, when you need to write lots of nearly identical things, consider using
templates. The problems with the following class definition, a generic list class,
As with function templates, an explicit template class specialization can be provided to override the automatic definition for a
given type:
class Vector<char *> { ... };
The symbol Vector must always be accompanied by a data type in angle brackets. It cannot appear alone, except in some cases
in the original template definition.
See Also
Exporting And Importing Templates ( see page 432)
412
3.1 C++ Reference RAD Studio C++ Language Guide
.
.
.
private:
T buffer;
};
class anObject : public aSubject, public aBase<aFilebuf> {
.
.
.
};
All the functions in aBase can call functions defined in aFilebuf directly, without having to go through a pointer. And if any of the
functions in aFilebuf can be inlined, you'll get a speed improvement, because templates allow them to be inlined.
By using templates, you can create whatever type-safe lists you want, as needed, with a simple declaration. And there's no code
generated by the type conversions from each wrapper class so there's no runtime overhead imposed by this type safety.
413
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Template Compiler Switches ( see page 414) The -Jg family of switches control how instances of templates are generated by
the compiler. Every template instance encountered by the compiler will be
affected by the value of the switch at the point where the first occurrence of that
particular instance is seen by the compiler.
For template functions the switch applies to the function instances; for template
classes, it applies to all member functions and static data members of the
template class. In all cases, this switch applies only to compiler-generated
template instances and never to user-defined instances. It can be used, however,
to tell the compiler which... more ( see page 414)
Template Generation Semantics ( see page 414) The C++ compiler generates the following methods for template instances:
For template functions the switch applies to the function instances; for template classes, it applies to all member functions and
static data members of the template class. In all cases, this switch applies only to compiler-generated template instances and
never to user-defined instances. It can be used, however, to tell the compiler which instances will be user-defined so that they
aren't generated from the template.
414
3.1 C++ Reference RAD Studio C++ Language Guide
The following STL example directs the compiler to generate all out-of-line methods for the “list<char>” class, regardless of
whether they are referenced by the user’s code:
template class list<char>
You can also explicitly instantiate a single method, or a single static data member of a template class, which means that the
method is generated to the .OBJ even though it is not used:
template void classname <template parameter>:: methodname ();
Topics
Name Description
Introduction To Constructors And Destructors ( see page 415) There are several special member functions that determine how the objects of a
class are created, initialized, copied, and destroyed. Constructors and
destructors are the most important of these. They have many of the
characteristics of normal member functions—you declare and define them within
the class, or declare them within the class and define them outside—but they
have some unique features:
415
C++ Language Guide RAD Studio 3.1 C++ Reference
• You cannot call constructors the way you call a normal function. Destructors can be called if you use their fully qualified name.
{
.
.
.
X *p;
.
.
.
p–>X::~X(); // legal call of destructor
X::X(); // illegal call of constructor
.
.
.
}
• The compiler automatically calls constructors and destructors when defining and destroying objects.
• Constructors and destructors can make implicit calls to operator new and operator delete if allocation is required for an
object.
• An object with a constructor or destructor cannot be used as a member of a union.
• If no constructor has been defined for some class X to accept a given type, no attempt is made to find other constructors or
conversion functions to convert the assigned value into a type acceptable to a constructor for class X. Note that this rule
applies only to any constructor with one parameter and no initializers that use the “=” syntax.
class X { /* ... */ X(int); };
class Y { /* ... */ Y(X); };
Y a = 1; // illegal: Y(X(1)) not tried
If class X has one or more constructors, one of them is invoked each time you define an object x of class X. The constructor
creates x and initializes it. Destructors reverse the process by destroying the class objects created by constructors.
Constructors are also invoked when local or temporary objects of a class are created; destructors are invoked when these
objects go out of scope.
3.1.3.1.4.2 Constructors
This section contains Constructor topics.
Topics
Name Description
Class Initialization ( see page 417) An object of a class with only public members and no constructors or base
classes (typically a structure) can be initialized with an initializer list. If a class has
a constructor, its objects must be either initialized or have a default constructor.
The latter is used for objects not explicitly initialized.
Objects of classes with constructors can be initialized with an expression list in
parentheses. This list is used as an argument list to the constructor. An
alternative is to use an equal sign followed by a single value. The single value
can be the same type as the first... more ( see page 417)
Constructor Defaults ( see page 419) The default constructor for class X is one that takes no arguments; it usually has
the form X::X(). If no user-defined constructors exist for a class, the compiler
generates a default constructor. On a declaration such as X x, the default
constructor creates the object x.
3 Like all functions, constructors can have default arguments. For example, the
constructor
Constructors ( see page 419) Constructors are distinguished from all other member functions by having the
same name as the class they belong to. When an object of that class is created
or is being copied, the appropriate constructor is called implicitly.
Constructors for global variables are called before the main function is called.
Global variable constructors are also called prior to #pragma startup functions.
Local objects are created as the scope of the variable becomes active. A
constructor is also invoked when a temporary object of the class is created.
416
3.1 C++ Reference RAD Studio C++ Language Guide
Order Of Calling Constructors ( see page 420) In the case where a class has one or more base classes, the base class
constructors are invoked before the derived class constructor. The base class
constructors are called in the order they are declared.
For example, in this setup,
Overloading Constructors ( see page 421) Constructors can be overloaded, allowing objects to be created, depending on
the values being used for initialization.
The Copy Constructor ( see page 421) A copy constructor for class X is one that can be called with a single argument of
type X as follows:
Objects of classes with constructors can be initialized with an expression list in parentheses. This list is used as an argument list
to the constructor. An alternative is to use an equal sign followed by a single value. The single value can be the same type as the
first argument accepted by a constructor of that class, in which case either there are no additional arguments, or the remaining
arguments have default values. It could also be an object of that class type. In the former case, the matching constructor is
called to create the object. In the latter case, the copy constructor is called to initialize the object.
class X
{
int i;
public:
X(); // function bodies omitted for clarity
X(int x);
X(const X&);
};
void main()
{
X one; // default constructor invoked
X two(1); // constructor X::X(int) is used
X three = 1; // calls X::X(int)
X four = one; // invokes X::X(const X&) for copy
X five(two); // calls X::X(const X&)
}
The constructor can assign values to its members in two ways:
1. It can accept the values as parameters and make assignments to the member variables within the function body of the
constructor:
class X
{
int a, b;
public:
X(int i, int j) { a = i; b = j }
};
2. An initializer list can be used prior to the function body:
class X
{
int a, b, &c; // Note the reference variable.
public: 3
X(int i, int j) : a(i), b(j), c(a) {}
};
The initializer list is the only place to initialize a reference variable.
In both cases, an initialization of X x(1, 2) assigns a value of 1 to x::a and 2 to x::b. The second method, the initializer list,
provides a mechanism for passing values along to base class constructors.
417
C++ Language Guide RAD Studio 3.1 C++ Reference
As described previously, the base classes are initialized in declaration order. Then the members are initialized, also in
declaration order, independent of the initialization list.
class X
{
int a, b;
public:
X(int i, j) : a(i), b(a+j) {}
};
With this class, a declaration of X x(1,1) results in an assignment of 1 to x::a and 2 to x::b.
Base class constructors are called prior to the construction of any of the derived classes members. If the values of the derived
class are changed, they will have no effect on the creation of the base class.
class base
{
int x;
public:
base(int i) : x(i) {}
};
class derived : base
{
int a;
public:
derived(int i) : a(i*10), base(a) { } // Watch out! Base will be
// passed an uninitialized ’a’
};
With this class setup, a call of derived d(1) will not result in a value of 10 for the base class member x. The value passed to the
base class constructor will be undefined.
3 When you want an initializer list in a non-inline constructor, don’t place the list in the class definition. Instead, put it at the point at
which the function is defined.
derived::derived(int i) : a(i)
{
.
.
.
}
418
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Invoking Destructors ( see page 424)
Like all functions, constructors can have default arguments. For example, the constructor
X::X(int, int = 0)
can take one or two arguments. When presented with one argument, the missing second argument is assumed to be a zero int.
Similarly, the constructor
X::X(int = 5, int = 6)
could take two, one, or no arguments, with appropriate defaults. However, the default constructor X::X() takes no arguments and
must not be confused with, say, X::X(int = 0), which can be called with no arguments as a default constructor, or can take an
argument.
You should avoid ambiguity in defining constructors. In the following case, the two default constructors are ambiguous:
class X
{
public:
X();
X(int i = 0);
};
int main()
{
X one(10); // OK; uses X::X(int)
X two; // Error;ambiguous whether to call X::X() or
// X::X(int = 0)
return 0;
}
See Also
Constructors ( see page 419)
3.1.3.1.4.2.3 Constructors
Constructors are distinguished from all other member functions by having the same name as the class they belong to. When an
object of that class is created or is being copied, the appropriate constructor is called implicitly. 3
Constructors for global variables are called before the main function is called. Global variable constructors are also called prior to
#pragma startup functions.
Local objects are created as the scope of the variable becomes active. A constructor is also invoked when a temporary object of
the class is created.
class X {
public:
419
C++ Language Guide RAD Studio 3.1 C++ Reference
If a virtual class is derived from a nonvirtual base, that nonvirtual base will be first so that the virtual base class can be properly
constructed. The code:
class X : public Y, virtual public Z
X one;
produces this order:
Z(); // virtual base class initialization
Y(); // nonvirtual base class
X(); // derived class
3 Or, for a more complicated example:
class base;
class base2;
class level1 : public base2, virtual public base;
class level2 : public base2, virtual public base;
class toplevel : public level1, virtual public level2;
toplevel view;
The construction order of view would be as follows:
420
3.1 C++ Reference RAD Studio C++ Language Guide
Constructors for elements of an array are called in increasing order of the subscript.
See Also
Class Initialization ( see page 417)
421
C++ Language Guide RAD Studio 3.1 C++ Reference
or
X::X(const X&)
or
X::X(const X&, int = 0)
Default arguments are also allowed in a copy constructor. Copy constructors are invoked when initializing a class object, typically
when you declare with initialization by another class object:
X x1;
X x2 = x1;
X x3(x1);
The compiler generates a copy constructor for class X if one is needed and no other constructor has been defined in class X.
The copy constructor that is generated by the compiler lets you safely start programming with simple data types. You need to
make your own definition of the copy constructor if your program creates aggregate, complex types such as class, struct, and
array types. The copy constructor is also called when you pass a class argument by value to a function.
See also the discussion of member-by-member class assignment. You should define the copy constructor if you overload the
assignment operator.
See Also
Constructor Defaults ( see page 419)
3.1.3.1.4.3 Destructors
This section contains Destructor topics.
Topics
Name Description
Destructors ( see page 423) The destructor for a class is called to free members of an object before the object
is itself destroyed. The destructor is a member function whose name is that of the
class preceded by a tilde (~). A destructor cannot accept any parameters, nor will
it have a return type or value declared.
Exit And Destructors ( see page 423) When you call exit from within a program, destructors are not called for any local
variables in the current scope. Global variables are destroyed in their normal
order.
Invoking Destructors ( see page 424) A destructor is called implicitly when a variable goes out of its declared scope.
3 Destructors for local variables are called when the block they are declared in is
no longer active. In the case of global variables, destructors are called as part of
the exit procedure after the main function.
When pointers to objects go out of scope, a destructor is not implicitly called. This
means that the delete operator must be called to destroy such an object.
Destructors are called in the exact opposite order from which their corresponding
constructors were called (see Order of calling constructors).
Virtual Destructors ( see page 424) A destructor can be declared as virtual. This allows a pointer to a base class
object to call the correct destructor in the event that the pointer actually refers to
a derived class object. The destructor of a class derived from a class with a
virtual destructor is itself virtual.
422
3.1 C++ Reference RAD Studio C++ Language Guide
abort And Destructors ( see page 425) If you call abort anywhere in a program, no destructors are called, not even for
variables with a global scope.
A destructor can also be invoked explicitly in one of two ways: indirectly through
a call to delete, or directly by using the destructor’s fully qualified name. You can
use delete to destroy objects that have been allocated using new. Explicit calls
to the destructor are necessary only for objects allocated a specific address
through calls to new
atexit, #pragma exit, And Destructors ( see page 426) All global objects are active until the code in all exit procedures has executed.
Local variables, including those declared in the main function, are destroyed as
they go out of scope. The order of execution at the end of a program is as follows:
3.1.3.1.4.3.1 Destructors
The destructor for a class is called to free members of an object before the object is itself destroyed. The destructor is a member
function whose name is that of the class preceded by a tilde (~). A destructor cannot accept any parameters, nor will it have a
return type or value declared.
#include <stdlib.h>
class X
{
public:
~X(){}; // destructor for class X
};
If a destructor isn’t explicitly defined for a class, the compiler generates one.
See Also
Class Initialization ( see page 417)
See Also
Class Initialization ( see page 417)
3
Invoking Destructors ( see page 424)
423
C++ Language Guide RAD Studio 3.1 C++ Reference
When pointers to objects go out of scope, a destructor is not implicitly called. This means that the delete operator must be called
to destroy such an object.
Destructors are called in the exact opposite order from which their corresponding constructors were called (see Order of calling
constructors).
See Also
Class Initialization ( see page 417)
424
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Class Initialization ( see page 417)
A destructor can also be invoked explicitly in one of two ways: indirectly through a call to delete, or directly by using the
destructor’s fully qualified name. You can use delete to destroy objects that have been allocated using new. Explicit calls to the
destructor are necessary only for objects allocated a specific address through calls to new
#include <stdlib.h>
class X {
public:
.
.
.
~X(){};
.
.
.
};
void* operator new(size_t size, void *ptr)
{
return ptr;
}
char buffer[sizeof(X)];
void main()
{
X* pointer = new X; 3
X* exact_pointer;
exact_pointer = new(&buffer) X; // pointer initialized at
// address of buffer
.
.
.
delete pointer; // delete used to destroy pointer
exact_pointer–>X::~X(); // direct call used to deallocate
}
425
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
Class Initialization ( see page 417)
Topics
Name Description
Declaring A namespace ( see page 427) An original namespace declaration should use an identifier that has not been
previously used as a global identifier.
Accessing Elements Of A namespace ( see page 427) There are three ways to access the elements of a namespace: by explicit access
qualification, the using-declaration, or the using-directive. Remember that no
matter which namespace you add to your local scope, identifiers in global scope
(global scope is just another namespace) are still accessible by using the scope
resolution operator ::.
426
3.1 C++ Reference RAD Studio C++ Language Guide
Explicit Access Qualification ( see page 428) You can explicitly qualify each member of a namespace. To do so, you use the
namespace identifier together with the :: scope resolution operator followed by
the member name. For example, to access a specific member of namespace
ALPHA, you write:
Extending A namespace ( see page 428) Namespaces are discontinuous and open for additional development. If you
redeclare a namespace, the effect is that you extend the original namespace by
adding new declarations. Any extensions that are made to a namespace after a
using-declaration, will not be known at the point at which the using-declaration
occurs. Therefore, all overloaded versions of some function should be included in
the namespace before you declare the function to be in use.
namespace Alias ( see page 429) You can use an alternate name to refer to a namespace identifier. An alias is
useful when you need to refer to a long, unwieldy namespace identifier.
using Directive ( see page 429) If you want to use several (or all of) the members of a namespace, C++ provides
an easy way to get access to the complete namespace. The using-directive
causes all identifiers in a namespace to be in scope at the point that the
using-directive statement is made. The grammar for the using-directive is as
follows.
using-directive:
using namespace :: opt nested-name-specifier opt namespace-name;
The using-directive is transitive. When you apply the using directive to a
namespace that contains using directives within itself, you get access to those
namespaces as well. For example, if you apply the using directive in your... more
( see page 429)
See Also
namespace Alias ( see page 429)
427
C++ Language Guide RAD Studio 3.1 C++ Reference
Each identifier that is enclosed within an unnamed namespace is unique within the translation unit in which the unnamed
namespace is defined.
3 New-style typecasting
This section presents a discussion of alternate methods for making a typecast. The methods presented here augment the earlier
cast expressions (which are still available) in the C language.
428
3.1 C++ Reference RAD Studio C++ Language Guide
the original namespace by adding new declarations. Any extensions that are made to a namespace after a using-declaration, will
not be known at the point at which the using-declaration occurs. Therefore, all overloaded versions of some function should be
included in the namespace before you declare the function to be in use.
using-directive:
The using-directive is transitive. When you apply the using directive to a namespace that contains using directives within itself,
you get access to those namespaces as well. For example, if you apply the using directive in your program, you also get
namespaces qux, foo, and bar.
namespace qux {
using namespace foo; // This has been defined previously
using namespace bar; // This also has been defined previously
}
The using-directive does not add any identifiers to your local scope. Therefore, an identifier defined in more than one namespace
won't be a problem until you actually attempt to use it. Local scope declarations take precedence by hiding all other similar
declarations.
directive in header files. You might accidentally break namespaces in client code.
See Also
Accessing Elements Of A namespace ( see page 427)
429
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
C++ Scope ( see page 430) The lexical scoping rules for C++, apart from class scope, follow the general rules
for C, with the proviso that C++, unlike C, permits both data and function
declarations to appear wherever a statement might appear. The latter flexibility
means that care is needed when interpreting such phrases as “enclosing scope”
and “point of declaration.”
C++ Scoping Rules Summary ( see page 431) The following rules apply to all names, including typedef names and class
names, provided that C++ allows such names in the particular context discussed:
• In member functions of X
• In expressions such as x.M, where x is an object of X
• In expressions such as xptr->M, where xptr is a pointer to
an object of X
• In expressions such as X::M or D::M, where D is a derived
class of X
• In forward references within the class of which it is a
member
Names of functions declared as friends of X are not
members of X; their names simply... more ( see page
431)
Hiding ( see page 432) A name can be hidden by an explicit declaration of the same name in an
enclosed block or in a class. A hidden class member is still accessible using the
scope modifier with a class name: X::M. A hidden file scope (global) name can be
referenced with the unary operator :: (for example, ::g). A class name X can be
hidden by the name of an object, function, or enumerator declared within the
scope of X, regardless of the order in which the names are declared. However,
the hidden class name X can still be accessed by prefixing X with... more ( see
page 432)
430
3.1 C++ Reference RAD Studio C++ Language Guide
• The name itself is tested for ambiguity. If no ambiguities are detected within its scope, the access sequence is initiated.
• If no access control errors occur, the type of the object, function, class, typedef, and so on, is tested.
• If the name is used outside any function and class, or is prefixed by the unary scope access operator ::, and if the name is not
qualified by the binary :: operator or the member selection operators . and ->, then the name must be a global object, function,
or enumerator.
• If the name n appears in any of the forms X::n, x.n (where x is an object of X or a reference to X), or ptr->n (where ptr is a
pointer to X), then n is the name of a member of X or the member of a class from which X is derived.
• Any name that hasn’t been discussed yet and that is used in a static member function must either be declared in the block it
occurs in or in an enclosing block, or be a global name. The declaration of a local name n hides declarations of n in enclosing
blocks and global declarations of n. Names in different scopes are not overloaded.
• Any name that hasn’t been discussed yet and that is used in a nonstatic member function of class X must either be declared
in the block it occurs in or in an enclosing block, be a member of class X or a base class of X, or be a global name. The
declaration of a local name n hides declarations of n in enclosing blocks, members of the function’s class, and global
declarations of n. The declaration of a member name hides declarations of the same name in base classes.
• The name of a function argument in a function definition is in the scope of the outermost block of the function. The name of a
function argument in a nondefining function declaration has no scope at all. The scope of a default argument is determined by
the point of declaration of its argument, but it can’t access local variables or nonstatic class members. Default arguments are
evaluated at each point of call.
• A constructor initializer is evaluated in the scope of the outermost block of its constructor, so it can refer to the constructor’s
argument names.
See Also
C++ Scope ( see page 430)
• In member functions of X
• In expressions such as x.M, where x is an object of X
• In expressions such as xptr->M, where xptr is a pointer to an object of X
• In expressions such as X::M or D::M, where D is a derived class of X
• In forward references within the class of which it is a member
Names of functions declared as friends of X are not members of X; their names simply have enclosing scope.
See Also 3
C++ Scope ( see page 430)
431
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.1.6.4 Hiding
A name can be hidden by an explicit declaration of the same name in an enclosed block or in a class. A hidden class member is
still accessible using the scope modifier with a class name: X::M. A hidden file scope (global) name can be referenced with the
unary operator :: (for example, ::g). A class name X can be hidden by the name of an object, function, or enumerator declared
within the scope of X, regardless of the order in which the names are declared. However, the hidden class name X can still be
accessed by prefixing X with the appropriate keyword: class, struct, or union.
The point of declaration for a name x is immediately after its complete declaration but before its initializer, if one exists.
See Also
C++ Scope ( see page 430)
Topics
Name Description
Exporting And Importing Templates ( see page 432) The declaration of a template function or template class needs to be sufficiently
flexible to allow it to be used in either a dynamic link library (shared library) or an
executable file. The same template declaration should be available as an import
and/or export, or without a modifier. To be completely flexible, the header file
template declarations should not use __export or __import modifiers. This
allows the user to apply the appropriate modifier at the point of instantiation
depending on how the instantiation is to be used.
The following steps demonstrate exporting and importing of templates. The
source code is... more ( see page 432)
The following steps demonstrate exporting and importing of templates. The source code is organized in three files. Using the
header file, code is generated in the dynamic link library.
432
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Function Templates ( see page 433) Consider a function max(x, y) that returns the larger of its two arguments. x and y
can be of any type that has the ability to be ordered. But, since C++ is a strongly
typed language, it expects the types of the parameters x and y to be declared at
compile time. Without using templates, many overloaded versions of max are
required, one for each data type to be supported even though the code for each
version is essentially identical. Each version compares the arguments and
returns the larger.
One way around this problem is to use a macro:
Implicit And Explicit Template Functions ( see page 434) When doing overload resolution (following the steps of looking for an exact
match), the compiler ignores template functions that have been generated
implicitly by the compiler.
Overriding A Template Function ( see page 434) The previous example is called a function template (or generic function, if you
like). A specific instantiation of a function template is called a template function.
Template function instantiation occurs when you take the function address, or
when you call the function with defined (non-generic) data types. You can
override the generation of a template function for a specific type with a
non-template function:
Another problem with the macro approach is that substitution will be performed where you don't want it to be. By using a
template instead, you can define a pattern for a family of related overloaded functions by letting the data type itself be a
parameter:
template <class T> T max(T x, T y){
return (x > y) ? x : y;
};
The data type is represented by the template argument <class T>. When used in an application, the compiler generates the
appropriate code for the max function according to the data type actually used in the call:
int i;
Myclass a, b;
int j = max(i,0); // arguments are integers 3
Myclass m = max(a,b); // arguments are type Myclass
Any data type (not just a class) can be used for <class T>. The compiler takes care of calling the appropriate operator>(), so
you can use max with arguments of any type for which operator>() is defined.
See Also
Exporting And Importing Templates ( see page 432)
433
C++ Language Guide RAD Studio 3.1 C++ Reference
When searching for an exact match for template function parameters, trivial conversions are considered to be exact matches.
See the example on trivial conversions.
Template functions with derived class pointer or reference arguments are permitted to match their public base classes. See the
example of base class referencing.
Only trivial argument conversions are performed with compiler-generated template functions.
The argument type(s) of a template function must use all of the template formal arguments. If it doesn't, there is no way of
deducing the actual values for the unused template arguments when the function is called.
434
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Handling Errors For The New Operator ( see page 435) By default, new throws the bad_alloc exception when a request for memory
allocation cannot be satisfied.
You can define a function to be called if the new operator fails. To tell the new
operator about the new-handler function, use set_new_handler and supply a
pointer to the new-handler. If you want new to return null on failure, you must use
set_new_handler(0) .
Operator new Placement Syntax ( see page 436) The placement syntax for operator new( ) can be used only if you have
overloaded the allocation operator with the appropriate arguments. You can use
the placement syntax when you want to use and reuse a memory space which
you set up once at the beginning of your program.
When you use the overloaded operator new( ) to specify where you want an
allocation to be placed, you are responsible for deleting the allocation. Because
you call your version of the allocation operator, you cannot depend on the global
::operator delete( ) to do the cleanup.
To release memory, you... more ( see page 436)
Overloading The Operator delete ( see page 436) The global operators, ::operator delete(), and ::operator delete[]() cannot be
overloaded. However, you can override the default version of each of these
operators with your own implementation. Only one instance of the each global
delete function can exist in the program.
The user-defined operator delete must have a void return type and void* as its
first argument; a second argument of type size_t is optional. A class T can define
at most one version of each of T::operator delete[]() and T::operator delete().
To overload the delete operators, use the following prototypes.
You can define a function to be called if the new operator fails. To tell the new operator about the new-handler function, use
set_new_handler and supply a pointer to the new-handler. If you want new to return null on failure, you must use
set_new_handler(0) .
435
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
new ( see page 556)
When you use the overloaded operator new( ) to specify where you want an allocation to be placed, you are responsible for
deleting the allocation. Because you call your version of the allocation operator, you cannot depend on the global ::operator
delete( ) to do the cleanup.
To release memory, you make an explicit call on the destructor. This method for cleaning up memory should be used only in
special situations and with great care. If you make an explicit call of a destructor before an object that has been constructed on
the stack goes out of scope, the destructor will be called again when the stackframe is cleaned up.
See Also
The keyword new ( see page 556)
The user-defined operator delete must have a void return type and void* as its first argument; a second argument of type size_t
is optional. A class T can define at most one version of each of T::operator delete[]() and T::operator delete(). To overload the
delete operators, use the following prototypes.
Class-specific memory allocation operators can also be overloaded. The operator new can be implemented to provide
alternative free storage (heap) memory-management routines, or implemented to accept additional arguments. A user-defined
operator new must return a void* and must have a size_t as its first argument. To overload the new operators, use the following
prototypes declared in the new.h header file.
3
• void * operator new(size_t Type_size); // For Non-array
• void * operator new[](size_t Type_size); // For arrays
The compiler provides Type_size to the new operator. Any data type may be substituted for Type_size except function names
(although a pointer to function is permitted), class declarations, enumeration declarations, const, volatile.
See Also
The keyword new ( see page 556)
436
3.1 C++ Reference RAD Studio C++ Language Guide
Only the operator new() function will accept an optional initializer. The array allocator version, operator new[](), will not accept
initializers. In the absence of explicit initializers, the object created by new contains unpredictable data (garbage). The objects
allocated by new, other than arrays, can be initialized with a suitable expression between parentheses:
int_ptr = new int(3);
Arrays of classes with constructors are initialized with the default constructor. The user-defined new operator with customized
initialization plays a key role in C++ constructors for class-type objects.
See Also
Overloading The Operator New ( see page 436)
See Also
The keyword new ( see page 556)
437
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
New-style Typecasting ( see page 438) This section presents a discussion of alternate methods for making a typecast.
The methods presented here augment the earlier cast expressions (which are
still available) in the C language.
Types cannot be defined in a cast.
See Also
Const_cast (typecast Operator) ( see page 539)
Topics
Name Description
How To Construct A Class Of Complex Vectors ( see page 438) This section contains How to Construct A Class Of Complex Vector topics.
Overloading Operators ( see page 441) C++ lets you redefine the actions of most operators, so that they perform
specified functions when used with objects of a particular class. As with
overloaded C++ functions in general, the compiler distinguishes the different
functions by noting the context of the call: the number and types of the
arguments or operands.
All the operators can be overloaded except for:
438
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Example Of Overloading Operators ( see page 439) The following example extends the class complex to create complex-type
vectors. Several of the most useful operators are overloaded to provide some
customary mathematical operations in the usual mathematical syntax.
Some of the issues illustrated by the example are:
• The default constructor is defined. The default constructor is provided by the compiler only if you have not defined it or any
other constructor.
• The copy constructor is defined explicitly. Normally, if you have not defined any constructors, the compiler will provide one.
You should define the copy constructor if you are overloading the assignment operator.
• The assignment operator is overloaded. If you do not overload the assignment operator, the compiler calls a default
assignment operator when required. By overloading assignment of cvector types, you specify exactly the actions to be taken.
Note that derived classes cannot inherit the assignment operator.
• The subscript operator is defined as a member function (a requirement when overloading) with a single argument. The const
version assures the caller that it will not modify its argument—this is useful when copying or assigning. This operator should
check that the index value is within range—a good place to implement exception handling.
• The addition operator is defined as a member function. It allows addition only for cvector types. Addition should always check
that the operands’ sizes are compatible.
• The multiplication operator is declared a friend. This lets you define the order of the operands. An attempt to reverse the
order of the operands is a compile-time error.
• The stream insertion operator is overloaded to naturally display a cvector. Large objects that don’t display well on a limited
size screen might require a different display strategy.
Example Source
/* HOW TO EXTEND THE complex CLASS AND OVERLOAD THE REQUIRED OPERATORS. */
complexcomplexcomplex
#include <complex> // This includes iostream
using namespace std;
// COMPLEX VECTORS 3
template <class T>
class cvector {
int size;
complex<T> *data;
public:
cvector() { size = 0; data = NULL; };
cvector(int i = 5) : size(i) { // DEFAULT VECTOR SIZE.
data = new complex<T>[size];
for (int j = 0; j < size; j++)
data[j] = j + (0.1 * j); // ARBITRARY INITIALIZATION.
439
C++ Language Guide RAD Studio 3.1 C++ Reference
};
/* THIS VERSION IS CALLED IN main() */
complex<T>& operator [](int i) { return data[i]; };
/* THIS VERSION IS CALLED IN ASSIGNMENT OPERATOR AND COPY THE CONSTRUCTOR */
const complex<T>& operator [](int i) const { return data[i]; };
cvector operator +(cvector& A) { // ADDITION OPERATOR
cvector result(A.size); // DO NOT MODIFY THE ORIGINAL
for (int i = 0; i < size; i++)
result[i] = data[i] + A.data[i];
return result;
};
/* BECAUSE scalar * vector MULTIPLICATION IS NOT COMMUTATIVE, THE ORDER OF
THE ELEMENTS MUST BE SPECIFIED. THIS FRIEND OPERATOR FUNCTION WILL ENSURE
PROPER MULTIPLICATION. */
friend cvector operator *(T scalar, cvector& A) {
cvector result(A.size); // DO NOT MODIFY THE ORIGINAL
for (int i = 0; i < A.size; i++)
result.data[i] = scalar * A.data[i];
return result;
}
/* THE STREAM INSERTION OPERATOR. */
friend ostream& operator <<(ostream& out_data, cvector& C) {
for (int i = 0; i < C.size; i++)
out_data << "[" << i << "]=" << C.data[i] << " ";
cout << endl;
return out_data;
};
cvector( const cvector &C ) { // COPY CONSTRUCTOR
size = C.size;
data = new complex<T>[size];
for (int i = 0; i < size; i++)
data[i] = C[i];
}
cvector& operator =(const cvector &C) { // ASSIGNMENT OPERATOR.
if (this == &C) return *this;
delete[] data;
size = C.size;
data = new complex<T>[size];
for (int i = 0; i < size; i++)
data[i] = C[i];
return *this;
};
virtual ~cvector() { delete[] data; }; // DESTRUCTOR
};
int main(void) { /* A FEW OPERATIONS WITH complex VECTORS. */
cvector<float> cvector1(4), cvector2(4), result(4);
// CREATE complex NUMBERS AND ASSIGN THEM TO complex VECTORS
cvector1[3] = complex<float>(3.3, 102.8);
cout << "Here is cvector1:" << endl;
cout << cvector1;
cvector2[3] = complex<float>(33.3, 81);
cout << "Here is cvector2:" << endl;
cout << cvector2;
result = cvector1 + cvector2;
cout << "The result of vector addition:" << endl;
cout << result;
3 result = 10 * cvector2;
cout << "The result of 10 * cvector2:" << endl;
cout << result;
return 0;
}
Output
Here is cvector1:
[0]=(0, 0) [1]=(1.1, 0) [2]=(2.2, 0) [3]=(3.3, 102.8)
Here is cvector2:
440
3.1 C++ Reference RAD Studio C++ Language Guide
The keyword operator followed by the operator symbol is called the operator function name; it is used like a normal function
name when defining the new (overloaded) action for the operator.
A function operator called with arguments behaves like an operator working on its operands in an expression. The operator
function cannot alter the number of arguments or the precedence and associativity rules applying to normal operator use.
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
Topics
Name Description
Overloading The Assignment operator = ( see page 442) The assignment operator=( ) can be overloaded by declaring a nonstatic member
function. For example,
3
Overloading Binary Operators ( see page 442) You can overload a binary operator by declaring a nonstatic member function
taking one argument, or by declaring a non-member function (usually friend)
taking two arguments. If @ represents a binary operator, x@y can be interpreted
as either x.operator@(y) or operator@(x,y) depending on the declarations made.
If both forms have been declared, standard argument matching is applied to
resolve any ambiguity.
Overloading The Class Member Access Operators -> ( see page 443) Syntax
Overloading The Function Call Operator ( ) ( see page 443) Syntax
441
C++ Language Guide RAD Studio 3.1 C++ Reference
Overloading Operator Functions ( see page 444) Operator functions can be called directly, although they are usually invoked
indirectly by the use of the overload operator:
Overloaded Operators And Inheritance ( see page 444) With the exception of the assignment function operator =( ), all overloaded
operator functions for class X are inherited by classes derived from X, with the
standard resolution rules for overloaded functions. If X is a base class for Y, an
overloaded operator function for X could possibly be further overloaded for Y.
Overloading The Subscript Operator [] ( see page 445) Syntax
Overloading Unary Operators ( see page 445) You can overload a prefix or postfix unary operator by declaring a nonstatic
member function taking no arguments, or by declaring a nonmember function
taking one argument. If @ represents a unary operator, @x and x@ can both be
interpreted as either x.operator@() or operator@(x), depending on the
declarations made. If both forms have been declared, standard argument
matching is applied to resolve any ambiguity.
Overloading The Class Member Access Operators -> ( see page 443)
3
Overloading The Function Call Operator ( ) ( see page 443)
442
3.1 C++ Reference RAD Studio C++ Language Guide
x.operator@(y) or operator@(x,y) depending on the declarations made. If both forms have been declared, standard argument
matching is applied to resolve any ambiguity.
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
The expression x->m, where x is a class X object, is interpreted as (x.operator->())->m, so that the function operator->() must
either return a pointer to a class object or return an object of a class for which operator-> is defined.
See Also
Example Of Overloading Operators ( see page 439)
In its ordinary use as a function call, the postfix-expression must be a function name, or a pointer or reference to a function. 3
When the postfix-expression is used to make a member function call, postfix-expression must be a class member function name
or a pointer-to-member expression used to select a class member function. In either case, the postfix-expression is followed by
the optional expression-list.
The function call operator, operator()(), can only be overloaded as a nonstatic member function.
443
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
Enumerations can have overloaded operators. However, the operator functions =, ( ), [ ], and -> cannot be overloaded for
enumerations.
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
444
3.1 C++ Reference RAD Studio C++ Language Guide
The corresponding operator function is operator[]() this can be user-defined for a class X (and any derived classes). The
expression X[y], where X is an object of class X, is interpreted as x.operator[](y).
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
• Under C++ 2.0, an overloaded operator ++ or -- is used for both prefix and postfix uses of the operator.
• With C++ 2.1, when an operator ++ or operator -- is declared as a member function with no parameters, or as a nonmember
function with one parameter, it only overloads the prefix operator ++ or operator --. You can only overload a postfix operator
++ or operator -- by defining it as a member function taking an int parameter or as a nonmember function taking one class and
one int parameter.
When only the prefix version of an operator ++ or operator -- is overloaded and the operator is applied to a class object as a
postfix operator, the compiler issues a warning. Then it calls the prefix operator, allowing 2.0 code to compile. The preceding
example results in the following warnings:
Warning: Overloaded prefix 'operator ++' used as a postfix operator in function func()
Warning: Overloaded prefix 'operator --' used as a postfix operator in function func()
See Also
Example Of Overloading Operators ( see page 439)
Overloading The Class Member Access Operators -> ( see page 443)
445
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Abstract Classes ( see page 446) This section contains Abstract Class topics.
Polymorphic Classes ( see page 447) Classes that provide an identical interface, but can be implemented to serve
different specific requirements, are referred to as polymorphic classes. A class is
polymorphic if it declares or inherits at least one virtual (or pure virtual) function.
The only types that can support polymorphism are class and struct.
Virtual Functions ( see page 447) This section contains Virtual Function topics.
Topics
Name Description
Abstract Classes ( see page 446) An abstract class is a class with at least one pure virtual function. A virtual
function is specified as pure by setting it equal to zero.
An abstract class can be used only as a base class for other classes. No objects
of an abstract class can be created. An abstract class cannot be used as an
argument type or as a function return type. However, you can declare pointers to
an abstract class. References to an abstract class are allowed, provided that a
temporary object is not needed in the initialization. For example,
An abstract class can be used only as a base class for other classes. No objects of an abstract class can be created. An abstract
class cannot be used as an argument type or as a function return type. However, you can declare pointers to an abstract class.
References to an abstract class are allowed, provided that a temporary object is not needed in the initialization. For example,
class shape { // abstract class
point center;
.
.
.
public:
where() { return center; }
move(point p) { center = p; draw(); }
virtual void rotate(int) = 0; // pure virtual function
virtual void draw() = 0; // pure virtual function
virtual void hilite() = 0; // pure virtual function
.
.
3 .
}
shape x;// ERROR: attempt to create an object of an abstract class
shape* sptr;// pointer to abstract class is OK
shape f();// ERROR: abstract class cannot be a return type
int g(shape s);// ERROR: abstract class cannot be a function argument type
shape& h(shape&);// reference to abstract class as return
// value or function argument is OK
Suppose that D is a derived class with the abstract class B as its immediate base class. Then for each pure virtual function pvf in
B, if D doesn’t provide a definition for pvf, pvf becomes a pure member function of D, and D will also be an abstract class.
446
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Polymorphic Classes ( see page 447)
See Also
Virtual Functions ( see page 449)
Topics
Name Description
Dynamic Functions ( see page 447) dynamic functions are allowed for classes derived from TObject. Dynamic
functions are similar to virtual functions except for the way they are stored in the
virtual tables. Virtual functions occupy a slot in the virtual table in the object they
are defined in, and in the virtual table of every descendant of that object.
Dynamic functions occupy a slot in every object that defines them, not in any
descendants. That is, dynamic functions are virtual functions stored in sparse
virtual tables. If you call a dynamic function, and that function is not defined in
your object, the virtual tables of... more ( see page 447)
Virtual Functions ( see page 449) virtual functions allow derived classes to provide different versions of a base
class function. You can use the virtual keyword to declare a virtual function in a
base class. By declaring the function prototype in the usual way and then
prefixing the declaration with the virtual keyword. To declare a pure function
(which automatically declares an abstract class), prefix the prototype with the
virtual keyword, and set the function equal to zero.
3
3.1.3.1.13.3.1 Dynamic Functions
dynamic functions are allowed for classes derived from TObject. Dynamic functions are similar to virtual functions except for the
way they are stored in the virtual tables. Virtual functions occupy a slot in the virtual table in the object they are defined in, and in
the virtual table of every descendant of that object. Dynamic functions occupy a slot in every object that defines them, not in any
descendants. That is, dynamic functions are virtual functions stored in sparse virtual tables. If you call a dynamic function, and
that function is not defined in your object, the virtual tables of its ancestors are searched until the function is found.
447
C++ Language Guide RAD Studio 3.1 C++ Reference
Therefore, dynamic functions reduces the size of your virtual tables at the expense of a delay at runtime to look up the address
of the functions.
Because dynamic functions are available only in classes derived from TObject, you will get an error if you use them in a regular
class. For example:
class dynfunc {
int __declspec(dynamic) bar() { return 5; }
};
gives the syntax error, “Error: Storage class 'dynamic' is not allowed here.” But, the following code compiles.
#include <clxvcl.h>
#include <stdio.h>
class __declspec(delphiclass) func1 : public TObject {
public:
func1() {}
int virtual virtbar() { return 5; }
int __declspec(dynamic) dynbar() { return 5; }
};
class __declspec(delphiclass) func2 : public func1 {
public:
func2() {}
};
class __declspec(delphiclass) func3 : public func2 {
public:
func3() {}
int virtbar() { return 10; }
int dynbar() { return 10; }
};
int main()
{
func3 * Func3 = new func3;
func1 * Func1 = Func3;
printf("func3->dynbar: %d\n", Func3->dynbar());
printf("func3->virtbar: %d\n", Func3->virtbar());
printf("func1->dynbar: %d\n", Func1->dynbar());
printf("func1->virtbar: %d\n", Func1->virtbar());
delete Func3;
func2 * Func2 = new func2;
printf("func2->dynbar: %d\n", Func2->dynbar());
printf("func2->virtbar: %d\n", Func2->virtbar());
delete Func2;
return 0;
}
Dynamic attribute is inherited
Since dynamic functions are just like virtual functions, the dynamic attribute is automatically inherited. You can verify this by
running the above example. When you generate assembly output with "bcc32 -S" you can examine the virtual tables of func1,
func2, and func3, and you'll see how func2 has NO entry for dynbar, but it does have an entry for virtbar. Still, you can call
dynbar in the func2 object:
Output:
3 func3->dynbar: 10
func3->virtbar: 10
func1->dynbar: 10
func1->virtbar: 10
func2->dynbar: 5
func2->virtbar: 5
Dynamic functions cannot be made virtual, and vice-versa
You cannot redeclare a virtual function to be dynamic; likewise, you cannot redeclare a dynamic function to be virtual. The
following example gives errors:
448
3.1 C++ Reference RAD Studio C++ Language Guide
#include <clxvcl.h>
#include <stdio.h>
class __declspec(delphiclass) foo1 : public TObject {
public:
foo1() {}
int virtual virtbar() { return 5; }
int __declspec(dynamic) dynbar() { return 5; }
};
class __declspec(delphiclass) foo2 : public foo1 {
public:
foo2() {}
int __declspec(dynamic) virtbar() { return 10; }
int virtual dynbar() { return 10; }
};
Error : Cannot override a virtual with a dynamic function
Error : Cannot override a dynamic with a virtual function
See Also
Polymorphic Classes ( see page 447)
Dynamic Functions
Example
struct C {
virtual void f() { } = 0; // ill-formed
};
The only legal syntax to provide a body is:
struct TheClass
{
virtual void funct3(void) = 0;
};
virtual void TheClass::funct3(void)
{
// Some code here.
};
Note: See Abstract classesAbstractClasses for a discussion of pure virtual functions. 3
When you declare virtual functions, keep these guidelines in mind:
449
C++ Language Guide RAD Studio 3.1 C++ Reference
To redefine a virtual function in any derived class, the number and type of arguments must be the same in the base class
declaration and in the derived class declaration. (The case for redefined virtual functions differing only in return type is
discussed below.) A redefined function is said to override the base class function.
You can also declare the functions int Base::Fun(int) and int Derived::Fun(int) even when they are not virtual. In such a case, int
Derived::Fun(int) is said to hide any other versions of Fun(int) that exist in any base classes. In addition, if class Derived
defines other versions of Fun(), (that is, versions of Fun() with different signatures) such versions are said to be overloaded
versions of Fun().
Virtual function return types
Generally, when redefining a virtual function, you cannot change just the function return type. To redefine a virtual function, the
new definition (in some derived class) must exactly match the return type and formal parameters of the initial declaration. If
two functions with the same name have different formal parameters, C++ considers them different, and the virtual function
mechanism is ignored.
However, for certain virtual functions in a base class, their overriding version in a derived class can have a return type that is
different from the overridden function. This is possible only when both of the following conditions are met:
• The overridden virtual function returns a pointer or reference to the base class.
• The overriding function returns a pointer or reference to the derived class.
If a base class B and class D (derived publicly from B) each contain a virtual function vf, then if vf is called for an object d of D,
the call made is D::vf(), even when the access is via a pointer or reference to B. For example,
struct X {};// Base class.
struct Y : X {};// Derived class.
struct B {
virtual void vf1();
virtual void vf2();
virtual void vf3();
void f();
virtual X* pf();// Return type is a pointer to base. This can
// be overridden.
};
class D : public B {
public:
virtual void vf1();// Virtual specifier is legal but redundant.
void vf2(int);// Not virtual, since it's using a different
// arg list. This hides B::vf2().
// char vf3();// Illegal: return-type-only change!
void f();
Y* pf();// Overriding function differs only
// in return type. Returns a pointer to
// the derived class.
};
void extf()
{
D d;// Instantiate D
B* bp = &d;// Standard conversion from D* to B*
// Initialize bp with the table of functions
// provided for object d. If there is no entry for a
// function in the d-table, use the function
// in the B-table.
bp–>vf1(); // Calls D::vf1
bp–>vf2(); // Calls B::vf2 since D's vf2 has different args
3 bp–>f(); // Calls B::f (not virtual)
X* xptr = bp–>pf();// Calls D::pf() and converts the result
// to a pointer to X.
D* dptr = &d;
Y* yptr = dptr–>pf();// Calls D::pf() and initializes yptr.
// No further conversion is done.
}
The overriding function vf1 in D is automatically virtual. The virtual specifier can be used with an overriding function declaration
in the derived class. If other classes will be derived from D, the virtual keyword is required. If no further classes will be derived
450
3.1 C++ Reference RAD Studio C++ Language Guide
The interpretation of a virtual function call depends on the type of the object it is called for; with nonvirtual function calls, the
interpretation depends only on the type of the pointer or reference denoting the object it is called for.
virtual functions exact a price for their versatility: each object in the derived class needs to carry a pointer to a table of functions
in order to select the correct one at runtime (late binding).
See Also
Polymorphic Classes ( see page 447)
3.1.3.1.14 Referencing
This section contains Typeid Operator topics.
Topics
Name Description
Reference Arguments ( see page 451) The reference declarator can also be used to declare reference type parameters
within a function:
Referencing ( see page 452) In the C programming language, you can pass arguments only by value. In C++,
you can pass arguments by value or by reference. C++ reference types, closely
related to pointer types, create aliases for objects. See the following topics for a
discussion of referencing.
Note: C++ specific pointer referencing and dereferencing is discussed in C++
specific operators ( see page 590).
Simple References ( see page 453) The reference declarator can be used to declare references outside functions:
When an actual argument x is passed by value, the matching formal argument in the function receives a copy of x. Any changes
to this copy within the function body are not reflected in the value of x outside the scope of the function. Of course, the function
can return a value that could be used later to change x, but the function cannot directly alter a parameter passed by value.
In C, changing the value of a function parameter outside the scope of the function requires that you pass the address of the 3
parameter. The address is passed by value, thus changing the contents of the address effects the value of the parameter outside
the scope of the function.
Even if the function does not need to change the value of a parameter, it is still useful to pass the address (or a reference) to a
function. This is especially true if the parameter is a large data structure or object. Passing an object directly to a function
necessitates copying the entire object.
451
C++ Language Guide RAD Studio 3.1 C++ Reference
Implementation 1
int treble_1(int n)
{
return 3 * n;
}
.
.
.
int x, i = 4;
x = treble_1(i); // x now = 12, i = 4
.
.
.
Implementation 2
void treble_2(int* np)
{
*np = (*np) * 3;
}
.
.
.
treble_2(&i); // i now = 2
Implementation 3
void treble_3(int& n) // n is a reference type
{
n = n * 3;
}
.
.
.
treble_3(i); // i now = 36
The formal argument declaration type& t establishes t as type “reference to type.” So, when treble_3 is called with the real
argument i, i is used to initialize the formal reference argument n. n therefore acts as an alias for i, so n = n*3 also assigns 3 * i to
i.
If the initializer is a constant or an object of a different type than the reference type, creates a temporary object for which the
reference acts as an alias:
int& ir = 6; /* temporary int object created, aliased by ir, gets value 6 */
float f;
int& ir2 = f; /* creates temporary int object aliased by ir2; f converted
before assignment */
ir2 = 2.0 // ir2 now = 2, but f is unchanged
The automatic creation of temporary objects permits the conversion of reference types when formal and actual arguments have
different (but assignment-compatible) types. When passing by value, of course, there are fewer conversion problems, since the
copy of the actual argument can be physically changed before assignment to the formal argument.
See Also
3.1.3.1.14.2 Referencing
In the C programming language, you can pass arguments only by value. In C++, you can pass arguments by value or by
reference. C++ reference types, closely related to pointer types, create aliases for objects. See the following topics for a
discussion of referencing.
452
3.1 C++ Reference RAD Studio C++ Language Guide
Note: C++ specific pointer referencing and dereferencing is discussed in C++ specific operators ( see page 590).
See Also
Simple References ( see page 453)
See Also
Referencing ( see page 452)
Topics
Name Description
Runtime Type Identification (RTTI) Overview ( see page 453) Runtime type identification (RTTI) lets you write portable code that can determine
the actual type of a data object at runtime even when the code has access only
to a pointer or reference to that object. This makes it possible, for example, to
convert a pointer to a virtual base class into a pointer to the derived type of the
actual object. Use the dynamic_cast operator to make runtime casts.
The RTTI mechanism also lets you check whether an object is of some particular
type and whether two objects are of the same type. You can do this with typeid...
more ( see page 453)
The Typeid Operator ( see page 454) This section contains Typeid Operator topics.
The RTTI mechanism also lets you check whether an object is of some particular type and whether two objects are of the same
type. You can do this with typeid operator, which determines the actual type of its argument and returns a reference to an object
of type const type_info, which describes that type.
3
You can also use a type name as the argument to typeid, and typeid will return a reference to a const type_info object for that
type. The class type_info provides an operator== and an operator!= that you can use to determine whether two objects are of
the same type. Class type_info also provides a member function name that returns a pointer to a character string that holds the
name of the type.
453
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
__rtti ( see page 528)
Topics
Name Description
Runtime Type Identification And Destructors ( see page 454) When destructor cleanup is enabled, a pointer to a class with a virtual destructor
can't be deleted if that class is not compiled with runtime type identification
enabled. The runtime type identification and destructor cleanup options are on by
default. They can be disabled from the C++ page of the Project Options dialog
box, or by using the -xd- and -RT- command-line options.
Example
Example
class Alpha {
public:
virtual ~Alpha( ) { }
};
void func( Alpha *Aptr ) {
delete Aptr; // Error. Alpha is not a polymorphic class type
}
Topics
Name Description
Scope Resolution Operator :: ( see page 454) The scope access (or resolution) operator :: (two colons) lets you access a global
(or file duration) member name even if it is hidden by a local redeclaration of that
name. You can use a global identifier by prefixing it with the scope resolution
operator. You can access a nested member name by specifying the class name
and using the scope resolution operator. Therefore, Alpha::func( ) and
Beta::func( ) are two different functions.
454
3.1 C++ Reference RAD Studio C++ Language Guide
C++Builder 2007.
This section lists some of the common areas where the compiler is stricter. Each case is illustrated with an example showing the
problem and how to update the code to compile with C++Builder 2007. Note that there are often many ways to bring offending
code up to date. The appropriate method depends on the intent of the original code.
Topics
Name Description
Stricter C++ Compiler: Binding of References and Qualifiers ( see page 455) There are many constructs that now generate error messages from the
CodeGear C++ compiler included with C++Builder 2007 and newer releases. The
rules governing this behavior are described in section 8.5.3 of the 2003 C++
ANSI standard.
The rules can be divided into the following categories (with the compiler switch
that overrides this behavior):
455
C++ Language Guide RAD Studio 3.1 C++ Reference
and newer releases. The rules governing this behavior are described in section 8.5.3 of the 2003 C++ ANSI standard.
The rules can be divided into the following categories (with the compiler switch that overrides this behavior):
• Binding a non-const lvalue to to non-const reference. (Use the compiler switch -Vbr to allow this.)
• Binding a temporary to a non-const reference. (Use the compiler switch -Vbr to allow this.)
• Binding of const or volatile objects to non-const or non-volatile methods repectively. (Use the compiler switch -Vbn to allow
this.)
Previous versions of the Borland C++ compilers allowed various forms of binding to non-const reference parameters. In the
following example, for instance, one was allowed to simply cast the psize parameter:
int takesLongRef(long& l);
return takesLongRef((long)*psize);
}
With C++Builder2007, the above code generates these errors:
Error E2357 test.cpp 3: Reference initialized with 'long', needs lvalue of type 'long' in
function takesUnsignedPtr(unsigned long *)
Error E2342 test.cpp 3: Type mismatch in parameter 'l' (wanted 'long &', got 'long') in
function takesUnsignedPtr(unsigned long *)
To remedy this, you can cast psize before dereferencing, as in:
int takesLongRef(long& l);
int takesUnsignedPtr(unsigned long* psize) { return takesLongRef(*reinterpret_cast
<long*>(psize)); }
Be aware of cases that involve temporaries in unobvious ways. For example, some binary operators imply a temporary:
enum { zero, one, two } num;
num |= two; // Not allowed
num = num | two; // OK
Another case that involves temporaries in an unobvious way is the return value of a property. The following example illustrates
code that compiled with previous versions of the compiler:
#include <vcl.h>
class TTest {
WideString FData ;
public:
__property WideString Data = {read = FData };
};
void test() {
TTest t;
Func(t.Data);
}
With C++Builder 2007, the above generates two errors:
3
Error E2357 test.cpp 14: Reference initialized with 'const WideString', needs lvalue of type
'WideString' in function test()
Error E2342 test.cpp 14: Type mismatch in parameter 'wref' (wanted 'WideString &', got
'WideString') in function test()
You can fix this by changing the reference to a const reference, as in:
void Func(const WideString& wref);
456
3.1 C++ Reference RAD Studio C++ Language Guide
struct X {
void foo();
};
const X x;
x.foo(); //error
Reconcile Error Dialog: Solving Problems
The temporaries and references issue referred to above is encountered in code generated by previous versions of the Reconcile
Error Dialog Wizard.
You might enable the -Vbs switch to revert string literals to non-const. However, CodeGear recommends that you update the
code instead.
Note that the change in the type of string literals can also change how the compiler resolves calls to overloaded methods. The
following example illustrates this:
void foo(char *);
void foo(const char *);
foo("string"); // New Compiler picks foo(const char *)
With C++Builder2007, the above code generates these errors:
See Also
Binding of References and Qualifiers ( see page 455)
457
C++ Language Guide RAD Studio 3.1 C++ Reference
};
foo<int>::foo();//Error
template<> foo<int>::foo();//OK
Also, the C++ compiler no longer allows explicit template specialization within a class. Use the compiler switch -Vbx to allow this.
For example, the following generates an error:
struct S {};
struct SP
{
template <typename> void foo(const T &) {}
template <> void foo(const S &) {} // Error
};
The compiler option -Vbo reverts to the old behavior, not enforcing the new stricter behavior. However, not all compiler changes
can be controlled by this switch, so CodeGear recommends that you update the code instead.
The following is an example of an ambiguity that was permitted by the previous compiler:
class X{};
void foo(X);
void foo(const X&);
void ambig() {
X x;
foo(x); //error-ambiguous-the previous compiler chose 'void foo(x)'
}
std::abs Ambiguity
The standard abs function might also generate an ambiguity message when invoked with a parameter that does not exactly
match the types expected by the various overloaded versions of abs. Here is an example:
#include <limits>bool test(long l) { return std::abs(l)> 0;}
458
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Stricter C++ Compiler (C++Builder 2007) ( see page 454)
• Direct initialization now requires initialization by a constructor and no longer picks a user conversion sequence.
• Copy initialization for objects of the same or derived type now requires a constructor call.
• Copy initialization for objects of the different types no longer prefers user conversion over construction. If the compiler finds a
suitable user conversion, it now continues to look for (possibly ambiguous) converting constructors. If the chosen conversion
function is a converting constructor, the call initializes a temporary of the destination type. The result of the call (which is the
temporary for the constructor case) is then used to directinitialize the object. Use the compiler switch -Vbo to revert to the
previous behavior.
• For an explicit cast, the compiler now performs direct initialization on a temporary.
This example illustrates the new behavior:
// In this example, dst is destination type and src is source type class A { }; class V
{ public: V() { }; V( const V & ) { } V( const A & ) { } };G g; V v;
// direct initialization
// ==> constructors are considered.
V v9(g);
// Both of these statements previously compiled but now get the error:
// Error E2015: Ambiguity between 'V::V(const V &)' and 'V::V(const A &)'
// casts
// (V)g is treated as V tmp(g) which is direct initialization of 'tmp'
// ==> constructors are considered.
(V)g;
static_cast<V> (g);
// Both of these statements previously compiled but now get the error:
// Error E2015: Ambiguity between 'V::V(const V &)' and 'V::V(const A &)'
459
C++ Language Guide RAD Studio 3.1 C++ Reference
To correct this ambiguity error, you must eliminate the cast as in:
bool operator ==(const AnsiString& rhs) const
{ return (*this) == rhs;}
You can also be explicit about the operator:
bool operator ==(const AnsiString& rhs) const
{ return this->operator AnsiString() == rhs; }
Variant/OleVariant/AnsiString/WideString/TDateTime
The issue described above with a user-defined conversion operator vs. conversion via constructor might be encountered in
several constructs involving the VCL classes Variant, OleVariant, AnsiString, WideString, TDateTime, Currency, and so forth.
The following table lists constructs that now generate error messages and the updated syntax.
The underlying compiler change for the errors described above is related to the way the compiler now handles initialization and
conversion.
See Also
Stricter C++ Compiler (C++Builder 2007) ( see page 454)
3.1.3.1.18 Templates
This section contains Template topics.
3 Topics
Name Description
Template Body Parsing ( see page 461) Earlier versions of the compiler didn't check the syntax of a template body unless
the template was instantiated. A template body is now parsed immediately when
seen like every other declaration.
460
3.1 C++ Reference RAD Studio C++ Language Guide
Using Templates ( see page 462) Templates, also called generics or parameterized types, let you construct a
family of related functions or classes. These topics introduce the basic concept of
templates:
Exporting and importing templates ( see page 432)
Template Body Parsing ( see page 461)
Function Templates ( see page 433)
Class Templates ( see page 412)
Implicit and Explicit Template Functions ( see page 434)
Template Compiler Switches ( see page 414)
The Keyword template ( see page 568)
If you want to access types defined by a template argument you should use a typedef to make your intention clear to the
compiler:
template <class T> class X : T
{
typedef typename T::Int Int;
Int j;
};
You cannot just write
typedef T::Int;
as in earlier versions of the compiler. Not giving the typedef name was acceptable, but this now causes an error message.
All other templates mentioned inside the template body are declared or defined at that point. Therefore, the following example is
ill-formed and will not compile:
template <class T> class X
{
void f(NotYetDefindedTemplate<T> x);
};
All template definitions must end with a semicolon. Earlier versions of the compiler did not complain if the semicolon was missing.
See Also
Using Templates ( see page 462)
461
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
alignof Operator (C++0x) ( see page 463) The C++0x standard includes the alignof keyword and operator, which tells you
the alignment of a type.
To get the alignment of a type, use the following syntax:
Type Trait Functions (C++0x) ( see page 463) This section contains Type Trait Functions help topics.
Attributes noreturn and final (C++0x) ( see page 492) The C++0x standard includes the addition of attributes that might be applied to
the declaration of a class, a general function, a constructor, an array, and so
forth. C++Builder 2009 implements two attributes: noreturn and final.
Attributes are set off in the code by double brackets, such as [[noreturn]].
Explicit Conversion Operators (C++0x) ( see page 493) C++Builder 2009 includes support for explicit conversion operators, one of the
features in the C++0x standard.
You can now apply the function specifier explicit in the definition of a
user-defined conversion operator. Previously, explicit constructors (including
copy constructors) were added to the language in order to prevent unintended
conversions being implicitly called by the compiler. Now explicit conversion
operators have been added to provide the same control over unintended
conversion calls. .
Conversion functions declared as explicit work in the same contexts as explicit
constructors (that is, direct-initialization, explicit type conversion). Explicit
conversion operators produce compiler diagnostics in the same... more ( see
page 493)
extern Templates (C++0x) ( see page 494) C++Builder 2009 includes the use of extern templates, which allow you to define
templates that are not instantiated in a translation unit. Using extern templates
thus reduces both compilation time and the size of the compiled module. This
feature is part of the new C++0x standard.
Forward Declaration of Enums (C++0x) ( see page 495) C++Builder 2009 introduces forward declaration of enums. You can declare an
enumeration without providing a list of enumerators. Such declarations would not
3 be definitions and can be provided only for enumerations with fixed underlying
types. An enumeration can then be re-declared, possibly providing the missing
list of enumerators, but the re-declaration must match the previous declaration.
This feature is one of the C++0x features added to C++Builder 2009.
rvalue References (C++0x) ( see page 495) C++Builder 2009 includes the use of rvalue references, which allow creating a
reference to temporaries. Also, rvalue references avoid unnecessary copying and
make possible perfect forwarding functions. This feature is one of the C++0x
features.
462
3.1 C++ Reference RAD Studio C++ Language Guide
Static Assertions (C++0x) ( see page 498) The static_assert keyword is used to test assertions at compile time. This is one
of the C++0x features added to C++Builder 2009.
This keyword operates differently than the macro assert, which raises assertions
at run time. The keyword static_assert also differs from the preprocessor
directive #error, which operates during preprocessing and simply emits a
message.
Strongly Typed Enums (C++0x) ( see page 498) C++Builder 2009 introduces scoped enums. In addition, existing enums are
extended with underlying type and explicit scoping. This feature is one of the
C++0x features added to C++Builder 2009.
Scoped enums are generally characterized as follows:
Applying alignof to a reference type yields the alignment of the referenced type. If you apply alignof to an array type, you get
the alignment of its element's type.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Topics
Name Description
Type Trait Functions Overview (C++0x) ( see page 472) C++Builder 2009 supports a library of type trait functions designed to support
compile time metaprogramming techniques.
These type trait functions are intrinsic type functions that are defined in a manner
similar to typeid, sizeof, and decltype. The type trait functions accept a type at 3
compile time and deliver a compile time constant expression as a result, typically
of type bool.
Each type trait function is named after its respective type trait, prefixed with a
double underscore (__), which marks a name reserved to the implementation.
For example, the following is a type trait function that evaluates... more ( see
page 472)
463
C++ Language Guide RAD Studio 3.1 C++ Reference
464
3.1 C++ Reference RAD Studio C++ Language Guide
465
C++ Language Guide RAD Studio 3.1 C++ Reference
466
3.1 C++ Reference RAD Studio C++ Language Guide
• array
• function
• pointer
• pointer-to-member
• reference
• class
• union
• enumeration
Compound types are defined in Section 3.92 of the Working
Draft.
__is_const ( see page 481) Category
Type Trait Functions
Syntax
bool __is_const(typename T)
Returns true if and only if T is a const-qualified type.
Note: References are never cv-qualified.
For pointers, refers to the pointer type itself, and NOT the pointed-to type.
Returns true if T is both const and volatile qualified.
__is_convertible ( see page 481) Category
Type Trait Functions
Syntax
bool __is_convertible ( typename From, typename To )
Returns true if and only if From is implicitly convertible to To.
Error if either From or To is an incomplete type.
3
Note: Exact test described in Working Draft Section 20.4.4.3 is true if the
following code is well formed:
467
C++ Language Guide RAD Studio 3.1 C++ Reference
• floating
• double
• long double
Floating point types are defined in Section 3.9.1 p 7 of the
Working Draft.
__is_function ( see page 483) Category
Type Trait Functions
Syntax
bool __is_function( typename T )
Returns true if and only if T is a function type.
Returns false for reference/pointer to function type.
Returns true for specialization of a function template.
Ill-formed if called with the name of a template, without specifying the template
parameters. A template is not a type; it is a type generator.
__is_fundamental ( see page 483) Category
Type Trait Functions
Syntax
bool __is_fundamental( typename T )
Returns true if and only if T is a fundamental type.
Fundamental types are defined in Section 3.9.1 of the Working Draft.
3 Definition is essentially __is_arithmetic(T) || __is_void(T)
Alternative is a compound type, such as pointer, reference, enum, class or array.
468
3.1 C++ Reference RAD Studio C++ Language Guide
469
C++ Language Guide RAD Studio 3.1 C++ Reference
470
3.1 C++ Reference RAD Studio C++ Language Guide
• a scalar type
• an array of standard layout types
• a standard layout class type:
A standard layout class is a class that has:
• no non-static data members other than standard layout
types
• same access control for all non-static data members (such
as all public or private)
• no base classes other than standard layout classes...
more ( see page 489)
__is_trivial ( see page 490) Category
Type Trait Functions
Syntax
bool __is_trivial( typename T )
Returns true if and only if T is a trivial type.
Error if T is an incomplete type.
Trivial types are defined in Section 3.9 p10 of the Working Draft.
Trivial classes are defined in Section 9 p5 of the Working Draft.
Returns true if T is both const and volatile qualified.
A type is trivial if it is:
• a scalar type
• an array of trivial types
• a class/union type where all 4 special members are trivial:
• default constructor
• copy constructor
• copy assignment operator
• destructor
Consult this online help for... more ( see page 490)
__is_union ( see page 491) Category
Type Trait Functions
Syntax
bool __is_union( typename T )
Returns true if and only if T is a union type.
Note: unions are class types declared with the class-key union.
Returns false for reference/pointer to union type.
__is_unsigned ( typename T ) ( see page 491) Category
3
Type Trait Functions
Syntax
bool __is_unsigned
Returns true if _is_arithmetic(T) and T does not recognize values less than
zero
471
C++ Language Guide RAD Studio 3.1 C++ Reference
These type trait functions are intrinsic type functions that are defined in a manner similar to typeid, sizeof, and decltype. The
type trait functions accept a type at compile time and deliver a compile time constant expression as a result, typically of type
bool.
Each type trait function is named after its respective type trait, prefixed with a double underscore (__), which marks a name
reserved to the implementation.
For example, the following is a type trait function that evaluates True if T is a union type, or False otherwise:
bool __is_union(typename T)
The typename keyword here indicates a function that takes a type rather than a value as an argument, for illustration purposes
only.
Similarly, any attempt to reference the type of a bit field (such as through decltype) produces the underlying storage type for the
bit field, and that is what is tested in the type trait functions.
However, a few type functions require complete types. For example, a class declaration is not sufficient to know about bases or
triviality.
A table of type trait functions that require that the type be a complete type, an array of unknown bound, or (possibly cv-qualified)
void is given in Table 43: “Type Property Predicates” in Section 20 of the Working Draft.
472
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.2 __alignment_of
Category
Syntax:
unsigned int __alignment_of( typename T )
This function is not necessary, as alignof ( see page 531) is a proposed new keyword.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.3 __array_extent
Category
Syntax
unsigned int __array_extent( typename T, unsigned intI )
Returns: If T is not an array type, or if it has rank less than I, or if I is 0 and T has type “array of unknown bound of U”, then 0;
otherwise, the size of the I’th dimension of T.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.4 __array_rank
Category
Syntax
unsigned int __array_rank( typename T )
Returns: If T names an array type, an integer representing the number of dimensions of T; otherwise, 0.. 3
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.5 __has_nothrow_assign
Category
473
C++ Language Guide RAD Studio 3.1 C++ Reference
Syntax
bool __has_nothrow_assign ( typename T )
Returns true if and only if compiler can prove T has a copy assignment operator that it cannot throw.
True if __has_trivial_assign(T).
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.6 __has_nothrow_copy_constructor
Category
Syntax
bool __has_nothrow_copy_constructor ( typename T )
Returns true if and only if compiler can prove T has a copy constructor that cannot throw.
True if __has_trivial_copy_constructor(T).
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.7 __has_nothrow_default_constructor
Category
Syntax
bool __has_nothrow_default_constructor (typename T )
Returns true if and only if T can prove T has a default constructor it cannot throw.
True if __has_trivial_default_constructor(T).
False (but well-formed) if a class type does not have a default constructor.
474
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.8 __has_trivial_assign
Category
Syntax
bool __has_trivial_assign (typename T )
The definition from Section 20.4.4.3 of the Working Draft notes says a type T has a trivial copy assignment operator if T is
neither const nor a reference type and T is one of:
3.1.3.1.19.2.9 __has_trivial_copy_constructor 3
Category
Syntax
bool __has_trivial_copy_constructor ( typename T )
475
C++ Language Guide RAD Studio 3.1 C++ Reference
False (but well-formed) if a class type does not have a default constructor
The definition (from Section 20.4.4.3 of the Working Draft) notes has a type T has a trivial copy constructor if it is in the list::
3.1.3.1.19.2.10 __has_trivial_default_constructor
Category
Syntax
bool __has_trivial_default_constructor (typename T )
False (but well-formed) if a class type does not have a default constructor.
According to the definition from Section 20.4.4.3 of the Working Draft notes, a type T has a trivial copy assignment operator if:
3
• a scalar type (or array thereof)
• an array of class type with a trivial default constructor
• a class type with a trivial default constructorr
Especially note false for reference types.
According to Section 21.1 p5 of the Working Draft, a default constructor is trivial if:
• It is not user provided
476
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.1.19.2.11 __has_trivial_destructor
Category
Syntax
bool __has_trivial_destructor (typename T )
Note: Definition from 20.4.4.3 notes has a type T has a trivial destructor if T is one of:
477
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.12 __has_virtual_destructor
Category
Syntax
bool __has_virtual_destructor (typename T )
Returns true if and only if T is a class type and the destructor is declared virtual.
Derived classes have a virtual destructor if the a base class destructor is declared virtual, even if not explicitly declared as virtual
in the derived class.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.13 __is_abstract
Category
Syntax
bool __is_abstract( typename T )
Note: An abstract class is one that contains or inherits (without overriding) at least one pure virtual function, according to
Section 10.4 of the Working Draft.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Syntax
bool __is_arithmetic ( typename T )
478
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.15 __is_array
Category
Syntax
bool __is_array( typename T )
Note: False for decayed pointer-to-array and reference to array; true for array-of-unknown bounds.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.16 __is_base_of
Category
Syntax
bool __is_base_of (typename Base, typename Derived)
Note: False (but well formed) if either Base or Derived is a union or non-class type, even if the other is an incomplete type.
True if any class in the DAG of base classes for Derived is Base. This includes private, protected, ambiguous or virtual bases so
simply return true the first time the search finds a match.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.17 __is_class
Category 3
Type Trait Functions
Syntax
bool __is_class(typename T)
Returns true if and only if T is a class type, and NOT a union type.
Returns true for classes declared with the class key class or struct.
479
C++ Language Guide RAD Studio 3.1 C++ Reference
Ill-formed if called with the name of a template, without specifying the template parameters. A template is not a type; it is a type
generator.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Syntax
bool __is_complete_type(T)
Returns True if and only if T is a complete type at the point of the function call.
This is a support function to help users track ill-formed code, not a distinct type trait required by the standard. This function is
typically used in static_assert statements, because most other uses risk violating the ODR. Note that void and arrays of
unknown bound are always incomplete types.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.19 __is_compound
Category
Syntax
bool __is_compound( typename T )
• array
• function
• pointer
• pointer-to-member
3
• reference
• class
• union
• enumeration
Compound types are defined in Section 3.92 of the Working Draft.
480
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.20 __is_const
Category
Syntax
bool __is_const(typename T)
For pointers, refers to the pointer type itself, and NOT the pointed-to type.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.21 __is_convertible
Category
Syntax
bool __is_convertible ( typename From, typename To )
Note: Exact test described in Working Draft Section 20.4.4.3 is true if the following code is well formed:
template <class T>
typename add_rvalue_reference<T>::type create();
3.1.3.1.19.2.22 __is_empty
Category
481
C++ Language Guide RAD Studio 3.1 C++ Reference
Syntax
bool __is_empty( typename T )
Definition of __is_empty is given in the table in Section 20.4.4.3 of the Working Draft.
A type T is empty if T:
3.1.3.1.19.2.23 __is_enum
Category
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.24 __is_floating_point
Category
3 Syntax
bool __is_floating_point(typename T)
• floating
• double
482
3.1 C++ Reference RAD Studio C++ Language Guide
• long double
Floating point types are defined in Section 3.9.1 p 7 of the Working Draft.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.25 __is_function
Category
Syntax
bool __is_function( typename T )
Ill-formed if called with the name of a template, without specifying the template parameters. A template is not a type; it is a type
generator.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.26 __is_fundamental
Category
Syntax
bool __is_fundamental( typename T )
See Also 3
C++0x Features (C++Builder 2009) ( see page 462)
483
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.1.19.2.27 __is_integral
Category
Syntax
bool __is_integral(typename T)
Integral types are defined in the Working Standard, Section 3.9.1 page 7.
The standard set of integral types is: bool, char, signed char, unsigned char, char16_t, char32_t, wchar_t, [unsigned]short,
[unsigned] int, [unsigned] long, and [unsigned] long.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.28 __is_lvalue_expr
Category
Syntax
bool __is_lvalue_expr( typename T )
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.29 __is_lvalue_reference
Category
Syntax
bool __is_lvalue_reference( typename T )
See Also
C++0x Features (C++Builder 2009) ( see page 462)
484
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.1.19.2.30 __is_member_function_pointer
Category
Syntax
bool __is_member_function_pointer( typename T )
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.31 __is_member_object_pointer
Category
Syntax
bool __is_member_object_pointer( typename T )
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.32 __is_member_pointer
Category
Syntax
bool __is_member_pointer( typename T )
See Also
3
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.33 __is_object
Category
485
C++ Language Guide RAD Studio 3.1 C++ Reference
Syntax
bool __is_object( typename T)
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.34 __is_pod
Category
Syntax
bool __is_pod( typename T )
POD types are defined in Section 3.9 p10 of the Working Draft.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.35 __is_pointer
Category
Syntax
3
bool __is_pointer( typename T )
486
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.36 __is_polymorphic
Category
Syntax
bool __is_polymorphic( typename T )
"A class that declares or inherits a virtual function is called a polymorphic class."
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.37 __is_reference
Category
Syntax
bool __is_reference( typename T )
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.38 __is_rvalue_expr
Category
See Also
C++0x Features (C++Builder 2009) ( see page 462)
487
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.1.19.2.39 __is_rvalue_reference
Category
Can be a reference to an object or function type, even though function type rvalues make little sense beyond metaprogramming
in the type system.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.40 __is_same
Category
Syntax
bool __is_same( typename T, typename U )
Returns true if and only if T and U are the same type, with identical CV qualifiers.
Names of types when calling __is_same may be different aliases for the same type, if called with typedefs or template type
parameters.
Ox interaction: template aliases will allow another way to alias the same type name.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.41 __is_scalar
Category
Syntax
bool __is_scalar( typename T )
Scalar types have a built in meaning for operator < as well as operator ==. Therefore, __closure is not a scalar type.
488
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.42 __is_signed
Category
Syntax
_bool __is_signed( typename T )
Returns true if and only if __is_arithmetic(T) and T recognizes values less than zero.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.43 __is_standard_layout
Category
Syntax
bool __is_standard_layout(typename T)
• a scalar type
• an array of standard layout types
• a standard layout class type:
A standard layout class is a class that has:
• no non-static data members other than standard layout types
• same access control for all non-static data members (such as all public or private)
• no base classes other than standard layout classes 3
• no virtual functions and no virtual base classes
• no more than one class in the DAG of inheritance tree has any non-static data
• no base class of same type as the first (if any) non-static data member
Standard layout types trigger several special clauses in the standard, which may affect code generation and optimizations, or
simply whether certain constructs are undefined. In particular, standard layout classes require the empty base optimization.
Note that standard layout types are a generalization of PODs in the 2003 standard, if the POD/standard layout refinement has
489
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.1.19.2.44 __is_trivial
Category
Syntax
bool __is_trivial( typename T )
Trivial types are defined in Section 3.9 p10 of the Working Draft.
• a scalar type
• an array of trivial types
• a class/union type where all 4 special members are trivial:
• default constructor
• copy constructor
• copy assignment operator
• destructor
Consult this online help for the definition of each __has_trivial_* traits.
Trivial types trigger several special clauses in the standard, which may affect code generation and optimizations, or simply
whether certain constructs are undefined.
Note that trivial types are a generalization of PODs (plain old data objects) in the 2003 standard, if the POD/trivial refinement has
not happened when this type function is initially implanted.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
490
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.1.19.2.45 __is_union
Category
Syntax
bool __is_union( typename T )
Note: unions are class types declared with the class-key union.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Syntax
bool __is_unsigned
Returns true if _is_arithmetic(T) and T does not recognize values less than zero
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3.1.3.1.19.2.47 __is_void
Category
Syntax
bool __is_void( typename T )
Returns True if T is (potentially cv-qualified) void. Returns False otherwise, including for pointer or reference to void.
See Also
C++0x Features (C++Builder 2009) ( see page 462) 3
Type Trait Functions Overview ( see page 472)
3.1.3.1.19.2.48 __is_volatile
Category
491
C++ Language Guide RAD Studio 3.1 C++ Reference
Syntax
bool __is_volatile( typename T )
For pointers, refers to the pointer type itself, and NOT the pointed-to type.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Attributes are set off in the code by double brackets, such as [[noreturn]].
For example:
void f [[noreturn]] () {
throw “error”; // OK
}
void g [[noreturn]] (int i) { // ill-formed if called with i<=0
if (i > 0)
throw “positive”;
}
The noreturn attribute is useful for a few library functions that cannot return, such as abort and exit. You can also define your
own functions that never return by using the noreturn attribute.
For example:
void fatal(void) [[noreturn]];
void fatal(...)
{
...
exit(1);
}
The noreturn keyword tells the C++ compiler to assume that fatal cannot return. The compiler can then optimize without regard
to what would happen if fatal ever did return. Thus, using noreturn can make better code. More importantly, it helps avoid
spurious warnings of uninitialized variables. You cannot assume that registers saved by the calling function are restored before
3 calling the function with the noreturn attribute. It does not make sense for a noreturn function to have a return type other than
void.
A class with the final attribute is not allowed to be a base class for another class. A virtual function with the final attribute is not
overridden in a subclass. If the attribute is specified for a class definition, it is equivalent to being specified for each virtual
492
3.1 C++ Reference RAD Studio C++ Language Guide
If a virtual member function f in some class B is marked final and in a class D derived from B, a function D::f overrides B::f, the
program is ill-formed (the compiler does not issue a message).
For example:
struct B {
virtual void f [[ final ]] ();
};
struct D : B {
void f(); // ill-formed
};
See Also
C++0x Features (C++Builder 2009) ( see page 462)
You can now apply the function specifier explicit in the definition of a user-defined conversion operator. Previously, explicit
constructors (including copy constructors) were added to the language in order to prevent unintended conversions being
implicitly called by the compiler. Now explicit conversion operators have been added to provide the same control over
unintended conversion calls. .
Conversion functions declared as explicit work in the same contexts as explicit constructors (that is, direct-initialization, explicit
type conversion). Explicit conversion operators produce compiler diagnostics in the same contexts (copy-initialization) as explicit
constructors do.
For example:
class T { };
class X {
public:
};
void m() {
X x;
// with cast:
T tc = (T)x;// ok 3
// without cast:
// gets: Error E2034 x.cpp 13: Cannot convert 'X' to 'T' in function m()
493
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
C++0x Features (C++Builder 2009) ( see page 462)
However, suppose you want to have a library in which all instantiations of this template occur, and you want to refer to these
instantiations in an executable. To make an explicit template declaration that does not instantiate the template in your code unit,
use the following:
extern template class MyClass<int>;
You can then reference the template, but the compiler does not generate code for it in that translation unit.
• A template instantiation must either follow an explicit template declaration in that translation unit or be in another translation
unit. This is similar to the usual use of extern: the entity referenced must be defined somewhere.
• An explicit template definition must occur only once in a unit.
• An explicit template definition must follow an explicit template declaration if both are present in a translation unit.
• An explicit template declaration can only apply to names of objects, functions, and explicit template instantiations. It may not
refer to a static function, but may apply to a static member function.
3
• The extern specifier may not be used in declaration of class members or parameters.
• An explicit template declaration only suppresses code generation if that template has not been instantiated with the same
specialization. For instance:
template class MyClass<int>;
...
extern template class MyClass<int>; // not allowed
extern template class MyClass<float>; // OK
494
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Description
Rvalue references are a compound type like standard C++ references, which are referred to as lvalue references. An lvalue
reference is formed by appending the ampersand character (&) to a type:
SomeClass l;
SomeClass& lReference = l; //lvalue rererence
The syntax of an rvalue reference is to add && after a type:
SomeClass r;
SomeClass&& rReference = r; //rvalue rererence
An rvalue reference behaves like an lvalue reference, except that you can bind an rvalue reference to a temporary -- an rvalue.
3
SomeClass a;
a = SomeClass();
SomeClass& lReference = a; //OK-lvalue reference can bind to an lvalue such as "a"
SomeClass& lReference2 = SomeClass(); //error-lvalue reference can't bind to an rvalue
SomeClass&& rReference = SomeClass(); //OK for rvalue reference to bind to rvalue
495
C++ Language Guide RAD Studio 3.1 C++ Reference
In the example above, SomeClass() is not bound to an identifiier, so it is an rvalue and can be bound to an rvalue reference --
but not an lvalue reference.
Rvalue rererences can be used to distinguish cases that require copying versus cases that merely require moving data. Since
copying can be a lengthy operation, you want to avoid it if possible.
If a function wants to copy something that has been passed to it as an rvalue, then it can do a move rather than a copy, because
it knows that the value is temporary. If a function is passed an lvalue, it may need to do a full copy if copy elision doesn't apply.
You can distinguish these cases with the function signature.
Consider a class ExampleClass that has a clone function that makes a deep copy of class instances. You want to define a move
function that moves an object's value. This function can be overloaded as follows:
// Parameter is lvalue
ExampleClass move(ExampleClass& l)
{
return l.clone(); //returns a copy since we can't touch the original value
// Parameter is rvalue
ExampleClass move(ExampleClass&& r)
{
return r; //returns a reference since we don't care about the temporary's value
}
template class MyClass<int>;
...
extern template class MyClass<int>; // not allowed
extern template class MyClass<float>; // OK
We could then use the move function for both rvalues and lvalues:
ExampleClass a, b, c;
a = ExampleClass();
b = b.move(a); //parameter is lvalue
c = c.move(ExampleClass()); //parameter is rvalue
Note that the move function for the rvalue parameter does very little, so it executes much more quickly than the move for an
lvalue parameter.
You can use a similar technique for functions that need to make copies, such as copy constructors and assignment operators.
Suppose we have a template class with a pointer to some other class, where clone is again a deep copy function:
template <class T>
class PointerClass
{
private:
T* pointer;
public:
// Regular constructor
PointerClass(void);
3
// Copy constructor for lvalues
PointerClass(PointerClass& pcl) : pointer(pcl.pointer ? pcl.pointer.clone() : 0) {} //make
full copy
// Copy constructor for rvalues
PointerClass(PointerClass&& pcr) : pointer(pcr.pointer) {pcr.pointer = 0;}
The copy constructor that takes an rvalue:
• Does a move, not a copy. That is, it simply returns a reference to the data.
496
3.1 C++ Reference RAD Studio C++ Language Guide
• Treats the rvalue argument pcr just like an lvalue in its code.
• Leaves the rvalue object in a defined state so that it can safely be deleted.
Non-Copyable but Movable Types
Types that are not copyable, such as ones that use unique_ptr, can be made movable. Although they cannot define assignment
operators, they can implement move functions and swap functions, since these do not require copying when rvalue references
are used. A sort function could be developed, since it only requires swapping, not copying.
For instance, consider this factory function that takes one argument:
template <class T, class U>
factory(const U& u)
{
return new T(u);
}
The above definition of factory works in this case:
T* p = factory<T>(7);
However, a compiler error occurs when a T is used whose constructor's parameter is a non-const reference. You could fix this
case by removing const from the definition:
template <class T, class U>
factory(U& u)
{
return new T(u);
}
However, the previous example now fails:
T* p = factory<T>(7); // compiler error
T* u = new T(7); //OK
This causes an error because the value 7 causes the template argument to be matched to int &, but this does not bind to the
rvalue 7.
This could be remedied by defining a factory function for each case of const and non-const. This is problematic, because the
number of functions needed increases exponentially with the number of arguments.
If you make the argument an rvalue reference, you can simplify the situation:
template <class T, class U.
factory(u&& u)
{
return new T(forward<U>(u));
}
Now the argument u binds to both rvalues and lvalues. The forward function returns an rvalue or lvalue, exactly as it was
passed. It can be defined in this way:
template <class U>
struct identity
{
typedef U type;
}; 3
template <class U>
U&& forward(typename identity<U>::type&& u)
{
return u;
}
See Also
C++0x Features (C++Builder 2009) ( see page 462)
497
C++ Language Guide RAD Studio 3.1 C++ Reference
This keyword operates differently than the macro assert, which raises assertions at run time. The keyword static_assert also
differs from the preprocessor directive #error, which operates during preprocessing and simply emits a message.
Syntax
A static assertion's declaration is:
static_assert (constant-expression, error-message);
The constant-expression must be one that can be statically evaluated as a boolean. If constant-expression is true,
the statement does nothing. If false, the compiler generates an error with the text error-message. Because the assertion is
tested at compile time, static_assert can do error checking in templates. For instance:
template <class T>
T Test(T x, T y) {
static_assert(sizeof T <= sizeof long, "Type is too large");
...
};
static_assert is useful for static type checking. A certain function might fail if the implementation of an int is too small, so
static_assert has utility outside of templates.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Working Draft - Standard for Programming Language C++ (Sec. 7.1 - Specifiers)
Underlying Type
For scoped enums, the underlying type is well specified (the default is int). You can specify the underlying type of the
enumeration and all the enumerators by writing : type after the enumeration name (you can specify any integral type except
wchar_t). The following example declares an enum of underlying type unsigned long:
498
3.1 C++ Reference RAD Studio C++ Language Guide
• You can now specify the underlying type of any enum, just as with scoped enums (by adding : type to the declaration).
• Existing enums now introduce their own scopes, just as with scoped enums. The names of enumerators are defined in the
enum's scope and are also injected into the enclosing scope.
For instance:
enum B { B1, B2, B3 = 100, B4 /* = 101 */ };
B b1 = B1; // ok
B b2 = B::B2; // ok
Examples
The following examples demonstrate the following two things:
Syntax
The format of the decltype operator is:
decltype ( expression )
Here are the rules for evaluating decltype(e):
• If e is an identifier expresson or accessing a class member, decltype(e) is the type of the thing designated by e. If there is 3
no such thing, or if e is the name of a set of overloaded functions so there is ambiguity, decltype(e) is invalid.
• Otherwise, if e is a function call or invokes an overloaded operator, decltype(e) is the type returned by the function.
• Otherwise, if e is an lvalue, decltype(e) is a reference to T (T&) where T is the type of e.
• If none of the other cases apply, decltype(e) is the type of e.
Examples
See the embedded contents in the following examples.
499
C++ Language Guide RAD Studio 3.1 C++ Reference
Working Draft - Standard for Programming Language C++ (Sec. 7.1.6.2 - Simple Type Specifiers)
• char16_t is a 16 bit character type. char16_t is a C++ keyword. This type could be used for UTF-16 characters.
• char32_t is a 32 bit character type. char32_t is a C++ keyword. This type can be used for UTF-32 characters.
The existing wchar_t ( see page 573) type is a type for a wide character in the execution wide-character set. A wchar_t
wide-character literal begins with an uppercase L (such as L'c').
Character Literals u'character' and U'character'
There are two new forms to create literals of the new types:
• u'character' is a literal for a single char16_t character, such as u'g'. A multicharacter literal such as u'kh' is badly formed.
The value of a char16_t literal is equal to its ISO 10646 code point value, provided that the code point is representable as a
16-bit cvalue. Only characters in the basic multi-lingual plane (BMP) can be represented.
• U'character' is a literal for a single char32_t character, such as U't'. A multicharacter literal such as U'de' is ill-formed. The
value of a char32_t literal is equal to its ISO 10646 code point value.
Multibyte character literals were previously only of the form L'characters', representing one or more characters of the type
wchar_t. The value of a single character wide-character literal is that character's encoding in the execution wide-character set.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
Working Draft - Standard for Programming Language C++ (Sec. 2.13.2 - Character Literals)
3
3.1.3.1.20 Unicode for C++
This section contains Unicode related feature topics for C++.
500
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
TCHAR Mapping ( see page 501) TCHAR, which is declared in the header file tchar.h, is a typedef (alias) that
maps either to char or to wchar_t. When you want to write portable code, you
should use TCHAR instead of hard coding char or wchar_t.
The TCHAR maps to option controls the floating definition of _TCHAR. Your
choices are:
_TCHAR Mapping Options
Floating Functions ( see page 502) This topic describes how to write portable code that correctly uses the floating
definitions of RTL functions. The list of floating functions is useful for choosing
the correct variant of a function.
Enabling C++ Applications for Unicode ( see page 507) C++ has a unique set of Unicode-related issues that Delphi users do not have.
Some of these issues are:
The TCHAR maps to option controls the floating definition of _TCHAR. Your choices are:
To set the TCHAR maps to option, go to the Project Options Directories and Conditionals dialog box.
501
C++ Language Guide RAD Studio 3.1 C++ Reference
points that you need. For a list of the floating functions contained in tchar.h, see Floating Functions ( see page 502).
See Also
Floating Functions ( see page 502)
502
3.1 C++ Reference RAD Studio C++ Language Guide
503
C++ Language Guide RAD Studio 3.1 C++ Reference
504
3.1 C++ Reference RAD Studio C++ Language Guide
505
C++ Language Guide RAD Studio 3.1 C++ Reference
506
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
TCHAR Mapping ( see page 501)
• String constants, such as "string constant", are still narrow (char*), so you cannot pass them to VCL functions that
take PChar as you did before. If you prefix the constant with L, as in L"string constant", you can pass the constant to
VCL functions with a PChar parameter.
• The C++ RTL is as wide and narrow as it always was. Unless you planned ahead and used <tchar.h> and the _txxxxxx()
macros, you need to do some work to use the wide flavor of the RTL. VCL generally uses wide string data, so you probably
need to use wide RTL functions.
• The Windows API is still narrow by default. The new _TCHAR mapping option helps trememdously here, but the option is
OFF by default. You need to explicitly set the _TCHAR maps to option on the Project Options Directories and
Conditionals dialog box.
• You can set the codepage for AnsiString types with AnsiStringT<codepage>. The same predefined types are available
that Delphi provides:
• AnsiString is AnsiStringT<0>
• UTF8String is AnsiStringT<65005>
• RawByteString is AnsiStringT<0xFFFF>
See Also
TCHAR Mapping ( see page 501)
507
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
How to Handle Delphi Anonymous Methods in C++ ( see page 508) This topic describes some programming issues that you might encounter when
dealing with anonymous methods, one of Delphi's newest features.
Under the cover, Delphi implements anonymous methods types (also known as
method references) via an interface that implements an Invoke(...) method.
So a method that takes a method reference parameter in Delphi is exposed to
C++ as a method that takes an interface. Here's an example:
How to Handle Delphi AnsiString Code Page Specification in C++ ( see page The C++ implementation of the AnsiString type provides CodePage support
510) similar to that available in Delphi 2009. However, while the Delphi version is
implemented via extension to the language, the C++ version is implemented via a
template with a non-type parameter as codepage, as in:
How to Handle Delphi Generics in C++ ( see page 511) This topic describes some programming issues that you might encounter when
dealing with generics, one of Delphi's newest features.
Delphi generics are exposed to C++ as templates. However, it's important to
realize that the instantiations occur on the Delphi side, not in C++. Therefore, you
can only use these template for types that were explicitly instantiated in Delphi
code. For example, let's declare a simply generic, TList<T>, in Delphi:
Under the cover, Delphi implements anonymous methods types (also known as method references) via an interface that
implements an Invoke(...) method. So a method that takes a method reference parameter in Delphi is exposed to C++ as a
method that takes an interface. Here's an example:
interface
type
TTestClass = class
public
function TakeRefProc(RefProc: TRefProc; I, J: Integer): Integer;
end;
The following is the .hpp file generated for the above:
__interface TRefProc;
typedef System::DelphiInterface <TRefProc> _di_TrefProc;
508
3.1 C++ Reference RAD Studio C++ Language Guide
{
private:
F callback;
public:
TMethodRef(F _callback) : callback(_callback) {}
void UseRefProcFlat()
{
std::auto_ptr<TTestClass> cls(new TTestClass());
_di_TRefProc proc = new TMethodRef<TRefProc, int (*)(int, int), int, int, 3
int>(multiplyCallback);
int i = cls->TakeRefProc(proc, 10, 20);
assert(i == 200);
}
You can also use the template to pass a member function as a method reference. The following code illustrates this:
class TMyClass {
public:
int add(int i, int j) {
509
C++ Language Guide RAD Studio 3.1 C++ Reference
return i+j;
}
};
typedef int (__closure *TClosure)(int, int);
void UseRefProcMember()
{
TMyClass myClass;
All assignments to an AnsiStringT instance will encode the data in the type's codepage. For example, in the following code, the
Unicode data assigned to the UTF8String variable is automatically UTF8-encoded:
const wchar_t* data = L"???????";
UTF8String utfs(data);
The 'utfs' variable can be passed to a function expecting a UnicodeString and the original data will be restored without any loss
incurred:
Button1->Caption = utfs; // Set button caption to "???????";
Note that while the AnsiStringT handles the codepage support behind the scene, you can still explicitly set the codepage of an
instance by calling the following method:
AnsiStringT<CP>::SetCodePage(unsigned short codePage, bool
convert=true)
This method should be used carefully because it might mislead users of the instance who expect the type to contain data
3 encoded in its default codepage.
See Also
Handling Anonymous Methods ( see page 508)
510
3.1 C++ Reference RAD Studio C++ Language Guide
Delphi generics are exposed to C++ as templates. However, it's important to realize that the instantiations occur on the Delphi
side, not in C++. Therefore, you can only use these template for types that were explicitly instantiated in Delphi code. For
example, let's declare a simply generic, TList<T>, in Delphi:
interface
type
implementation
{$R *.dfm}
private: 3
typedef DynamicArray<T> _MyTList__1__1;
public:
_MyTList__1__1 FItems;
protected:
int __fastcall GetLength(void);
public:
T __fastcall Get(int Index);
511
C++ Language Guide RAD Studio 3.1 C++ Reference
__published:
__property int Len = {read=GetLength, nodefault};
public:
/* TList<T>.Create */ inline __fastcall MyTList__1(void)/* overload */ :
Generics_collections::TList__1<T>() { }
/* TList<T>.Destroy */ inline __fastcall virtual ~MyTList__1(void) { }
};
public:
/* TList<Double>.Create */ inline __fastcall ScoreList(void)/* overload */ :
MyTList__1<double>() { }
/* TList<Double>.Destroy */ inline __fastcall virtual ~ScoreList(void) { }
};
public:
/* TList<string>.Create */ inline __fastcall StringList(void)/* overload */ :
MyTList__1<System::UnicodeString>() { }
/* TList<string>.Destroy */ inline __fastcall virtual ~StringList(void) { }
};
C++ code linking with the .obj created from the above Delphi unit can use instances of TList__1<double> or ScoreList.
void UseScoreList()
{
ScoreList* list = new ScoreList();
list->Add(1.0);
list->Add(2.0);
delete list;
}
void UseTList__1()
{
// C++ code can use the Generics defined in Delphi directly
// as long as the C++ code limits itself to types for which
3 // the generic was instantiated on the Delphi size. For example,
// since test.pas uses TList<String> and TList<double> we can use
// these here. However, if we try to use TList__1>char> we'll get
// an error since the Delphi side did not instantiate
// TList<AnsiChar>.
TList__1<double>* dblList = new MyTList__1<double>();
dblList—>Add(1.0);
dblList—>Add(1.5);
double d = dblList—>Get(1);
delete dblList;
512
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Handling Anonymous Methods ( see page 508)
Topics
Name Description
__automated ( see page 522) Category
Keyword extensions
Syntax
__classid ( see page 523) Category
Operators, Keyword extensions
Syntax
__closure ( see page 523) Category
Keyword extensions
Syntax
__declspec ( see page 523) Category 3
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__dispid ( see page 525) Category
Modifiers
Syntax
__except ( see page 525) Category
Statements, Keyword extensions
Syntax
513
C++ Language Guide RAD Studio 3.1 C++ Reference
514
3.1 C++ Reference RAD Studio C++ Language Guide
515
C++ Language Guide RAD Studio 3.1 C++ Reference
516
3.1 C++ Reference RAD Studio C++ Language Guide
517
C++ Language Guide RAD Studio 3.1 C++ Reference
518
3.1 C++ Reference RAD Studio C++ Language Guide
519
C++ Language Guide RAD Studio 3.1 C++ Reference
520
3.1 C++ Reference RAD Studio C++ Language Guide
521
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.2.1 __automated
Category
Keyword extensions
Syntax
_automated: <declarations>
Description
The visibility rules for automated members are identical to those of public members. The only difference between automated and
public members is that OLE automation information is generated for member functions and properties that are declared in an
automated section. This OLE automation type information makes it possible to create OLE Automation servers.
3
• For a member function, the types of all member function parameters and the function result (if any) must be automatable.
Likewise, for a property, the property type and the types of any array property parameters must be automatable. The
automatable types are: Currency, OleVariant, DelphiInterface, double, int, float, short, String, TDateTime, Variant, and
unsigned short. Declaring member functions or properties that use non-automatable types in an __automated section results
in a compile-time error.
• Member function declarations must use the __fastcall calling convention.
• Member functions can be virtual.
522
3.1 C++ Reference RAD Studio C++ Language Guide
• Member functions may add __dispid(constant int expression) after the closing parenthesis of the parameter list.
• Property declarations can only include access specifiers (__dispid, read, and write). No other specifiers (index, stored, default,
nodefault) are allowed.
• Property access specifiers must list a member function identifier. Data member identifiers are not allowed.
• Property access member functions must use the __fastcall calling convention.
• Property overrides (property declarations that don’t include the property type) are not allowed.
See Also
__dispid ( see page 525)
3.1.3.2.2 __classid
Category
Syntax
__classid(classType)
Description
The __classid operator was added to support the VCL framework. Normally, programmers should not directly use this operator.
For more information, see the keyword extensions.
See Also
__classmethod ( see page 574)
3.1.3.2.3 __closure
Category
Keyword extensions
Syntax
<type> ( __closure * <id> ) (<param list>);
Description
The keyword __closure was added to support the VCL framework and is used when declaring event handler functions. For more
information, see the keyword extensions. 3
See Also
__property ( see page 527)
3.1.3.2.4 __declspec
Category
523
C++ Language Guide RAD Studio 3.1 C++ Reference
Syntax
__declspec(<decl-modifier>)
Description
For a list of __declspec keyword arguments used for the VCL framework, see VCL class declarations.
Use the __declspec keyword to indicate the storage class attributes for a variable or function.
The __declspec keyword extends the attribute syntax for storage class modifiers so that their placement in a declarative
statement is more flexible. The __declspec keyword and its argument can appear anywhere in the declarator list, as opposed to
the old-style modifiers which could only appear immediately preceding the identifier to be modified.
__export void f(void); // illegal
void __export f(void) // correct
void __declspec(dllexport) f(void); // correct
__declspec(dllexport)void f(void); // correct
class __declspec(dllexport) ClassName { } // correct
In addition to the arguments listed above, the supported decl-modifier arguments are:
• dllexport
• dllimport
• naked
• noreturn
• nothrow
• novtable
• property
• selectany
• thread
• uuid
These arguments are equivalent to the following storage class attribute keywords.
See Also
_export ( see page 530)
524
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.5 __dispid
Category
Modifiers
Syntax
__dispid(constant int expression)
Description
A member function that has been declared in the __automated section of a class can include an optional __dispid(constant int
expression) directive. The directive must be declared after the closing parenthesis of the parameter list.
The constant int expression gives the Automation dispatch ID of the member function or property. If a dispid directive is not used,
the compiler automatically picks a number one larger than the largest dispatch ID used by any member function or property in
the class and its base classes.
See Also
__closure ( see page 523)
3.1.3.2.6 __except
Category
Syntax
__except (expression) compound-statement
Description
The __except keyword specifies the action that should be taken when the exception specified by expression has been raised.
See Also
__finally ( see page 550)
3.1.3.2.7 __inline
Category
Keyword extensions
Syntax
525
C++ Language Guide RAD Studio 3.1 C++ Reference
Use the __inline keyword to declare or define C or C++ inline functions. The behavior of the __inline keyword is identical to that
of the inline keyword, which is only supported in C++.
Inline functions are best reserved for small, frequently used functions.
Keyword extensions
Description
You can specify the size for integer types. You must use the appropriate suffix when using extended integers.
See Also
Constants ( see page 667)
3.1.3.2.9 __msfastcall
Category
526
3.1 C++ Reference RAD Studio C++ Language Guide
Syntax
__msfastcall <function-name>
Description
This calling convention emulates the Microsoft implementation of the fastcall calling convertion. The first two DWORD or smaller
arguments are passed in ECX and EDX registers, all other arguments are passed from right to left. The called function is
responsible for removing these arguments from the stack.
3.1.3.2.10 __msreturn
Category
Syntax
__msreturn <function-name>
Description
This calling convention is used for Microsoft compatible __fastcall calling convention return values. Structures with a size that is
greater than 4 bytes and less than 9 bytes, and having at least one of its members sized 4 bytes or larger, are returned in
EAX/EDX.
3.1.3.2.11 __property
Category
Keyword extensions
Syntax
<property declaration> ::=
__property <type> <id> [ <prop dim list> ] = "{" <prop attrib list> "}"
See Also
__closure ( see page 523)
527
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.2.12 __published
Category
Keyword extensions
Syntax
__published: <declarations>
Description
See Also
__closure ( see page 523)
Description
Runtime type identification is enabled by default. You can disable RTTI on the C++ page of the Project Options dialog box. From
the command-line, you can use the -RT- option to disable it or -RT to enable it.
If RTTI is disabled, or if the argument to typeid is a pointer or a reference to a non-polymorphic class, typeid returns a reference
to a const type_info object that describes the declared type of the pointer or reference, and not the actual object that the pointer
or reference is bound to.
In addition, even when RTTI is disabled, you can force all instances of a particular class and all classes derived from that class
to provide polymorphic runtime type identification (where appropriate) by using the __rtti keyword in the class definition.
When runtime type identification is disabled, if any base class is declared __rtti, then all polymorphic base classes must also be
declared __rtti.
struct __rtti S1 { virtual s1func(); }; /* Polymorphic */
struct __rtti S2 { virtual s2func(); }; /* Polymorphic */
struct X : S1, S2 { };
If you turn off the RTTI mechanism, type information might not be available for derived classes. When a class is derived from
multiple classes, the order and type of base classes determines whether or not the class inherits the RTTI capability.
When you have polymorphic and non-polymorphic classes, the order of inheritance is important. If you compile the following
declarations without RTTI, you should declare X with the __rtti modifier. Otherwise, switching the order of the base classes for
the class X results in the compile-time error "Can't inherit non-RTTI class from RTTI base 'S1'."
3 struct __rtti S1 { virtual func(); }; /* Polymorphic class */
struct S2 { }; /* Non-polymorphic class */
struct __rtti X : S1, S2 { };
Note: The class X is explicitly declared with __rtti
. This makes it safe to mix the order and type of classes. In the following example, class X inherits only non-polymorphic
classes. Class X does not need to be declared __rtti.
struct __rtti S1 { }; // Non-polymorphic class
528
3.1 C++ Reference RAD Studio C++ Language Guide
struct S2 { };
struct X : S2, S1 { }; // The order is not essential
Neither the __rtti keyword, nor enabling RTTI will make a static class into a polymorphic class.
See Also
Runtime Type Identification (RTTI) Overview ( see page 453)
Keyword extensions
Description
The keyword __thread is used in multithread programs to preserve a unique copy of global and static class variables. Each
program thread maintains a private copy of a __thread variable for each thread.
3.1.3.2.15 __try
Category
Syntax
__try compound-statement handler-list__try
__try compound-statement termination-statement
Description
The __try keyword is supported in both C and C++ programs. You can also use try in C++ programs.
A block of code in which an exception can occur must be prefixed by the keyword __try. Following the try keyword is a block of
code enclosed by braces. This indicates that the program is prepared to test for the existence of exceptions. If an exception
occurs, the normal program flow is interrupted. The program begins a search for a handler that matches the exception. If the
exception is generated in a C module, it is possible to handle the structured exception in either a C module or a C++ module.
If a handler can be found for the generated structured exception, the following actions can be taken:
529
C++ Language Guide RAD Studio 3.1 C++ Reference
Form 1
class _export <class name>
Form 2
return_type _export <function name>
Form 3
data_type _export <data name>
Description
The linker enters functions flagged with _export or __export into an export table for the module.
Using _export or __export eliminates the need for an EXPORTS section in your module definition file.
Functions that are not modified with _export or __export receive abbreviated prolog and epilog code, resulting in a smaller
object file and slightly faster execution.
or __export to export a function, that function will be exported by name rather than by ordinal (ordinal is usually more efficient).
If you want to change various attributes from the default, you'll need a module definition file.
Syntax
return-value _fastcall function-name(parm-list)
return-value __fastcall function-name(parm-list)
Description
Use the __fastcall modifier to declare functions that expect parameters to be passed in registers. The first three parameters are
passed (from left to right) in EAX, EDX, and ECX, if they fit in the register. The registers are not used if the parameter is a
floating-point or struct type.
Note: All VCL class member functions and form class member functions must use the __fastcall
3 convention. The compiler treats this calling convention as a new language specifier, along the lines of _cdecl and _pascal
Functions declared using _cdecl or _pascal cannot have the _fastcall modifier because they use the stack to pass parameters.
Likewise, the __fastcall modifier cannot be used together with _export.
The compiler prefixes the __fastcall function name with an at-sign ("@"). This prefix applies to both unmangled C function
names and to mangled C++ function names.
For Microsoft C++ style __fastcall implementation, see __msfastcall and __msreturn.
530
3.1 C++ Reference RAD Studio C++ Language Guide
Note: Note: The __fastcall modifier is subject to name mangling. See the description of the -VC option.
Syntax
__stdcall <function-name>
_stdcall <function-name>
Description
The _stdcall and __stdcall keywords force the compiler to generate function calls using the Standard calling convention.
Functions must pass the correct number and type of arguments; this is unlike normal C use, which permits a variable number of
function arguments.
Note: Note: The __stdcall modifier is subject to name mangling. See the description of the -VC option.
3.1.3.2.19 alignof
Category
Syntax
alignof(type);
Description
The alignof operator tells you the alignment of a type. This feature is one of the C++0x features added to C++Builder 2009.
The result is an integer constant of type std::size_t. The value indicates the boundaries on which elements of that type are
aligned in memory. An alignment of 2 means that the type must begin on even memory addresses, for instance. A typical value
for alignof(double) might be 8.
Applying alignof to a reference type yields the alignment of the referenced type. If you apply alignof to an array type, you get
the alignment of its element's type.
See Also
C++0x Features (C++Builder 2009) ( see page 462)
3
3.1.3.2.20 and, &&
Category
Syntax
Description
531
C++ Language Guide RAD Studio 3.1 C++ Reference
The and operator is an alternative representation of the && operator (binary or logical AND).
If both operands have a value of true, the result has the value true. Otherwise, the result has the value false. Both operands are
implicitly converted to bool and the result type is bool.
Unlike the & (bitwise AND) operator, the && operator guarantees left-to-right evaluation of the operands. If the left operand
evaluates to 0 (or false), the right operand is not evaluated.
Both the and and && operators short-circuit (that is, do not evaluate the second operand if the first evaluates as false). Thus, it is
both valid and safe to test for a null pointer, as in the following example:
In order to use the and operator, you need to check the Enable new operator names option (the -Vn compiler switch, available
on the Compatibility page of the Project Options dialog box).
Example of and
bool test( int * p ) {
return (p != 0) and (*p > 5);
};
}
Substituting && for and is also valid.
You can overload the && operator as well as the alternative representation, and. Keep in mind that when the operator is
overloaded, the logic is not short-circuited, and the empty pointer test is not safe. Here is an example demonstrating how to
overload and:
struct example { bool operator and ( const example & ) {return true;}// same as operator &&}
Using && in rvalue References
As part of the new C++0x standard, C++Builder now supports rvalue references. An rvalue reference is formed by placing an &&
(but not an and) after a type in a declaration, as follows:
Apt a;Apt&& a_ref1 = a;
A major difference between the familiar lvalue reference and the new rvalue reference is that rvalue references can bind to a
temporary (that is, an rvalue), but an lvalue reference (at least one that is not a const) cannot bind to an rvalue.
Syntax
asm <opcode> <operands> <; or newline>_asm__asm
_asm <opcode> <operands> <; or newline>
__asm <opcode> <operands> <; or newline>
Description
3
Use the asm, _asm, or __asm keyword to place assembly language statements in the middle of your C or C++ source code.
Any C++ symbols are replaced by the appropriate assembly language equivalents.
You can group assembly language statements by beginning the block of statements with the asm keyword, then surrounding the
statements with braces ({}).
532
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.22 auto
Category
Syntax
[auto] <data-definition> ;
Description
Use the auto modifer to define a local variable as having a local lifetime.
Syntax
Description
The bitwise AND operator compares each bit of the first operand to the corresponding bit of the second operand When both bits
are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.
In order to use the bitand operator, you need to check the Enable new operator names option (the -Vn compiler switch,
available on the Compatibility page of the Project Options dialog box).
3.1.3.2.24 bitor, |
Category
Syntax
Description
bitor takes integer or enumeration operands. bitor may pass two or more arguments. These arguments must be character or
numeric.
When coded as a keyword, bitor can only pass two arguments. In either case, the result type is the same as the arguments: (1)
unsigned if all arguments are unsigned, or (2) an integer. 3
In order to use the bitor operator, you need to check the Enable new operator names option (the -VM compiler switch,
available on the Compatibility page of the Project Options dialog box).
533
C++ Language Guide RAD Studio 3.1 C++ Reference
C++-Specific Keywords
Syntax
bool <identifier>;
Description
Use bool and the literals false and true to perform Boolean logic tests.
The bool keyword represents a type that can take only the value false or true. The keywords false and true are Boolean literals
with predefined values. false is numericallly zero and true is numerically one. These Boolean literals are rvalues; you cannot
make an assignment to them.
You can convert an rvalue that is of type bool to an rvalue that is int type. The numerical conversion sets false to zero and true
becomes one.
You can convert arithmetic, enumeration, pointer, or pointer to member rvalue types to an rvalue of type bool. A zero value, null
pointer value, or null member pointer value is converted to false. Any other value is converted to true.
3.1.3.2.26 break
Category
Statements
Syntax
Description
Use the break statement within loops to pass control to the first statement following the innermost switch, for, while, or do
block.
Example
This example illustrates the use of keywords break, case, default, return, and switch.
#include <iostream>
cout << "PRESS a, b, OR c. ANY OTHER CHOICE WILL TERMINATE THIS PROGRAM." << endl;
for ( /* FOREVER */; cin >> ch; )
switch (ch)
{
case 'a' : /* THE CHOICE OF a HAS ITS OWN ACTION. */
cout << endl << "Option a was selected." << endl;
break;
case 'b' : /* BOTH b AND c GET THE SAME RESULTS. */
3 case 'c' :
cout << endl << "Option b or c was selected." << endl;
break;
default :
cout << endl << "NOT A VALID CHOICE! Bye ..." << endl;
return(-1);
}
}
See Also
continue ( see page 540)
534
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.27 case
Category
Statements
Syntax
switch ( <switch variable> ){casebreakdefault
case <constant expression> : <statement>; [break;]
.
.
.
default : <statement>;
}
Description
Use the case statement in conjunction with switches to determine which statements evaluate.
The list of possible branch points within <statement> is determined by preceding substatements with
case <constant expression> : <statement>;
where <constant expression> must be an int and must be unique.
The <constant expression> values are searched for a match for the <switch variable>.
If a match is found, execution continues after the matching case statement until a break statement is encountered or the end of
the switch statement is reached.
This example illustrates the use of keywords break, case, default, return, and switch.
#include <iostream>
cout << "PRESS a, b, OR c. ANY OTHER CHOICE WILL TERMINATE THIS PROGRAM." << endl;
for ( /* FOREVER */; cin >> ch; )
switch (ch)
{
case 'a' : /* THE CHOICE OF a HAS ITS OWN ACTION. */
cout << endl << "Option a was selected." << endl;
break;
535
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.2.28 catch
Category
Syntax
catch (exception-declaration) compound-statement
Description
The exception handler is indicated by the catch keyword. The handler must be used immediately after the statements marked by
the try keyword. The keyword catch can also occur immediately after another catch. Each handler will only evaluate an
exception that matches, or can be converted to, the type specified in its argument list.
Syntax
cdecl <data/function definition> ;_cdecl__cdecl
_cdecl <data/function definition> ;
__cdecl <data/function definition> ;
Description
Use a cdecl, _cdecl, or __cdecl modifier to declare a variable or a function using the C-style naming conventions
(case-sensitive, with a leading underscore appended). When you use cdecl, _cdecl, or __cdecl in front of a function, it affects
how the parameters are passed (parameters are pushed right to left, and the caller cleans up the stack). The __cdecl modifier
overrides the compiler directives and IDE options.
3 The cdecl, _cdecl, and __cdecl keywords are specific to CodeGear C++.
3.1.3.2.30 char
Category
Type specifiers
536
3.1 C++ Reference RAD Studio C++ Language Guide
Syntax
[signed|unsigned] char <variable_name>
Description
Use the type specifier char to define a character data type. Variables of type char are 1 byte in length.
Objects declared as characters (char) are large enough to store any member of the basic ASCII character set.
3.1.3.2.31 char16_t
Category
Syntax
char16_t <identifier>;
Description
In C++ programs, char16_t is a fundamental data type that can represent a 16 bit character type. This type could be used for
UTF-16 characters. You can create a char16_t type with u'<character>', which is a literal for a single char16_t character
3.1.3.2.32 char32_t
Category
Syntax
char32_t <identifier>;
Description
In C++ programs, char32_t is a fundamental data type that can represent a 32 bit character type. This type could be used for
UTF-32 characters. You can create a char32_t type with U'<character>', which is a literal for a single char32_t character
3.1.3.2.33 class
Category
Syntax
<classkey> <classname> <baselist> { <member list> }
• <classkey> is either a class, struct, or union. 3
• <classname> can be any name unique within its scope.
• <baselist> lists the base class(es) that this class derives from. <baselist> is optional
• <member list> declares the class's data members and member functions.
Description
Use the class keyword to define a C++ class.
537
C++ Language Guide RAD Studio 3.1 C++ Reference
Within a class:
• the data are called data members
• the functions are called member functions
See Also
Private ( see page 560)
3.1.3.2.34 compl, ~
Category
Syntax
Description
compl Inverts true to false and false to true, The tilde (~) is placed in front of the integer used for the complement.
Besides an integer, ~ also outputs an enumeration type; this can be the result of the one’s complement of the operand. Integral
calculations are performed.
There can be ambiguity in the unary expression ~X(), where X is a class-name. The ambiguity is resolved in favor of treating ~
as a unary complement rather than treating ~X as a destructor.
In order to use the compl operator, you need to check the Enable new operator names option (the -VM compiler switch,
available on the Compatibility page of the Project Options dialog box).
3.1.3.2.35 const
Category
Modifiers
Syntax
const <variable name> [ = <value> ];
<function name> ( const <type>*<variable name> ;)
3 <function name> const;
Description
Use the const modifier to assign an initial value to a variable that cannot be changed by the program. Any future assignments to
a const result in a compiler error.
A const pointer cannot be modified, though the object to which it points can be changed. Consider the following examples.
538
3.1 C++ Reference RAD Studio C++ Language Guide
// A constant pointer
char *const str1 = "Hello, world";
C++ extends const to include classes and member functions. In a C++ class definition, use the const modifier following a
member function declaration. The member function is prevented from modifying any data in the class.
A class object defined with the const keyword attempts to use only member functions that are also defined with const. If you call
a member function that is not defined as const, the compiler issues a warning that a non-const function is being called for a
const object. Using the const keyword in this manner is a safety feature of C++.
See Also
mutable ( see page 555)
C++-Specific Keywords
Syntax
const_cast< T > (arg)
Description
Use the const_cast operator to add or remove the const or volatile modifier from a type.
In the statement, const_cast< T > (arg), T and arg must be of the same type except for const and volatile modifiers. The cast is 3
resolved at compile time. The result is of type T. Any number of const or volatile modifiers can be added or removed with a
single const_cast expression.
A pointer to const can be converted to a pointer to non-const that is in all other respects an identical type. If successful, the
resulting pointer refers to the original object.
A const object or a reference to const cast results in a non-const object or reference that is otherwise an identical type.
The const_cast operator performs similar typecasts on the volatile modifier. A pointer to volatile object can be cast to a pointer
539
C++ Language Guide RAD Studio 3.1 C++ Reference
to non-volatile object without otherwise changing the type of the object. The result is a pointer to the original object. A
volatile-type object or a reference to volatile-type can be converted into an identical non-volatile type.
See Also
Dynamic_cast (typecast Operator) ( see page 547)
3.1.3.2.37 continue
Category
Statements
Syntax
continue;
Description
Use the continue statement within loops to pass control to the end of the innermost enclosing end brace belonging to a looping
construct, such as for or while; at which point the loop continuation condition is re-evaluated.
Example
3 3.1.3.2.38 __declspec(dllexport)
Category
Syntax
__declspec( dllexport ) declarator
The
540
3.1 C++ Reference RAD Studio C++ Language Guide
dllexport storage-class attribute is used for Microsoft C and C++ language compatibility. This attribute enables you to export
functions, data, and objects from a DLL. This attribute explicitly defines the DLL’s interface to its client, which can be the
executable file or another DLL. Declaring functions as dllexport eliminates the need for a module-definition (.DEF) file, at least
with respect to the specification of exported functions.
Note: dllexport
3.1.3.2.39 __declspec(dllimport)
Category
Syntax
__declspec( dllimport ) declarator
The dllimport storage-class attribute is used for Microsoft C and C++ language compatability. This attribute enables you to
import functions, data, and objects to a DLL
Note: Note
3.1.3.2.40 __declspec(naked)
Category
Syntax
__declspec( naked ) declarator
Use of the naked argument suppresses the prolog/epilog code. Be aware when using __declspec(naked) that it does not set up
a normal stack frame. A function with __declspec(naked) will not preserve the register values that are normally preserved. It is
the programmer's responsibility to conform to whatever conventions the caller of the function expects.
You can use this feature to write your own prolog/epilog code using inline assembler code. Naked functions are particularly
useful in writing virtual device drivers.
The naked attribute is relevant only to the definition of a function and is not a type modifier.
Example
3.1.3.2.41 __declspec(noreturn)
Category
541
C++ Language Guide RAD Studio 3.1 C++ Reference
Syntax
__declspec( noreturn ) declarator
This __declspec attribute tells the compiler that a function does not return. As a consequence, the compiler knows that the code
following a call to a __declspec(noreturn) function is unreachable.
If the compiler finds a function with a control path that does not return a value, it generates a warning. If the control path cannot
be reached due to a function that never returns, you can use __declspec(noreturn) to prevent this warning or error.
Example
Consider the following code. The else clause does not contain a return statement, so the programmer declares fatal as
__declspec(noreturn) to avoid an error or warning message.
__declspec(noreturn) extern void fatal ()
{
// Code omitted
}
int foo()
{
if(...)
return 1;
else if(...)
return 0;
else
fatal();
}
3.1.3.2.42 __declspec(nothrow)
Category
Syntax
__declspec( nothrow ) declarator
This is a __declspec extended attribute that can be used in the declaration of functions. This attribute tells the compiler that the
declared function and the functions it calls never throw an exception. With the synchronous exception handling model, now the
default, the compiler can eliminate the mechanics of tracking the lifetime of certain unwindable objects in such a function, and
significantly reduce the code size.
3.1.3.2.43 __declspec(novtable)
Category
Syntax
542
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.44 __declspec(property)
Category
Syntax
__declspec( property( get=get_func_name ) ) declarator
__declspec( property( put=put_func_name ) ) declarator
__declspec( property( get=get_func_name, put=put_func_name ) ) declarator
This attribute can be applied to non-static “virtual data members” in a class or structure definition. The compiler treats these
“virtual data members” as data members by changing their references into function calls.
When the compiler sees a data member declared with this attribute on the right of a member-selection operator (“.” or “->“), it
converts the operation to a get or put function, depending on whether such an expression is an l-value or an r-value. In more
complicated contexts, such as “+=“, a rewrite is performed by doing both get and put.
This attribute can also be used in the declaration of an empty array in a class or structure definition.
Example
The above statement indicates that x[] can be used with one or more array indices. In this case:
i=p->x[a][b]
will be turned into:
i=p->GetX(a, b),
and
p->x[a][b] = i
will be turned into
p->PutX(a, b, i);
3.1.3.2.45 __declspec(selectany)
Category
Note This attribute can only be applied to the actual initialization of global data items that are externally visible.
543
C++ Language Guide RAD Studio 3.1 C++ Reference
Example
//Incorrect - __declspec(selectany) is applied to the uninitialized //declaration of x5 extern __declspec(selectany) int x5;
3.1.3.2.46 __declspec(thread)
Category
Syntax
__declspec( thread ) declarator
Thread Local Storage (TLS) is the method by which each thread in a given multithreaded process allocates storage for
thread-specific data.
The thread extended storage-class modifier is used to declare a thread local variable. The thread attribute must be used with
the __declspec keyword.
3.1.3.2.47 __declspec(uuid(“ComObjectGUID”))
Category
Syntax
__declspec( uuid(“ComObjectGUID”) ) declarator
3 The compiler attaches a GUID to a class or structure declared or defined (full COM object definitions only) with the uuid
attribute. The uuid attribute takes a string as its argument. This string names a GUID in normal registry format with or without the
{ } delimiters. For example:
This attribute can be applied in a redeclaration. This allows the system headers to supply the definitions of interfaces such as
544
3.1 C++ Reference RAD Studio C++ Language Guide
IUnknown, and the redeclaration in some other header (such as COMDEF.H) to supply the GUID.
The keyword __uuidof can be applied to retrieve the constant GUID attached to a user-defined type.
3.1.3.2.48 decltype
Category
Type specifiers
Syntax
decltype ( expression )
Description
Use the decltype type specifier to obtain the type specifier of an expression.
decltype may be applied to expressions that are identifiers, class members and function names or calls.
3.1.3.2.49 default
Category
Statements
Syntax
switch ( <switch variable> ){casebreakdefault
case <constant expression> : <statement>; [break;]
.
.
.
default : <statement>;
}
Description
• If a case match is not found and the default statement is found within the switch statement, the execution continues at this
point.
• If no default is defined in the switch statement, control passes to the next statement that follows the switch statement block.
Example
This example illustrates the use of keywords break, case, default, return, and switch.
#include <iostream>
545
C++ Language Guide RAD Studio 3.1 C++ Reference
case 'c' :
cout << endl << "Option b or c was selected." << endl;
break;
default :
cout << endl << "NOT A VALID CHOICE! Bye ..." << endl;
return(-1);
}
}
See Also
break ( see page 534)
3.1.3.2.50 delete
Category
Syntax
void operator delete(void *ptr) throw();
void operator delete(void *ptr, const std::nothrow_t&) throw();
void operator delete[](void *ptr) throw();
void operator delete[](void *ptr, const std::nothrow_t &) throw();
void operator delete(void *ptr, void *) throw(); // Placement form
void operator delete[](void *ptr, void *) throw(); // Placement form
Description
The delete operator deallocates a memory block allocated by a previous call to new. It is similar but superior to the standard
library function free.
You should use the delete operator to remove all memory that has been allocated by the new operator. Failure to free memory
can result in memory leaks.
The default placement forms of operator delete are reserved and cannot be redefined. The default placement delete operator
performs no action (since no memory was allocated by the default placement new operator). If you overload the placement
version of operator new, it is a good idea (though not strictly required) to provide the overload the placement delete operator with
the corresponding signature.
See Also
Overloading The Operator delete ( see page 436)
3.1.3.2.51 do
3
Category
Statements
Syntax
do <statement> while ( <condition> );
Description
546
3.1 C++ Reference RAD Studio C++ Language Guide
Since the conditon tests after each the loop executes the <statement>, the loop will execute at least once.
See Also
while ( see page 574)
3.1.3.2.52 double
Category
Type specifiers
Syntax
[long] double <identifier>
Description
Use the double type specifier to define an identifier to be a floating-point data type. The optional modifier long extends the
accuracy of the floating-point value.
If you use the double keyword, the floating-point math package will automatically be linked into your program.
See Also
float ( see page 552)
C++-Specific Keywords
Description
In the expression, dynamic_cast< T > (ptr), T must be a pointer or a reference to a defined class type or void*. The argument ptr
must be an expression that resolves to a pointer or reference.
If T is void* then ptr must also be a pointer. In this case, the resulting pointer can access any element of the class that is the
most derived element in the hierarchy. Such a class cannot be a base for any other class.
Conversions from a derived class to a base class, or from one derived class to another, are as follows: if T is a pointer and ptr is
a pointer to a non-base class that is an element of a class hierarchy, the result is a pointer to the unique subclass. References
are treated similarly. If T is a reference and ptr is a reference to a non-base class, the result is a reference to the unique subclass.
A conversion from a base class to a derived class can be performed only if the base is a polymorphic type.
The conversion to a base class is resolved at compile time. A conversion from a base class to a derived class, or a conversion
across a hierarchy is resolved at runtime. 3
If successful, dynamic_cast< T > (ptr) converts ptr to the desired type. If a pointer cast fails, the returned pointer is valued 0. If a
cast to a reference type fails, the Bad_cast exception is thrown.
547
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
Const_cast (typecast Operator) ( see page 539)
3.1.3.2.54 enum
Category
Type specifiers
Syntax
enum [<type_tag>] {<constant_name> [= <value>], ...} [var_list];
• <type_tag> is an optional type tag that names the set.
• <constant_name> is the name of a constant that can optionally be assigned the value of <value>. These are also called
enumeration constants.
• <value> must be an integer. If <value> is missing, it is assumed to be: <prev> + 1 where <prev> is the value of the previous
integer constant in the list. For the first integer constant in the list, the default value is 0.
• <var_list> is an optional variable list that assigns variables to the enum type.
Description
Use the enum keyword to define a set of constants of type int, called an enumeration data type.
An enumeration data type provides mnemonic identifiers for a set of integer values. Use the -b flag to toggle the Treat Enums As
Ints option. .Enums are always interpreted as ints if the range of values permits this, but if they are not ints the value gets
promoted to an int in expressions. Depending on the values of the enumerators, identifiers in an enumerator list are implicitly
of type signed char, unsigned char, short, unsigned short, int, or unsigned int.
In C, an enumerated variable can be assigned any value of type int--no type checking beyond that is enforced. In C++, an
enumerated variable can be assigned only one of its enumerators.
In C++, you can omit the enum keyword if <tag_type> is not the name of anything else in the same scope. You can also omit
<tag_type> if no further variables of this enum type are required.
In the absence of a <value> the first enumerator is assigned the value of zero. Any subsequent names without initializers will
then increase by one. <value> can be any expression yielding a positive or negative integer value (after possible integer
promotions). These values are usually unique, but duplicates are legal.
Enumeration tags share the same name space as structure and union tags. Enumerators share the same name space as
ordinary variable identifiers.
In C++, enumerators declared within a class are in the scope of that class.
3.1.3.2.55 explicit
3
Category
C++-Specific Keywords
Syntax
explicit <single-parameter constructor declaration>
Description
548
3.1 C++ Reference RAD Studio C++ Language Guide
Normally, a class with a single-parameter constructor can be assigned a value that matches the constructor type. This value is
automatically (implicitly) converted into an object of the class type to which it is being assigned. You can prevent this kind of
implicit conversion from occurring by declaring the constructor of the class with the explicit keyword. Then all objects of that
class must be assigned values that are of the class type; all other assignments result in a compiler error.
Objects of the following class can be assigned values that match the constructor type or the class type:
class X {
public:
X(int);
X(const char*, int = 0);
};
Then, the following assignment statements are legal.
void f(X arg) {
X a = 1;
X B = "Jessie";
a = 2;
}
However, objects of the following class can be assigned values that match the class type only:
class X {
public:
explicit X(int);
explicit X(const char*, int = 0);
};
The explicit constructors then require the values in the following assignment statements to be converted to the class type to
which they are being assigned.
void f(X arg) {
X a = X(1);
X b = X("Jessie",0);
a = X(2);
}
3.1.3.2.56 export
Category
Unimplemented
Syntax
export template < template-parameter-list > declaration
Description
The export keyword is reserved for future implementation, but has no effect in this release.
See Also
_export ( see page 530)
3
3.1.3.2.57 extern
Category
Syntax
extern <data definition> ;
549
C++ Language Guide RAD Studio 3.1 C++ Reference
Use the extern modifier to indicate that the actual storage and initial value of a variable, or body of a function, is defined in a
separate source code module. Functions declared with extern are visible throughout all source files in a program, unless you
redefine the function as static.
Use extern "C" to prevent function names from being mangled in C++ programs.
Also, extern templates allow you to define templates that are not instantiated in a translation unit. Using extern templates thus
reduces both compilation time and the size of the compiled module. The extern template ( see page 494) feature is part of the
new C++0x standard.
3.1.3.2.58 final
Category
Syntax
return-type function-name [[final]]
Description
The final attribute prevents a class or function from being further inherited. You can add the final attribute to a class definition or
to a virtual member function declaration inside a class definition. If the attribute is specified for a class definition, it is equivalent
to being specified for each virtual member function of that class, including inherited member functions.
See Also
Attributes noreturn and final ( see page 492)
3.1.3.2.59 __finally
Category
Syntax
__finally {compound-statement}
Description
The __finally keyword specifies actions that should be taken regardless of how the flow within the preceding __try exits.
The following is the code fragment shows how to use the try/__finally construct:
#include <stdio.h>#include <string.h>#include <windows.h>class
3 Exception{public:Exception(char* s = "Unknown"){what = strdup(s); }Exception(const
Exception& e ){what = strdup(e.what); } ~Exception() {free(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;}
#include <string.h>
#include <windows.h>
550
3.1 C++ Reference RAD Studio C++ Language Guide
class Exception
{
public:
Exception(char* s = "Unknown"){what = strdup(s); }
Exception(const Exception& e ){what = strdup(e.what); }
~Exception() {free(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;
}
#include <iostream>#include <stdexcept>using namespace std;class MyException : public
exception {public:virtual const char *what() const throw() {return("MyException
occurred.");}};// Give me any integer...void myFunc(int a){ MyException e; // ...but not
that one. if(a == 0) throw(e);}void main(){ int g; // Note __finally must be in its
own try block (with no preceding catch). try { try { g = 0; myFunc(g);
} catch(MyException &e) { cout << "Exception: " << e.what() << endl; } }
__finally { cout << "Finally block reached." << endl; }
#include <stdexcept>
using namespace std;
class MyException : public exception {
public:
virtual const char *what() const throw() {
return("MyException occurred.");
}
};
// Give me any integer... 3
void myFunc(int a)
{
MyException e;
// ...but not that one.
if(a == 0)
throw(e);
}
void main()
{
551
C++ Language Guide RAD Studio 3.1 C++ Reference
int g;
// Note __finally must be in its own try block (with no preceding catch).
try {
try {
g = 0;
myFunc(g);
}
catch(MyException &e) {
cout << "Exception: " << e.what() << endl;
}
}
__finally {
cout << "Finally block reached." << endl;
}
}
Running the above program results in the following:
Another exception:Caught a C-based exception.Caught C++ exception[Hardware error: Divide by
0]C++ allows __finally too!Exception: MyException occurred.Finally block reached.
Caught a C-based exception.Caught C++ exception[Hardware error: Divide by 0]C++ allows
__finally too!Exception: MyException occurred.Finally block reached.
3.1.3.2.60 float
Category
Type specifiers
Syntax
float <identifier>
Description
Use the float type specifier to define an identifier to be a floating-point data type.
The floating-point math package will be automatically linked into your program if you use floating-point values or operators.
See Also
double ( see page 547)
3.1.3.2.61 for
Category
Statements
Syntax
3
for ( [<initialization>] ; [<condition>] ; [<increment>] ) <statement>
Description
552
3.1 C++ Reference RAD Studio C++ Language Guide
• Before the first iteration of the loop, <initialization> initializes variables for the loop.
• After each iteration of the loop, <increments> increments a loop counter. Consequently, j++ is functionally the same as ++j.
In C++, <initialization> can be an expression or a declaration.
The scope of any identifier declared within the for loop extends to the end of the control statement only.
A variable defined in the for-initialization expression is in scope only within the for-block. See the description of the -Vd option.
All the expressions are optional. If <condition> is left out, it is assumed to be always true.
3.1.3.2.62 friend
Category
C++-Specific Keywords
Syntax
friend <identifier>;
Description
Use friend to declare a function or class with full access rights to the private and protected members of the class, without being
a member of that class. The outside class has fill access to the class that declares that outside class a friend.
In all other respects, the friend is a normal function in terms of scope, declarations, and definitions.
3.1.3.2.63 goto
Category
Statements
Syntax
goto <identifier> ;
Description
Use the goto statement to transfer control to the location of a local label specified by <identifier>.
Operators
C++ Syntax
if ( <condition1> ) <statement1> 3
if ( <condition1> ) <statement1>;
else <statement2>;
if ( <condition1> ) <statement1>;
else if ( <condition2> ) <statement2>;
else <statement3>;
if ( <condition1> )
{
if ( <condition2> ) {
<statement1>
<statement2>
553
C++ Language Guide RAD Studio 3.1 C++ Reference
}
else <statement3>
}
else
<statement4>
Description
The condition statement must convert to a bool type. Otherwise, the condition is ill-formed.
The else keyword is optional, but no statements can come between an if statement and an else.
The #if and #else preprocessor statements (directives) look similar to the if and else statements, but have very different effects.
They control which source file lines are compiled and which are ignored.
Form 1
class _import <class name>
class __import <class name>
Form 2
return_type _import <function name>
return_type __import <function name>
Form 3
data_type _import <data name>
data_type __import <data name>
Description
3.1.3.2.66 inline
3 Category
C++-Specific Keywords
Syntax
inline <datatype> <class>_<function> (<parameters>) { <statements>; }
Description
554
3.1 C++ Reference RAD Studio C++ Language Guide
Inline functions are best reserved for small, frequently used functions.
3.1.3.2.67 int
Category
Type specifiers
Syntax
[signed|unsigned] int <identifier> ;
Description
3.1.3.2.68 long
Category
Type specifiers
Syntax
long [int] <identifier> ;
[long] double <identifier> ;
Description
When used to modify a double, it defines a floating-point data type with 80 bits of precision instead of 64.
The floating-point math package will be automatically linked with your program if you use floating-point values or operators.
3.1.3.2.69 mutable
Category
Syntax
mutable <variable name>;
Description
Use the mutable specifier to make a variable modifiable even though it is in a const-qualified expression.
Only class data members can be declared mutable. The mutable keyword cannot be used on static or const names. The
purpose of mutable is to specify which data members can be modified by const member functions. Normally, a const member 3
function cannot modify data members.
See Also
const ( see page 538)
555
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.2.70 namespace
Category
C++-Specific Keywords
Description
Most real-world applications consist of more than one source file. The files can be authored and maintained by more than one
developer. Eventually, the separate files are organized and linked to produce the final application. Traditionally, the file
organization requires that all names that aren't encapsulated within a defined namespace (such as function or class body, or
translation unit) must share the same global namespace. Therefore, multiple definitions of names discovered while linking
separate modules require some way to distinguish each name. The solution to the problem of name clashes in the global scope
is provided by the C++ namespace mechanism.
The namespace mechanism allows an application to be partitioned into a number of subsystems. Each subsystem can define
and operate within its own scope. Each developer is free to introduce whatever identifiers are convenient within a subsystem
without worrying about whether such identifiers are being used by someone else. The subsystem scope is known throughout the
application by a unique identifier.
It only takes two steps to use C++ namespaces. The first is to uniquely identify a namespace with the keyword namespace. The
second is to access the elements of an identified namespace by applying the using keyword.
3.1.3.2.71 new
Category
Syntax
void *operator new(std::size_t size) throw(std::bad_alloc);
void *operator new(std::size_t size, const std::nothrow_t &) throw();
void *operator new[](std::size_t size) throw(std::bad_alloc);
void *operator new[](std::size_t size, const std::nothrow_t &) throw();
void *operator new(std::size_t size, void *ptr) throw(); // Placement form
void *operator new[](std::size_t size, void *ptr) throw(); // Placement form
Description
The new operators offer dynamic storage allocation, similar but superior to the standard library function malloc. These allocation
functions attempt to allocate size bytes of storage. If successful, new returns a pointer to the allocated memory. If the allocation
fails, the new operator will call the new_handler function. The default behavior of new_handler is to throw an exception of type
bad_alloc. If you do not want an exception to be thrown, use the nothrow version of operator new. The nothrow versions return
a null pointer result on failure, instead of throwing an exception.
The default placement forms of operator new are reserved and cannot be redefined. You can, however, overload the placement
form with a different signature (i.e. one having a different number, or different type of arguments). The default placement forms
3 accept a pointer of type void, and perform no action other than to return that pointer, unchanged. This can be useful when you
want to allocate an object at a known address. Using the placement form of new can be tricky, as you must remember to
explicitly call the destructor for your object, and then free the pre-allocated memory buffer. Do not call the delete operator on an
object allocated with the placement new operator.
A request for non-array allocation uses the appropriate operator new() function. Any request for array allocation will call the
appropriate operator new[]() function. Remember to use the array form of operator delete[](), when deallocating an array
created with operator new[]().
556
3.1 C++ Reference RAD Studio C++ Language Guide
Note: Arrays of classes require that a default constructor be defined in the class.
A request for allocation of 0 bytes returns a non-null pointer. Repeated requests for zero-size allocations return distinct, non-null
pointers.
3.1.3.2.72 noreturn
Category
Syntax
void function-name [[noreturn]]
Description
Use the noreturn modifier to declare functions that have no return value.
See Also
Attributes noreturn and final ( see page 492)
3.1.3.2.73 not, !
Category
Description
not returns true if its operand is false, and false if its operand is truet.
If an integer is 1, the expression of !1 indicates that the number is other than 1 So that is a true statement. not can also be used
557
C++ Language Guide RAD Studio 3.1 C++ Reference
for strings as well. The expression !Smith indicates that the person's name is other than Smith.. not inverts the bits of the
expression.
In order to use the not operator, you need to check the Enable new operator names option (the -VM compiler switch, available
on the Compatibility page of the Project Options dialog box).
3.1.3.2.74 not_eq, !=
Category
Syntax
Description
The not_eq operator is an alternative representation of != (bitwise inequality). It tests for logical inequivalence.
not_eq compares two expressions to determine whether or not they are the same.
Therefore, 7 != 8 returns true, while 7 != 7 returns false. The same is true for any expression such as Smith != Smith. which
returns false.
In order to use the not_eq operator, you need to check the Enable new operator names option (the -VM compiler switch,
available on the Compatibility page of the Project Options dialog box).
3.1.3.2.75 nullptr
Category
Reserved Words
Syntax
nullptr
Description
Reserved for future use. nullptr is a literal that can be assigned to any pointer to indicate the pointer doesn't point to anything.
but does treat it as a keyword when the -Ax compiler flag is set. Do not use nullptr as an identifier.
3.1.3.2.76 operator
Category
3 Syntax
operator <operator symbol>( <parameters> )
{
<statements>;
}
Description
Use the operator keyword to define a new (overloaded) action of the given operator. When the operator is overloaded as a
member function, only one argument is allowed, as *this is implicitly the first argument.
558
3.1 C++ Reference RAD Studio C++ Language Guide
When you overload an operator as a friend, you can specify two arguments.
See Also
class ( see page 537)
3.1.3.2.77 or, ||
Category
Syntax
Description
or returns false if both values are the same, such as 10 and 10.
In order to use the or operator, you need to check the Enable new operator names option (the -VM compiler switch, available
on the Compatibility page of the Project Options dialog box).
3.1.3.2.78 or_eq, |=
Category
Syntax
Description
or_eq operates on two values. When the first value or the second value is 1, true is returned. When the values are 0, false is
returned.
In order to use the not_eq operator, you need to check the Enable new operator names option (the -VM compiler switch,
available on the Compatibility page of the Project Options dialog box).
Syntax
pascal <data-definition/function-definition> ;
_pascal <data-definition/function-definition> ;
__pascal <data-definition/function-definition> ;
Description
Use the pascal, _pascal, and __pascal keywords to declare a variable or a function using a Pascal-style naming convention
559
C++ Language Guide RAD Studio 3.1 C++ Reference
In addition, pascal declares Delphi language-style parameter-passing conventions when applied to a function header
(parameters pushed left to right; the called function cleans up the stack).
In C++ programs, functions declared with the pascal modifier are still mangled.
3.1.3.2.80 private
Category
C++-Specific Keywords
Syntax
private: <declarations>
Description
Access to private class members is restricted to member functions within the class, and to friend classes.
Structure (struct) and union members are public by default. You can override the default access specifier for structures, but not
for unions.
Friend declarations can be placed anywhere in the class declaration; friends are not affected by access control specifiers.
See Also
class ( see page 537)
3.1.3.2.81 protected
Category
C++-Specific Keywords
Syntax
protected: <declarations>
Description
Access to protected class members is restricted to member functions within the class, member functions of derived classes, and
to friend classes.
Structure (struct) and union members are public by default. You can override the default access specifier for structures, but not
for unions.
3
Friend declarations can be placed anywhere in the class declaration; friends are not affected by access control specifiers.
See Also
class ( see page 537)
560
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.82 public
Category
C++-Specific Keywords
Syntax
public: <declarations>
Description
You can override the default access specifier for structures, but not for unions.
Friend declarations can be placed anywhere in the class declaration; friends are not affected by access control specifiers.
See Also
class ( see page 537)
3.1.3.2.83 register
Category
Syntax
register <data definition> ;
Description
Use the register storage class specifier to store the variable being declared in a CPU register (if possible), to optimize access
and reduce code.
Note: The compiler can ignore requests for register allocation. Register allocation is based on the compiler’s analysis of how a
variable is used.
C++-Specific Keywords
Syntax
reinterpret_cast< T > (arg)
Description
561
C++ Language Guide RAD Studio 3.1 C++ Reference
In the statement, reinterpret_cast< T > (arg), T must be a pointer, reference, arithmetic type, pointer to function, or pointer to
member.
An integral arg can be converted to a pointer. Converting a pointer to an integral type and back to the same pointer type results
in the original value.
A pointer to a function can be explicitly converted to a pointer to an object type provided the object pointer type has enough bits
to hold the function pointer. A pointer to an object type can be explicitly converted to a pointer to a function only if the function
pointer type is large enough to hold the object pointer.
See Also
Const_cast (typecast Operator) ( see page 539)
3.1.3.2.85 return
Category
Statements
Syntax
return [ <expression> ] ;
Description
Use the return statement to exit from the current function back to the calling routine, optionally returning a value.
Example
This example illustrates the use of keywords break, case, default, return, and switch.
#include <iostream>
cout << "PRESS a, b, OR c. ANY OTHER CHOICE WILL TERMINATE THIS PROGRAM." << endl;
for ( /* FOREVER */; cin >> ch; )
switch (ch)
{
case 'a' : /* THE CHOICE OF a HAS ITS OWN ACTION. */
cout << endl << "Option a was selected." << endl;
break;
3 case 'b' : /* BOTH b AND c GET THE SAME RESULTS. */
case 'c' :
cout << endl << "Option b or c was selected." << endl;
break;
default :
cout << endl << "NOT A VALID CHOICE! Bye ..." << endl;
return(-1);
}
}
562
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.86 short
Category
Type specifiers
Syntax
short int <variable> ;
Description
Use the short type modifier when you want a variable smaller than an int. This modifier can be applied to the base type int.
See Also
long ( see page 555)
3.1.3.2.87 signed
Category
Type specifiers
Syntax
signed <type> <variable> ;
Description
Use the signed type modifier when the variable value can be either positive or negative. The signed modifier can be applied to
base types int, char, long, short, and __int64.
See Also
char ( see page 536)
3.1.3.2.88 sizeof
3
Category
Operators
Description
sizeof unary-expression
563
C++ Language Guide RAD Studio 3.1 C++ Reference
sizeof (type-name)
The result in both cases is an integer constant that gives the size in bytes of how much memory space is used by the operand
(determined by its type, with some exceptions). The amount of space that is reserved for each type depends on the machine.
In the first use, the type of the operand expression is determined without evaluating the expression (and therefore without side
effects). When the operand is of type char (signed or unsigned), sizeof gives the result 1. When the operand is a
non-parameter of array type, the result is the total number of bytes in the array (in other words, an array name is not converted to
a pointer type). The number of elements in an array equals sizeof array/ sizeof array[0] .
If the operand is a parameter declared as array type or function type, sizeof gives the size of the pointer. When applied to
structures and unions, sizeof gives the total number of bytes, including any padding.
You cannot use sizeof with expressions of function type, incomplete types, parenthesized names of such types, or with an lvalue
that designates a bit field object.
You can use sizeof in preprocessor directives; this is specific to CodeGear C++.
In C++, sizeof(classtype), where classtype is derived from some base class, returns the size of the object (remember, this
includes the size of the base class).
Example
/* USE THE sizeof OPERATOR TO GET SIZES OF DIFFERENT DATA TYPES. */
#include <stdio.h>
struct st {
char *name;
int age;
double height;
};
struct st St_Array[]= { /* AN ARRAY OF structs */
{ "Jr.", 4, 34.20 }, /* St_Array[0] */
{ "Suzie", 23, 69.75 }, /* St_Array[1] */
};
int main()
{
long double LD_Array[] = { 1.3, 501.09, 0.0007, 90.1, 17.08 };
printf("\nNumber of elements in LD_Array = %d",
sizeof(LD_Array) / sizeof(LD_Array[0]));
/**** THE NUMBER OF ELEMENTS IN THE St_Array. ****/
printf("\nSt_Array has %d elements",
sizeof(St_Array)/sizeof(St_Array[0]));
/**** THE NUMBER OF BYTES IN EACH St_Array ELEMENT. ****/
printf("\nSt_Array[0] = %d", sizeof(St_Array[0]));
/**** THE TOTAL NUMBER OF BYTES IN St_Array. ****/
printf("\nSt_Array=%d", sizeof(St_Array));
return 0;
}
Output
Number of elements in LD_Array = 5
3 St_Array has 2 elements
St_Array[0] = 16
St_Array= 32
3.1.3.2.89 static
Category
564
3.1 C++ Reference RAD Studio C++ Language Guide
Syntax
static <data definition> ;static
static <function name> <function definition> ;
Description
Use the static storage class specifier with a local variable to preserve the last value between successive calls to that function. A
static variable acts like a local variable but has the lifetime of an external variable.
In a class, data and member functions can be declared static. Only one copy of the static data exists for all objects of the class.
A static member function of a global class has external linkage. A member of a local class has no linkage. A static member
function is associated only with the class in which it is declared. Therefore, such member functions cannot be virtual.
Static member functions can only call other static member functions and only have access to static data. Such member
functions do not have a this pointer.
See Also
Static Members ( see page 394)
3.1.3.2.90 static_assert
Category
Syntax
static_assert (constant-expression, error-message);
Description
The static_assert keyword is used to test assertions at compile-time, rather than at preprocessor or run-time.
C++-Specific Keywords
Syntax
static_cast< T > (arg)
Description
In the statement, static_cast< T > (arg), T must be a pointer, reference, arithmetic type, or enum type. Both T and arg must be
fully known at compile time.
If a complete type can be converted to another type by some conversion method already provided by the language, then making
such a conversion by using static_cast achieves exactly the same thing.
3
Integral types can be converted to enum types. A request to convert arg to a value that is not an element of enum is undefined.
The null pointer is converted to the null pointer value of the destination type, T.
A pointer to one object type can be converted to a pointer to another object type. Note that merely pointing to similar types can
cause access problems if the similar types are not similarly aligned.
You can explicitly convert a pointer to a class X to a pointer to some class Y if X is a base class for Y. A static conversion can be
made only under the following conditions:
565
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.2.92 struct
Category
Type specifiers
Syntax
struct [<struct type name>] {
[<type> <variable-name[, variable-name, ...]>] ;
.
.
.
} [<structure variables>] ;
Description
<struct type name> An optional tag name that refers to the structure type.
Though both <struct type name> and <structure variables> are optional, one of the two must appear.
You define elements in the record by naming a <type>, followed by one or more <variable-name> (separated by commas).
To declare additional variables of the same type, use the keyword struct followed by the <struct type name>, followed by the
3 variable names. In C++ the keyword struct can be omitted.
Note: The compiler allows the use of anonymous struct embedded within another structure.
See Also
class ( see page 537)
566
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.93 switch
Category
Statements
Syntax
switch ( <switch variable> ) {casebreakdefault
case <constant expression> : <statement>; [break;]
.
.
.
default : <statement>;
}
Description
Use the switch statement to pass control to a case that matches the <switch variable>. At which point the statements following
the matching case evaluate.
To avoid evaluating any other cases and relinquish control from the switch, terminate each case with break.
Example
This example illustrates the use of keywords break, case, default, return, and switch.
#include <iostream>
cout << "PRESS a, b, OR c. ANY OTHER CHOICE WILL TERMINATE THIS PROGRAM." << endl;
for ( /* FOREVER */; cin >> ch; )
switch (ch)
{
case 'a' : /* THE CHOICE OF a HAS ITS OWN ACTION. */
cout << endl << "Option a was selected." << endl;
break;
case 'b' : /* BOTH b AND c GET THE SAME RESULTS. */
case 'c' :
cout << endl << "Option b or c was selected." << endl;
break;
default :
cout << endl << "NOT A VALID CHOICE! Bye ..." << endl;
return(-1);
}
}
See Also
3
break ( see page 534)
567
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.2.94 template
Category
C++-Specific Keywords
Syntax
template-declaration:templateclass
template < template-argument-list > declaration
template-argument-list:
template-argument
template-argument-list, template argument
template-argument:
type-argument
argument-declaration
type-argument:
class typename identifier
template-class-name:
template-name < template-arg-list >
template-arg-list:
template-arg
template-arg-list , template-arg
template-arg:
expression
type-name
< template-argument-list > declaration
Description
Use templates (also called generics or parameterized types) to construct a family of related functions or classes.
3.1.3.2.95 this
Category
C++-Specific Keywords
Example
class X {
int a;
public:
X (int b) {this -> a = b;}
};
Description
In nonstatic member functions, the keyword this is a pointer to the object for which the function is called. All calls to nonstatic
member functions pass this as a hidden argument.
this is a local variable available in the body of any nonstatic member function. Use it implicitly within the function for member
references. It does not need to be declared and it is rarely referred to explicitly in a function definition.
3
For example, in the call x.func(y) , where y is a member of X, the keyword this is set to &x and y is set to this->y, which is
equivalent to x.y.
Static member functions do not have a this pointer because they are called with no particular object in mind. Thus, a static
member function cannot access nonstatic members without explicitly specifying an object with . or ->.
See Also
class ( see page 537)
568
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.96 throw
Category
Syntax
throw assignment-expression
Description
When an exception occurs, the throw expression initializes a temporary object of the 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.
See Also
catch ( see page 536)
3.1.3.2.97 try
Category
Syntax
try compound-statement handler-list
Description
The try keyword is supported only in C++ programs. Use __try in C programs. C++ also allows __try.
A block of code in which an exception can occur must be prefixed by the keyword try. Following the try keyword is a block of
code enclosed by braces. This indicates that the program is prepared to test for the existence of exceptions. If an exception
occurs, the program flow is interrupted. The sequence of steps taken is as follows:
3.1.3.2.98 typedef
3
Category
Syntax
typedef <type definition> <identifier> ;
Description
569
C++ Language Guide RAD Studio 3.1 C++ Reference
Use the typedef keyword to assign the symbol name <identifier> to the data type definition <type definition>.
3.1.3.2.99 typeid
Category
Syntax
typeid( expression )
typeid( type-name )
Description
You can use typeid to get runtime identification of types and expressions. A call to typeid returns a reference to an object of
type const type_info. The returned object represents the type of the typeid operand.
If the typeid operand is a dereferenced pointer or a reference to a polymorphic type, typeid returns the dynamic type of the
actual object pointed or referred to. If the operand is non-polymorphic, typeid returns an object that represents the static type.
You can use the typeid operator with fundamental data types as well as user-defined types.
When the typeid operand is a Delphi class object/reference, typeid returns the static rather than runtime type.
If the typeid operand is a dereferenced NULL pointer, the Bad_typeid exception is thrown.
3.1.3.2.100 typename
Category
C++-Specific Keywords
Syntax 1
typename identifier
Syntax 2
template < typename identifier > class identifier
Description
Use the syntax 1 to reference a type that you have not yet defined. See example 1.
Use syntax 2 in place of the class keyword in a template declaration. See example 2.
keyword with templates, the compiler will not always report an error in cases where the ANSI standard requires the typename
keyword. The compiler will flag the omission of typename when the compiler is invoked with the -A switch. For example, given
the following code:
3 #include <stdio.h>
struct A{ typedef int AInt; };
Note: The compiler will flag the omission of typename when the compiler is invoked with the -A
switch.
570
3.1 C++ Reference RAD Studio C++ Language Guide
bc++bcc32 test.cpp
The result is no error. The Compiler should not assume AInt is a typename, but it does unless -A switch is used
switch)
bc++bcc32 -A test.cpp
The result is:
3.1.3.2.101 union
Category
Type specifiers
Syntax
union [<union type name>] {
<type> <variable names> ;
...
} [<union variables>] ;
Description
The compiler allocates enough storage in a_number to accommodate the largest element in the union.
Unlike a struct, the members of a union occupy the same location in memory. Writing into one overwrites all others.
See Also
class ( see page 537)
3.1.3.2.102 unsigned
Category
Type specifiers
Syntax 3
unsigned <type> <variable> ;
Description
Use the unsigned type modifier when variable values will always be positive. The unsigned modifer can be applied to base
types int, char, long, short, and __int64.
571
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
char ( see page 536)
C++-Specific Keywords
Description
You can access namespace members individually with the using-declaration syntax. When you make a using declaration, you
add the declared identifier to the local namespace. The grammar is
using-declaration:
using :: unqualified-identifier;
3.1.3.2.104 virtual
Category
C++-Specific Keywords
Syntax
virtual class-namevirtual
virtual function-name
Description
Use the virtual keyword to allow derived classes to provide different versions of a base class function. Once you declare a
function as virtual, you can redefine it in any derived class, even if the number and type of arguments are the same.
3.1.3.2.105 void
Category
Special types
3 Syntax
void identifier
Description
void is a special type indicating the absence of any value. Use the void keyword as a function return type if the function does
not return a value.
void hello(char *name)
{
572
3.1 C++ Reference RAD Studio C++ Language Guide
printf("Hello, %s.",name);
}
Use void as a function heading if the function does not take any parameters.
int init(void)
{
return 1;
}
Void Pointers
Generic pointers can also be declared as void, meaning that they can point to any type.
void pointers cannot be dereferenced without explicit casting because the compiler cannot determine the size of the pointer
object.
3.1.3.2.106 volatile
Category
Modifiers
Syntax
volatile <data definition> ;
Description
Use the volatile modifier to indicate that a background routine, an interrupt routine, or an I/O port can change a variable.
Declaring an object to be volatile warns the compiler not to make assumptions concerning the value of the object while
evaluating expressions in which it occurs because the value could change at any moment. It also prevents the compiler from
making the variable a register variable.
volatile int ticks;
void timer( ) {
ticks++;
}
void wait (int interval) {
ticks = 0;
while (ticks < interval); // Do nothing
}
The routines in this example (assuming timer has been properly associated with a hardware clock interrupt) implement a timed
wait of ticks specified by the argument interval. A highly optimizing compiler might not load the value of ticks inside the test of the
while loop since the loop doesn’t change the value of ticks.
to include classes and member functions. If you’ve declared a volatile object, you can use only its volatile member functions.
See Also
const ( see page 538)
3
3.1.3.2.107 wchar_t
Category
Syntax
573
C++ Language Guide RAD Studio 3.1 C++ Reference
wchar_t <identifier>;
Description
In C++ programs, wchar_t is a fundamental data type that can represent distinct codes for any element of the largest extended
character set in any of the supported locales. In CodeGear C++, A wchar_t type is the same size, signedness, and alignment
requirement as an unsigned short type.
3.1.3.2.108 while
Category
Statements
Syntax
while ( <condition> ) <statement>
Description
The test takes place before <statement> executes. Thus, if <condition> evaluates to false on the first pass, the loop does not
execute.
3.1.3.2.109 xor, ^
Category
Syntax
Description
It returns a Boolean true result if just one of its operands is true. This is in opposition to an inclusive or which denotes that both
statements must be integers for a true statement to be returned.
If 2 or 8.25 are stated to be integers, a true statement will be returned even though 8.25 is a decimal.
If Jack and Jill are both stated to be male, a true statement would be returned even though Jill is female.
In order to use the xor operator, you need to check the Enable new operator names option (the -VM compiler switch, available
on the Compatibility page of the Project Options dialog box).
3.1.3.2.110 __classmethod
3
Category
Syntax
virtual __classmethod int <funcdecl> ( int );
__classmethod virtual int <funcdecl> (int );
Description
574
3.1 C++ Reference RAD Studio C++ Language Guide
The __classmethod keyword was added to declare class methods in C++. The modifier __classmethod indicates that a
function may be invoked on a class name--as well as on an instance of that class.
See Also
__classid ( see page 523)
3.1.3.2.111 alignas
Category
C++-Specific Keywords
Syntax
alignas
Description
but does treat it as a keyword when the -Ax compiler flag is set.
Syntax
Description
The and_eq operator is an alternative representation of the &= assignment operator (bitwise AND).
The value of the first operand is added to the value of the second operand, and the result is stored in the first operand.
In order to use the and_eq operator, you need to check the Enable new operator names option (the -Vn compiler switch,
available on the Compatibility page of the Project Options dialog box).
See Also
Assignment Operators ( see page 591)
3.1.3.2.113 axiom
Category
Reserved Words
3
Syntax
axiom
Description
575
C++ Language Guide RAD Studio 3.1 C++ Reference
but does treat it as a keyword when the -Ax compiler flag is set.
3.1.3.2.114 concept
Category
Reserved Words
Syntax
concept
Description
but does treat it as a keyword when the -Ax compiler flag is set.
3.1.3.2.115 concept_map
Category
Reserved Words
Syntax
concept_map
Description
but does treat it as a keyword when the -Ax compiler flag is set.
3.1.3.2.116 constexpr
Category
Reserved Words
Syntax
constexpr
Description
3.1.3.2.117 late_check
Category
Reserved Words
576
3.1 C++ Reference RAD Studio C++ Language Guide
Syntax
late_check
Description
but does treat it as a keyword when the -Ax compiler flag is set.
3.1.3.2.118 requires
Category
Reserved Words
Syntax
requires
Description
but does treat it as a keyword when the -Ax compiler flag is set.
3.1.3.2.119 thread_local
Category
Reserved Words
Syntax
thread_local
Description
but does treat it as a keyword when the -Ax compiler flag is set.
3.1.3.2.120 xor_eq, ^=
Category
Description
The xor_eq operator is an alternative representation of the ^=; operator (bitwise XOR assignment)..
True is returned if one number on the left side of an equation is the same as another number on the right side, such as
10*5!=10*2.
577
C++ Language Guide RAD Studio 3.1 C++ Reference
In order to use the xor operator, you need to check the Enable new operator names option (the -VM compiler switch, available
on the Compatibility page of the Project Options dialog box).
3.1.3.2.121 _Bool
Category
Reserved Words
Syntax
_Bool
Description
but does treat it as a keyword when the -An compiler flag is set.
3.1.3.2.122 _Complex
Category
Reserved Words
Syntax
_Complex
Description
but does treat it as a keyword when the -An compiler flag is set.
3.1.3.2.123 _Imaginary
Category
Reserved Words
Syntax
_Imaginary
Description
3
Reserved for future use. _Imaginary is a literal that can be assigned to any pointer to indicate the pointer doesn't point to
anything.
but does treat it as a keyword when the -An compiler flag is set. Do not use _Imaginary as an identifier.
578
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.2.124 restrict
Category
Reserved Words
Syntax
restrict
Description
but does treat it as a keyword when the -An compiler flag is set.
Topics
Name Description
Alternative Representations of Tokens ( see page 579) This section contains topics about alternative representations of C++ tokens.
Attributes ( see page 580) This section contains C++ attributes keyword topics.
C++Builder Keyword Extensions ( see page 580) This section contains C++Builder Keyword Extension topics.
C++ Specific Keywords ( see page 581) This section contains C++ specific keyword topics.
Modifiers ( see page 582) This section contains C++ Modifier keyword topics.
Operators ( see page 583) This section contains C++ Operator keyword topics.
Reserved Words ( see page 584) This section contains C++ Reserved Words keyword topics.
Special Types ( see page 584) This section contains C++ Special Type keyword topics.
Statement Keywords ( see page 584) This section contains C++ Statement keyword topics.
Storage Class Specifiers ( see page 585) This section contains C++ Storage Class Specifier keyword topics.
Type Specifiers (C++) ( see page 586) This section contains C++ Type Specifier keyword topics.
Keyword Topics
The following table summarizes the alternative representation keywords and the token that each keyword represents.
579
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.3.2 Attributes
This section contains C++ attributes keyword topics.
Keyword Topics
final ( see page 550)
See Also
Attributes noreturn and final (C++0x) ( see page 492)
Keyword Topics
alignof ( see page 531)
580
3.1 C++ Reference RAD Studio C++ Language Guide
__int8 __int16 __int32 __int64 Unsigned_int64 (Extended integer types) ( see page 526)
Keyword Topics
asm ( see page 532)
581
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.3.5 Modifiers
This section contains C++ Modifier keyword topics.
Keyword Topics
Cdecl ( see page 536)
582
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.3.6 Operators
This section contains C++ Operator keyword topics.
Keyword Topics
alignof ( see page 531)
583
C++ Language Guide RAD Studio 3.1 C++ Reference
Keyword Topic
alignas ( see page 575)
Type Trait Functions ( see page 472), such as __is_abstract, and so forth
Keyword Topic
nullptr ( see page 558)
3 Keyword Topics
break ( see page 534)
584
3.1 C++ Reference RAD Studio C++ Language Guide
Keyword Topics
auto ( see page 533)
585
C++ Language Guide RAD Studio 3.1 C++ Reference
Keyword Topics
char ( see page 536)
Topics
Name Description
Binary Operators ( see page 587) This section contains Binary Operator topics.
Declarations ( see page 593) This section briefly reviews concepts related to declarations: objects, storage
classes, types, scope, visibility, duration, and linkage. A general knowledge of
these is essential before tackling the full declaration syntax. Scope, visibility,
3 duration, and linkage determine those portions of a program that can make legal
references to an identifier in order to access its object.
Declaration Syntax ( see page 600) All six interrelated attributes (storage classes, types, scope, visibility, duration,
and linkage) are determined in diverse ways by declarations.
Declarations can be defining declarations (also known as definitions) or
referencing declarations (sometimes known as nondefining declarations). A
defining declaration, as the name implies, performs both the duties of declaring
and defining; the nondefining declarations require a definition to be added
somewhere in the program. A referencing declaration introduces one or more
identifier names into a program. A definition actually allocates memory to an
object and associates an identifier with that object.
586
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Binary Operators ( see page 587) These are the binary operators in CodeGear C++:
Bitwise Operators ( see page 589) Syntax
C++ Specific Operators ( see page 590) The operators specific to C++ are:
Equality Operators ( see page 590) There are two equality operators: == and !=. They test for equality and inequality
between arithmetic or pointer values, following rules very similar to those for the
relational operators.
Note: Notice that ==
and != have a lower precedence than the relational operators < and >, <=, and
>=. Also, == and != can compare certain pointer types for equality and inequality
where the relational operators would not be allowed. The syntax is
Logical Operators ( see page 590) Syntax
>, <, >=, <= Relational Operators ( see page 591) Syntax
Assignment Operators ( see page 591) Syntax
Comma Operator ( see page 592) Syntax
Conditional Operators ( see page 592) Syntax
Multiplicative Operators ( see page 593) Syntax
587
C++ Language Guide RAD Studio 3.1 C++ Reference
588
3.1 C++ Reference RAD Studio C++ Language Guide
Use the bitwise operators to modify the individual bits rather than the number.
Note: &, >>, << are context sensitive. & can also be the pointer reference operator.
Note: >> is often overloaded to be the input operator in I/O expressions. << is often overloaded to be the output operator in I/O
expressions.
589
C++ Language Guide RAD Studio 3.1 C++ Reference
Operator Meaning
:: Scope access (or resolution) operator
.* Dereference pointers to class members
->* Dereference pointers to pointers to class members
const_cast adds or removes the const or volatile modifier from a type
delete dynamically deallocates memory
dynamic_cast converts a pointer to a desired type
new dynamically allocates memory
reinterpret_cast replaces casts for conversions that are unsafe or implementation dependent
static_cast converts a pointer to a desired type
typeid gets run-time identification of types and expressions
Use the scope access (or resolution) operator ::(two semicolons) to access a global (or file duration) name even if it is hidden by
a local redeclaration of that name.
Use the .* and ->* operators to dereference pointers to class members and pointers to pointers to class members.
and != have a lower precedence than the relational operators < and >, <=, and >=. Also, == and != can compare certain pointer
types for equality and inequality where the relational operators would not be allowed. The syntax is
equality-expression:==!=
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
&& logical AND; returns true only if both expressions evaluate to be nonzero, otherwise returns false. If the first expression
evaluates to false, the second expression is not evaluated.
|| logical OR; returns true if either of the expressions evaluate to be nonzero, otherwise returns false. If the first expression
evaluates to true, the second expression is not evaluated.
! logical negation; returns true if the entire expression evaluates to be nonzero, otherwise returns false. The expression !E is
590
3.1 C++ Reference RAD Studio C++ Language Guide
equivalent to (0 == E).
In the expression:
E1 <operator> E2
the operands must follow one of these conditions:
In the expression E1 = E2, E1 must be a modifiable lvalue. The assignment expression itself is not an lvalue.
3
The expression
E1 op= E2
has the same effect as
E1 = E1 op E2
except the lvalue E1 is evaluated only once. For example, E1 += E2 is the same as E1 = E1 + E2.
591
C++ Language Guide RAD Studio 3.1 C++ Reference
For both simple and compound assignment, the operands E1 and E2 must obey one of the following rules:
The comma is also used as an operator in comma expressions. Mixing the two uses of comma is legal, but you must use
parentheses to distinguish them.
The left operand E1 is evaluated as a void expression, then E2 is evaluated to give the result and type of the comma expression.
By recursion, the expression
E1, E2, ..., En
results in the left-to-right evaluation of each Ei, with the value and type of En giving the result of the whole expression.
To avoid ambiguity with the commas in function argument and initializer lists, use parentheses. For example,
func(i, (j = 1, j + 4), k);
calls func with three arguments (i, 5, k), not four.
In the expression E1 ? E2 : E3, E1 evaluates first. If its value is true, then E2 evaluates and E3 is ignored. If E1 evaluates to
false, then E3 evaluates and E2 is ignored.
3 The result of E1 ? E2 : E3 will be the value of either E2 or E3 depending upon which evaluates.
E1 must be a scalar expression. E2 and E3 must obey one of the following rules:
• 1. Both of arithmetic type. E2 and E3 are subject to the usual arithmetic conversions, which determines the resulting type.
• 2. Both of compatible struct or union types. The resulting type is the structure or union type of E2 and E3.
• 3. Both of void type. The resulting type is void.
• 4. Both of type pointer to qualified or unqualified versions of compatible types. The resulting type is a pointer to a type
592
3.1 C++ Reference RAD Studio C++ Language Guide
qualified with all the type qualifiers of the types pointed to by both operands.
• 5. One operand is a pointer, and the other is a null pointer constant. The resulting type is a pointer to a type qualified with all
the type qualifiers of the types pointed to by both operands.
• 6. One operand is a pointer to an object or incomplete type, and the other is a pointer to a qualified or unqualified version of
void. The resulting type is that of the non-pointer-to-void operand.
• * (multiplication)
• / (division)
• % (modulus or remainder)
The usual arithmetic conversions are made on the operands.
(op1 * op2) Product of the two operands
(op1 / op2) Quotient of (op1 divided by op2)
(op1 % op2) Remainder of (op1 divided by op2)
For / and %, op2 must be nonzero op2 = 0 results in an error. (You can't divide by zero.)
When op1 and op2 are integers and the quotient is not an integer:
• 1. If op1 and op2 have the same sign, op1 / op2 is the largest integer less than the true quotient, and op1 % op2 has the sign
of op1.
• 2. If op1 and op2 have opposite signs, op1 / op2 is the smallest integer greater than the true quotient, and op1 % op2 has the
sign of op1.
Note: Rounding is always toward zero.
* is context sensitive and can be used as the pointer reference operator.
3.1.3.4.2 Declarations
This section briefly reviews concepts related to declarations: objects, storage classes, types, scope, visibility, duration, and
linkage. A general knowledge of these is essential before tackling the full declaration syntax. Scope, visibility, duration, and
linkage determine those portions of a program that can make legal references to an identifier in order to access its object.
Topics
Name Description
Duration ( see page 594) Duration, closely related to storage class, defines the period during which the 3
declared identifiers have real, physical objects allocated in memory. We also
distinguish between compile-time and run-time objects. Variables, for instance,
unlike typedefs and types, have real memory allocated during run time. There
are three kinds of duration: static, local, and dynamic.
Static
Memory is allocated to objects with static duration as soon as execution is
underway; this storage allocation lasts until the program terminates. All functions,
wherever defined, are objects with static duration. All variables with file scope
have static duration. Other variables can be given static... more ( see page 594)
593
C++ Language Guide RAD Studio 3.1 C++ Reference
Linkage ( see page 595) An executable program is usually created by compiling several independent
translation units, then linking the resulting object files with preexisting libraries. A
problem arises when the same identifier is declared in different scopes (for
example, in different files), or declared more than once in the same scope.
Linkage is the process that allows each instance of an identifier to be associated
correctly with one particular object or function. All identifiers have one of three
linkage attributes, closely related to their scope: external linkage, internal linkage,
or no linkage. These attributes are determined by the placement and format of
your declarations,... more ( see page 595)
Objects ( see page 596) An object is a specific region of memory that can hold a fixed or variable value (or
set of values). (This use of the word object is different from the more general
term used in object-oriented languages.) Each value has an associated name
and type (also known as a data type). The name is used to access the object.
This name can be a simple identifier, or it can be a complex expression that
uniquely references the object. The type is used
3.1.3.4.2.1 Duration
Duration, closely related to storage class, defines the period during which the declared identifiers have real, physical objects
3 allocated in memory. We also distinguish between compile-time and run-time objects. Variables, for instance, unlike typedefs
and types, have real memory allocated during run time. There are three kinds of duration: static, local, and dynamic.
Static
Memory is allocated to objects with static duration as soon as execution is underway; this storage allocation lasts until the
program terminates. All functions, wherever defined, are objects with static duration. All variables with file scope have static
duration. Other variables can be given static duration by using the explicit static or extern storage class specifiers.
Static duration objects are initialized to zero (or null) in the absence of any explicit initializer or, in C++, a class constructor.
594
3.1 C++ Reference RAD Studio C++ Language Guide
Don't confuse static duration with file or global scope. An object can have static duration and local scope.
Local
Local duration objects, also known as automatic objects, lead a more precarious existence. They are created on the stack (or in
a register) when the enclosing block or function is entered. They are deallocated when the program exits that block or function.
Local duration objects must be explicitly initialized; otherwise, their contents are unpredictable. Local duration objects must
always have local or function scope. The storage class specifier auto can be used when declaring local duration variables, but is
usually redundant, because auto is the default for variables declared within a block. An object with local duration also has local
scope, because it does not exist outside of its enclosing block. The converse is not true: a local scope object can have static
duration.
When declaring variables (for example, int, char, float), the storage class specifier register also implies auto; but a request (or
hint) is passed to the compiler that the object be allocated a register if possible. The compiler can be set to allocate a register to
a local integral or pointer variable, if one is free. If no register is free, the variable is allocated as an auto, local object with no
warning or error.
Note: The compiler can ignore requests for register allocation. Register allocation is based on the compiler's analysis of how a
variable is used.
Dynamic
Dynamic duration objects are created and destroyed by specific function calls during a program. They are allocated storage from
a special memory reserve known as the heap, using either standard library functions such as malloc, or by using the C++
operator new. The corresponding deallocations are made using free or delete.
See Also
Declarations ( see page 593)
3.1.3.4.2.2 Linkage
An executable program is usually created by compiling several independent translation units, then linking the resulting object
files with preexisting libraries. A problem arises when the same identifier is declared in different scopes (for example, in different
files), or declared more than once in the same scope. Linkage is the process that allows each instance of an identifier to be
associated correctly with one particular object or function. All identifiers have one of three linkage attributes, closely related to
their scope: external linkage, internal linkage, or no linkage. These attributes are determined by the placement and format of
your declarations, together with the explicit (or implicit by default) use of the storage class specifier static or extern.
3
Each instance of a particular identifier with external linkage represents the same object or function throughout the entire set of
files and libraries making up the program. Each instance of a particular identifier with internal linkage represents the same object
or function within one file only. Identifiers with no linkage represent unique entities.
Any object or file identifier having file scope will have internal linkage if its declaration contains the storage class specifier static.
For C++, if the same identifier appears with both internal and external linkage within the same file, the identifier will have external
595
C++ Language Guide RAD Studio 3.1 C++ Reference
If the declaration of an object or function identifier contains the storage class specifier extern, the identifier has the same linkage
as any visible declaration of the identifier with file scope. If there is no such visible declaration, the identifier has external linkage.
If a function is declared without a storage class specifier, its linkage is determined as if the storage class specifier extern had
been used.
If an object identifier with file scope is declared without a storage class specifier, the identifier has external linkage.
• Any identifier declared to be other than an object or a function (for example, a typedef identifier)
• Function parameters
• Block scope identifiers for objects declared without the storage class specifier extern
Name mangling
When a C++ module is compiled, the compiler generates function names that include an encoding of the function's argument
types. This is known as name mangling. It makes overloaded functions possible, and helps the linker catch errors in calls to
functions in other modules. However, there are times when you won't want name mangling. When compiling a C++ module to
be linked with a module that does not have mangled names, the C++ compiler has to be told not to mangle the names of the
functions from the other module. This situation typically arises when linking with libraries or .obj files compiled with a C
compiler
To tell the C++ compiler not to mangle the name of a function, declare the function as extern "C", like this:
extern "C" void Cfunc( int );
This declaration tells the compiler not to mangle references to the function Cfunc.
You can also apply the extern "C" declaration to a block of names:
extern "C" {
void Cfunc1( int );
void Cfunc2( int );
void Cfunc3( int );
};
As with the declaration for a single function, this declaration tells the compiler that references to the functions Cfunc1, Cfunc2,
and Cfunc3 should not be mangled. You can also use this form of block declaration when the block of function names is
contained in a header file:
extern "C" {
#include "locallib.h"
};
Note: extern “C” cannot be used with class identifiers.
See Also
Declarations ( see page 593)
3.1.3.4.2.3 Objects
An object is a specific region of memory that can hold a fixed or variable value (or set of values). (This use of the word object is
596
3.1 C++ Reference RAD Studio C++ Language Guide
different from the more general term used in object-oriented languages.) Each value has an associated name and type (also
known as a data type). The name is used to access the object. This name can be a simple identifier, or it can be a complex
expression that uniquely references the object. The type is used
3.1.3.4.2.4 Scope
3
The scope of an identifier is that part of the program in which the identifier can be used to access its object. There are six
categories of scope: block (or local), function, function prototype, file, class (C++ only), condition (C++ only), and namespace
(C++ only). These depend on how and where identifiers are declared.
• Block. The scope of an identifier with block (or local) scope starts at the declaration point and ends at the end of the block
containing the declaration (such a block is known as the enclosing block). Parameter declarations with a function definition
also have block scope, limited to the scope of the block that defines the function.
• Function. The only identifiers having function scope are statement labels. Label names can be used with goto statements
597
C++ Language Guide RAD Studio 3.1 C++ Reference
anywhere in the function in which the label is declared. Labels are declared implicitly by writing label_name: followed by a
statement. Label names must be unique within a function.
• Function prototype. Identifiers declared within the list of parameter declarations in a function prototype (not part of a function
definition) have function prototype scope. This scope ends at the end of the function prototype.
• File. File scope identifiers, also known as globals, are declared outside of all blocks and classes; their scope is from the point
of declaration to the end of the source file.
• Class (C++). A class is a named collection of members, including data structures and functions that act on them. Class scope
applies to the names of the members of a particular class. Classes and their objects have many special access and scoping
rules; see Classes.
• Condition (C++). Declarations in conditions are supported. Variables can be declared within the expression of if, while, and
switch statements. The scope of the variable is that of the statement. In the case of an if statement, the variable is also in
scope for the else block.
• namespace (C++). A namespace is a logical grouping of program entities (e.g. identifiers, classes, and functions).
Namespaces are open, that is, they can span multiple compilation units. You can think of a namespace as introducing a
named scope, similar in many ways to a class in C++. See the help for the namespace keyword for more inforrmation on how
to declare and use namespaces.
Name spaces
Name space is the scope within which an identifier must be unique. Note that a C++ namespace extends this concept by
allowing you to give the scope a name. In addition to the named-scoping capability of C++, the C programming language uses
four distinct classes of identifiers:
• goto label names. These must be unique within the function in which they are declared.
• Structure, union, and enumeration tags. These must be unique within the block in which they are defined. Tags declared
outside of any function must be unique.
• Structure and union member names. These must be unique within the structure or union in which they are defined. There is
no restriction on the type or offset of members with the same member name in different structures.
• Variables, typedefs, functions, and enumeration members. These must be unique within the scope in which they are defined.
Externally declared identifiers must be unique among externally declared variables.
See Also
Declarations ( see page 593)
The type determines how much memory is allocated to an object and how the program will interpret the bit patterns found in the
object's storage allocation. A given data type can be viewed as the set of values (often implementation-dependent) that
identifiers of that type can assume, together with the set of operations allowed on those values. The compile-time operator,
sizeof, lets you determine the size in bytes of any standard or user-defined type. See sizeof for more on this operator.
598
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Declarations ( see page 593)
See Also
Declarations ( see page 593)
3.1.3.4.2.7 Visibility
The visibility of an identifier is that region of the program source code from which legal access can be made to the identifier's
associated object.
Scope and visibility usually coincide, though there are circumstances under which an object becomes temporarily hidden by the
appearance of a duplicate identifier: the object still exists but the original identifier cannot be used to access it until the scope of
the duplicate identifier is ended. 3
Note: Visibility cannot exceed scope, but scope can exceed visibility.
Again, special rules apply to hidden class names and class member names: C++ operators allow hidden identifiers to be
accessed under certain conditions
See Also
Declarations ( see page 593)
599
C++ Language Guide RAD Studio 3.1 C++ Reference
Declarations can be defining declarations (also known as definitions) or referencing declarations (sometimes known as
nondefining declarations). A defining declaration, as the name implies, performs both the duties of declaring and defining; the
nondefining declarations require a definition to be added somewhere in the program. A referencing declaration introduces one or
more identifier names into a program. A definition actually allocates memory to an object and associates an identifier with that
object.
Topics
Name Description
Tentative Definitions ( see page 602) The ANSI C standard supports the concept of the tentative definition. Any
external data declaration that has no storage class specifier and no initializer is
considered a tentative definition. If the identifier declared appears in a later
definition, then the tentative definition is treated as if the extern storage class
specifier were present. In other words, the tentative definition becomes a simple
referencing declaration.
If the end of the translation unit is reached and no definition has appeared with
an initializer for the identifier, then the tentative definition becomes a full
definition, and the object defined has uninitialized (zero-filled) space... more (
see page 602)
Possible Declarations ( see page 603) The range of objects that can be declared includes
• Variables
• Functions
• Classes and class members (C++)
• Types
• Structure, union, and enumeration tags
• Structure members
• Union members
• Arrays of other types
• Enumeration constants
• Statement labels
• Preprocessor macros
3 The full syntax for declarations is shown in Tables 2.1
through 2.3. The recursive nature of the declarator syntax
allows complex declarators. You'll probably want to use
typedefs to improve legibility.
In CodeGear C++ declaration syntax., note the restrictions
on the number and order of modifiers and qualifiers. Also,
the modifiers listed are the only addition to the declarator
syntax that are... more ( see page 603)
600
3.1 C++ Reference RAD Studio C++ Language Guide
External Declarations and Definitions ( see page 606) The storage class specifiers auto and register cannot appear in an external
declaration. For each identifier in a translation unit declared with internal linkage,
no more than one external definition can be given.
An external definition is an external declaration that also defines an object or
function; that is, it also allocates storage. If an identifier declared with external
linkage is used in an expression (other than as part of the operand of sizeof),
then exactly one external definition of that identifier must exist in the entire
program.
The C++ compiler allows later declarations of external names, such as arrays,...
more ( see page 606)
Type Specifiers ( see page 607) The type determines how much memory is allocated to an object and how the
program interprets the bit patterns found in the object's storage allocation. A data
type is the set of values (often implementation-dependent) identifiers can
assume, together with the set of operations allowed on those values.
The type specifier with one or more optional modifiers is used to specify the type
of the declared identifier:
Type Categories ( see page 608) Provides information on C++ type categories.
The four basic type categories (and their subcategories) are as follows:
The Fundamental Types ( see page 609) The fundamental type specifiers are built from the following keywords:
Initialization ( see page 611) Initializers set the initial value that is stored in an object (variables, arrays,
structures, and so on). If you don't initialize an object, and it has static duration, it
will be initialized by default in the following manner:
601
C++ Language Guide RAD Studio 3.1 C++ Reference
Mixed-Language Calling Conventions ( see page 615) Provides information on C++ mixed-language calling conventions.
This section describes C++ mixed-language calling conventions.
You can call routines written in other languages, and vice versa. When you mix
languages, you have to deal with two important issues: identifiers and parameter
passing.
By default, the compiler saves all global identifiers in their original case (lower,
upper, or mixed) with an underscore "_" prepended to the front of the identifier.
To remove the default, you can use the -u command-line option.
Note: The section Linkage ( see page 595) tells how to use extern
, which allows C names to be referenced from a C++ program.... more ( see
page 615)
Multithread Variables ( see page 616) The following topic describes C++ multithread variables.
Function Modifiers ( see page 616) This section presents descriptions of the function modifiers available with the
CodeGear C++ compiler.
You can use the __declspec(dllexport), and __declspec(dllimport)and
__saveregs modifiers to modify functions.
In 32-bit programs the keyword can be applied to class, function, and variable
declarations
The __declspec(dllexport) modifier makes the function exportable from
Windows. The __declspec(dllimport) modifier makes a function available to a
Windows program. The keywords are used in an executable (if you don't use
smart callbacks) or in a DLL.
Functions declared with the __fastcall modifier have different names than their
non-__fastcall counterparts. The compiler prefixes the __fastcall function name
with... more ( see page 616)
If the end of the translation unit is reached and no definition has appeared with an initializer for the identifier, then the tentative
definition becomes a full definition, and the object defined has uninitialized (zero-filled) space reserved for it. For example,
int x;
int x; /*legal, one copy of x is reserved */
int y;
int y = 4; /* legal, y is initialized to 4 */
int z = 5;
int z = 6; /* not legal, both are initialized definitions */
Unlike ANSI C, C++ doesn't have the concept of a tentative declaration; an external data declaration without a storage class
specifier is always a definition.
See Also
Declaration Syntax
602
3.1 C++ Reference RAD Studio C++ Language Guide
• Variables
• Functions
• Classes and class members (C++)
• Types
• Structure, union, and enumeration tags
• Structure members
• Union members
• Arrays of other types
• Enumeration constants
• Statement labels
• Preprocessor macros
The full syntax for declarations is shown in Tables 2.1 through 2.3. The recursive nature of the declarator syntax allows complex
declarators. You'll probably want to use typedefs to improve legibility.
In CodeGear C++ declaration syntax., note the restrictions on the number and order of modifiers and qualifiers. Also, the
modifiers listed are the only addition to the declarator syntax that are not ANSI C or C++. These modifiers are each discussed
in greater detail in Variable Modifiers and Function Modifiers.
CodeGear C++ declaration syntax
declaration: elaborated-type-specifier:
<decl-specifiers> class-key identifier
<declarator-list>;
asm-declaration class-key class-name
function-declaration enum enum-name
linkage-specification class-key: (C++ specific)
decl-specifier: class
storage-class-specifier struct
type-specifier union
function-specifier enum-specifier:
friend (C++ specific) enum <identifier> { <enum-list> }
typedef enum-list:
decl-specifiers: enumerator
<decl-specifiers> enumerator-list , enumerator
decl-specifier 3
storage-class-specifier: enumerator:
auto identifier
register identifier = constant-expression
static constant-expression:
extern conditional-expression
603
C++ Language Guide RAD Studio 3.1 C++ Reference
604
3.1 C++ Reference RAD Studio C++ Language Guide
• <cv-qualifier-list> initializer:
See Also
Declaration Syntax
605
C++ Language Guide RAD Studio 3.1 C++ Reference
An external definition is an external declaration that also defines an object or function; that is, it also allocates storage. If an
identifier declared with external linkage is used in an expression (other than as part of the operand of sizeof), then exactly one
external definition of that identifier must exist in the entire program.
The C++ compiler allows later declarations of external names, such as arrays, structures, and unions, to add information to
earlier declarations. Here's an example:
int a[]; // no size
struct mystruct; // tag only, no member declarators
.
.
.
int a[3] = {1, 2, 3}; // supply size and initialize
struct mystruct {
int i, j;
}; // add member declarators
CodeGear C++ class declaration syntax (C++ only) covers class declaration syntax. In the section on classes (beginning with
Classes), you can find examples of how to declare a class. Referencing covers C++ reference types (closely related to pointer
types) in detail. Finally, see Using Templates for a discussion of template-type classes.
class-specifier: base-specifier:
class-head: base-list:
member-list: base-specifier:
qualified-name ; protected
3 member-declarator-list: public
member-declarator conversion-function-name:
member-declarator: conversion-type-name:
606
3.1 C++ Reference RAD Studio C++ Language Guide
pure-specifier: : member-initializer-list
=0
member-initializer , member-initializer-list + - * / % ^
[ ] .*
See Also
Declaration Syntax ( see page 600)
The type specifier with one or more optional modifiers is used to specify the type of the declared identifier:
int i; // declare i as an integer
unsigned char ch1, ch2; // declare two unsigned chars
By long-standing tradition, if the type specifier is omitted, type signed int (or equivalently, int) is the assumed default. However,
in C++, a missing type specifier can lead to syntactic ambiguity, so C++ practice requires you to explicitly declare all int type
specifiers. 3
The type specifier keywords by the CodeGear C++ compiler are:
607
C++ Language Guide RAD Studio 3.1 C++ Reference
Use the sizeof operators to find the size in bytes of any predefined or user-defined type.
The four basic type categories (and their subcategories) are as follows:
Aggregate Array
struct
union
class (C++ only)
Function
Scalar
Arithmetic
Enumeration
Pointer
Reference (C++ only)
void
Types can also be viewed in another way: they can be fundamental or derived types. The fundamental types are void, char, int,
float, and double, together with short, long, signed, and unsigned variants of some of these. The derived types include
pointers and references to other types, arrays of other types, function types, class types, structures, and unions.
A class object, for example, can hold a number of objects of different types together with functions for manipulating these
objects, plus a mechanism to control access and inheritance from other classes.
Given any nonvoid type type (with some provisos), you can declare derived types as follows:
Declaring Types
Declaration Description
type t; An object of type type
type array[10]; Ten types: array[0] - array[9]
type *ptr; ptr is a pointer to type
type &ref = t; ref is a reference to type (C++)
type func(void); func returns value of type type
void func1(type t); func1 takes a type type parameter
struct st {type t1;type t2}; structure st holds two types
Note: type& var, type &var, and type & var are all equivalent.
See Also
Declaration Syntax
3
Tentative Definitions ( see page 602)
608
3.1 C++ Reference RAD Studio C++ Language Guide
From these keywords you can build the integral and floating-point types, which are together known as the arithmetic types. The
modifiers long, short, signed, and unsigned can be applied to the integral types. The include file limits.h contains definitions of
the value ranges for all the fundamental types.
Integral types
char, short, int, and long, together with their unsigned variants, are all considered integral data types. Integral types shows the
integral type specifiers, with synonyms listed on the same line.
Integral types
Note: These synonyms are not valid in C++. See The three char types.
signed or unsigned can only be used with char, short, int, or long. The keywords signed and unsigned, when used on their 3
own, mean signed int and unsigned int, respectively.
In the absence of unsigned, signed is assumed for integral types. An exception arises with char. You can set the default for
char to be signed or unsigned. (The default, if you don't set it yourself, is signed.) If the default is set to unsigned, then the
declaration char ch declares ch as unsigned. You would need to use signed char ch to override the default. Similarly, with a
signed default for char, you would need an explicit unsigned char ch to declare an unsigned char.
Only long or short can be used with int. The keywords long and short used on their own mean long int and short int.
609
C++ Language Guide RAD Studio 3.1 C++ Reference
ANSI C does not dictate the sizes or internal representations of these types, except to indicate that short, int, and long form a
nondecreasing sequence with "short <= int <= long." All three types can legally be the same. This is important if you want to
write portable code aimed at other platforms.
The compiler regards the types int and long as equivalent, both being 32 bits. The signed varieties are all stored in two's
complement format using the most significant bit (MSB) as a sign bit: 0 for positive, 1 for negative (which explains the ranges
shown in 32-bit data types, sizes, and ranges). In the unsigned versions, all bits are used to give a range of 0 - (2n - 1), where n
is 8, 16, or 32.
Floating-point types
The representations and sets of values for the floating-point types are implementation dependent; that is, each implementation of
C is free to define them. The compiler uses the IEEE floating-point formats.See the topic on ANSI implementation-specific.
float and double are 32- and 64-bit floating-point data types, respectively. long can be used with double to declare an 80-bit
precision floating-point identifier: long double test_case, for example.
The table of 32-bit data types, sizes, and ranges indicates the storage allocations for the floating-point types
When you use an arithmetic expression, such as a + b, where a and b are different arithmetic types, The compiler performs
certain internal conversions before the expression is evaluated. These standard conversions include promotions of "lower" types
to "higher" types in the interests of accuracy and consistency.
Here are the steps the compiler uses to convert the operands in an arithmetic expression:
• 1. Any small integral types are converted as shown in Methods used in standard arithmetic conversions. After this, any two
values associated with an operator are either int (including the long and unsigned modifiers), or they are of type double,
float, or long double.
• 2. If either operand is of type long double, the other operand is converted to long double.
• 3. Otherwise, if either operand is of type double, the other operand is converted to double.
• 4. Otherwise, if either operand is of type float, the other operand is converted to float.
• 5. Otherwise, if either operand is of type unsigned long, the other operand is converted to unsigned long.
• 6. Otherwise, if either operand is of type long, then the other operand is converted to long.
• 7. Otherwise, if either operand is of type unsigned, then the other operand is converted to unsigned.
• 8. Otherwise, both operands are of type int.
The result of the expression is the same type as that of the two operands.
Methods used in standard arithmetic conversions
Note: The conversions discussed in this section are specific to the Borland C++ compiler.
610
3.1 C++ Reference RAD Studio C++ Language Guide
Assigning a signed character object (such as a variable) to an integral object results in automatic sign extension. Objects of type
signed char always use sign extension; objects of type unsigned char always set the high byte to zero when converted to int.
Converting a longer integral type to a shorter type truncates the higher order bits and leaves low-order bits unchanged.
Converting a shorter integral type to a longer type either sign-extends or zero-fills the extra bits of the new value, depending on
whether the shorter type is signed or unsigned, respectively.
See Also
Declaration Syntax
3.1.3.4.3.7 Initialization
Initializers set the initial value that is stored in an object (variables, arrays, structures, and so on). If you don't initialize an object,
and it has static duration, it will be initialized by default in the following manner:
The number of initializers in the initializer list cannot be larger than the number of objects to be initialized.
For C (not required for C++), all expressions must be constants if they appear in one of these places:
3
In an initializer for an object that has static duration.
In an initializer list for an array, structure, or union (expressions using sizeof are also allowed).
• If a declaration for an identifier has block scope, and the identifier has external or internal linkage, the declaration cannot have
an initializer for the identifier.
• If a brace-enclosed list has fewer initializers than members of a structure, the remainder of the structure is initialized implicitly
in the same way as objects with static storage duration.
611
C++ Language Guide RAD Studio 3.1 C++ Reference
Scalar types are initialized with a single expression, which can optionally be enclosed in braces. The initial value of the object is
that of the expression; the same constraints for type and conversions apply as for simple assignments.
For unions, a brace-enclosed initializer initializes the member that first appears in the union's declaration list. For structures or
unions with automatic storage duration, the initializer must be one of the following:
• An initializer list (as described in Arrays, structures, and unions).
• A single expression with compatible union or structure type. In this case, the initial value of the object is that of the expression.
Arrays, structures, and unions
You initialize arrays and structures (at declaration time, if you like) with a brace-enclosed list of initializers for the members or
elements of the object in question. The initializers are given in increasing array subscript or member order. You initialize
unions with a brace-enclosed initializer for the first member of the union. For example, you could declare an array days, which
counts how many times each day of the week appears in a month (assuming that each day will appear at least once), as
follows:
int days[7] = { 1, 1, 1, 1, 1, 1, 1 }
The following rules initialize character arrays and wide character arrays:
• You can initialize arrays of character type with a literal string, optionally enclosed in braces. Each character in the string,
including the null terminator, initializes successive elements in the array. For example, you could declare
*
char name[] = { "Unknown" };
which sets up an eight-element array, whose elements are 'U' (for name[0]), 'n' (for name[1]), and so on (and including a null
terminator).
• You can initialize a wide character array (one that is compatible with wchar_t) by using a wide string literal, optionally
enclosed in braces. As with character arrays, the codes of the wide string literal initialize successive elements of the array.
* Here is an example of a structure initialization:
struct mystruct {
int i;
char str[21];
double d;
} s = { 20, "Borland", 3.141 };
Complex members of a structure, such as arrays or structures, can be initialized with suitable expressions inside nested braces.
See Also
Declaration Syntax
612
3.1 C++ Reference RAD Studio C++ Language Guide
terminated by a semicolon.
These are all defining declarations; storage is allocated and any optional initializers are applied.
The initializer for an automatic object can be any legal expression that evaluates to an assignment-compatible value for the type
of the variable involved. Initializers for static objects must be constants or constant expressions.
In C++, an initializer for a static object can be any expression involving constants and previously declared variables and
functions.
The format of the declarator indicates how the declared name is to be interpreted when used in an expression. If type is any
type, and storage class specifier is any storage class specifier, and if D1 and D2 are any two declarators, then the declaration:
storage-class-specifier type D1, D2;
indicates that each occurrence of D1 or D2 in an expression will be treated as an object of type type and storage class storage
class specifier. The type of the name embedded in the declarator will be some phrase containing type, such as "type," "pointer
to type," "array of type," "function returning type," or "pointer to function returning type," and so on.
For example, in Declaration syntax examples each of the declarators could be used as rvalues (or possibly lvalues in some
cases) in expressions where a single int object would be appropriate. The types of the embedded identifiers are derived from
their declarators as follows:
Note the need for parentheses in (*name)[ ] and (*name)( ); this is because the precedence of both the array declarator [ ] and
the function declarator ( ) is higher than the pointer declarator *. The parentheses in *(name[ ]) are optional.
Note: See CodeGear C++ declaration syntax for the declarator syntax. The definition covers both identifier and function
613
C++ Language Guide RAD Studio 3.1 C++ Reference
declarators.
See Also
Declaration Syntax
Storage classes specifiers are also called type specifiers. They dictate the location (data segment, register, heap, or stack) of an
object and its duration or lifetime (the entire running time of the program, or during execution of some blocks of code).
Storage class can be established by the declaration syntax, by its placement in the source code, or by both of these factors.
The keyword mutable does not affect the lifetime of the class member to which it is applied.
Calling Conventions
614
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Declaration Syntax ( see page 600)
You can call routines written in other languages, and vice versa. When you mix languages, you have to deal with two important
issues: identifiers and parameter passing.
By default, the compiler saves all global identifiers in their original case (lower, upper, or mixed) with an underscore "_"
prepended to the front of the identifier. To remove the default, you can use the -u command-line option.
Note: The section Linkage ( see page 595) tells how to use extern
3
, which allows C names to be referenced from a C++ program.
Topics
Cdecl ( see page 536)
615
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
__thread ( see page 529)
You can use the __declspec(dllexport), and __declspec(dllimport)and __saveregs modifiers to modify functions.
In 32-bit programs the keyword can be applied to class, function, and variable declarations
The __declspec(dllexport) modifier makes the function exportable from Windows. The __declspec(dllimport) modifier makes
a function available to a Windows program. The keywords are used in an executable (if you don't use smart callbacks) or in a
DLL.
Functions declared with the __fastcall modifier have different names than their non-__fastcall counterparts. The compiler
prefixes the __fastcall function name with an @. This prefix applies to both unmangled C function names and to mangled C++
function names.
1. C++ extends const and volatile to include classes and member functions.
2. This is the default.
616
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Declaration Syntax
3.1.3.4.4 Enumerations
This section contains Enumeration topics.
Topics
Name Description
Enumerations ( see page 617) An enumeration data type is used to provide mnemonic identifiers for a set of
integer values. For example, the following declaration:
Assignment To Enum Types ( see page 618) The rules for expressions involving enum types have been made stricter. The
compiler enforces these rules with error messages if the compiler switch -A is
turned on (which means strict ANSI C++).
Assigning an integer to a variable of enum type results in an error:
3.1.3.4.4.1 Enumerations
An enumeration data type is used to provide mnemonic identifiers for a set of integer values. For example, the following
declaration:
enum days { sun, mon, tues, wed, thur, fri, sat } anyday;
establishes a unique integral type, enum days, a variable anyday of this type, and a set of enumerators (sun, mon,...) with
constant integer values.
The -b compiler switch controls the “Treat Enums As Ints” option. When this switch is used, the compiler allocates a whole word
(a four-byte int) for enumeration types (variables of type enum). The default is ON (meaning enums are always ints) if the
range of values permits, but the value is always promoted to an int when used in expressions. The identifiers used in an
enumerator list are implicitly of type signed char, unsigned char, or int, depending on the values of the enumerators. If all
values can be represented in a signed or unsigned char, then that is the type of each enumerator.
In C, a variable of an enumerated type can be assigned any value of type int--no type checking beyond that is enforced. In C++,
a variable of an enumerated type can be assigned only one of its enumerators. That is:
3
anyday = mon; // OK
anyday = 1; // illegal, even though mon == 1
The identifier days is the optional enumeration tag that can be used in subsequent declarations of enumeration variables of type
enum days:
enum days payday, holiday; // declare two variables
In C++, you can omit the enum keyword if days is not the name of anything else in the same scope.
617
C++ Language Guide RAD Studio 3.1 C++ Reference
As with struct and union declarations, you can omit the tag if no further variables of this enum type are required:
enum { sun, mon, tues, wed, thur, fri, sat } anyday;
/* anonymous enum type */
The enumerators listed inside the braces are also known as enumeration constants. Each is assigned a fixed integral value. In
the absence of explicit initializers, the first enumerator (sun) is set to zero, and each succeeding enumerator is set to one more
than its predecessor (mon = 1, tues = 2, and so on). See Enumeration constants for more on enumeration constants.
With explicit integral initializers, you can set one or more enumerators to specific values. Any subsequent names without
initializers will then increase by one. For example, in the following declaration:
/* Initializer expression can include previously declared enumerators */
enum coins { penny = 1, tuppence, nickel = penny + 4, dime = 10,
quarter = nickel * nickel } smallchange;
tuppence would acquire the value 2, nickel the value 5, and quarter the value 25.
The initializer can be any expression yielding a positive or negative integer value (after possible integer promotions). These
values are usually unique, but duplicates are legal.
In C++ it is possible to overload most operators for an enumeration. However, because the =, [ ], ( ), and -> operators must be
overloaded as member functions, it is not possible to overload them for an enum. See the example on how to overload the
postfix and prefix increment operators.
618
3.1 C++ Reference RAD Studio C++ Language Guide
return c;
}
The same applies when passing an integer as a parameter to a function. Notice that the result type of the expression flag1|flag2
is int:
enum e
{
flag1 = 0x01,
flag2 = 0x02
};
void p(e);
void f()
{
p(flag1|flag2);
}
To make the example compile, the expression flag1|flag2 must be cast to the enum type: e (flag1|flag2).
3.1.3.4.5 Expressions
This section contains C++ Expression topics.
Topics
Name Description
Expressions (C++) ( see page 620) An expression is a sequence of operators, operands, and punctuators that
specifies a computation. The formal syntax, listed in CodeGear C++ expressions,
indicates that expressions are defined recursively: subexpressions can be nested
without formal limit. (However, the compiler will report an out-of-memory error if it
can't compile an expression that is too complex.)
Note: CodeGear C++ expressions show how identifiers and operators are
combined to form grammatically legal "phrases."
Expressions are evaluated according to certain conversion, grouping,
associativity, and precedence rules that depend on the operators used, the
presence of parentheses, and the data types of the operands. The standard...
more ( see page 620)
Precedence Of Operators ( see page 622) There are 16 precedence categories, some of which contain only one operator.
Operators in the same category have equal precedence with each other.
Where duplicates of operators appear in the table, the first occurrence is unary,
the second binary. Each category has an associativity rule: left to right, or right to
left. In the absence of parentheses, these rules resolve the grouping of
expressions with operators of equal precedence.
The precedence of each operator in the following table is indicated by its order in
the table. The first category (on the first line) has the highest precedence.
Operators on the... more ( see page 622)
Expressions And C++ ( see page 623) C++ allows the overloading of certain standard C operators, as explained in
Overloading Operator Functions. An overloaded operator is defined to behave in
a special way when applied to expressions of class type. For instance, the
equality operator == might be defined in class complex to test the equality of two
complex numbers without changing its normal usage with non-class data types.
An overloaded operator is implemented as a function; this function determines
the operand type, lvalue, and evaluation order to be applied when the overloaded
operator is used. However, overloading cannot change the precedence of an
operator. Similarly, C++... more ( see page 623)
Evaluation Order ( see page 624) The order in which the compiler evaluates the operands of an expression is not
specified, except where an operator specifically states otherwise. The compiler
will try to rearrange the expression in order to improve the quality of the 3
generated code. Care is therefore needed with expressions in which a value is
modified more than once. In general, avoid writing expressions that both modify
and use the value of the same object. For example, consider the expression
Errors And Overflows ( see page 624) Associativity and precedence of CodeGear C++ operators. summarizes the
precedence and associativity of the operators. During the evaluation of an
expression, the compiler can encounter many problematic situations, such as
division by zero or out-of-range floating-point values. Integer overflow is ignored
(C uses modulo 2n arithmetic on n-bit registers), but errors detected by math
library functions can be handled by standard or user-defined routines.See
_matherr and signal.
619
C++ Language Guide RAD Studio 3.1 C++ Reference
Note: CodeGear C++ expressions show how identifiers and operators are combined to form grammatically legal "phrases."
Expressions are evaluated according to certain conversion, grouping, associativity, and precedence rules that depend on the
operators used, the presence of parentheses, and the data types of the operands. The standard conversions are detailed in
Methods used in standard arithmetic conversions. The way operands and subexpressions are grouped does not necessarily
specify the actual order in which they are evaluated by the compiler (see Evaluation order).
Expressions can produce an lvalue, an rvalue, or no value. Expressions might cause side effects whether they produce a value
or not
The precedence and associativity of the operators are summarized in Associativity and precedence of CodeGear C++ operators.
The grammar in CodeGear C++ expressions, completely defines the precedence and associativity of the operators.
teral:
integer-constant
character-constant
floating-constant
string-literal
name:
identifier
operator-function-name (C++ specific)
conversion-function-name (C++ specific)
postfix-expression . name
postfix-expression -> name
3 postfix-expression ++
postfix-expression --
const_cast < type-id > ( expression ) (C++ specific)
dynamic_cast < type-id > ( expression ) (C++ specific)
reinterpret_cast < type-id > ( expression ) (C++ specific)
static_cast < type-id > ( expression ) (C++ specific)
typeid ( expression ) (C++ specific)
typeid ( type-name ) (C++ specific)
expression-list:
620
3.1 C++ Reference RAD Studio C++ Language Guide
assignment-expression
expression-list , assignment-expression
unary-expression:
postfix-expression
++ unary-expression
- - unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )
allocation-expression (C++ specific)
deallocation-expression (C++ specific)
unary-operator: one of & * + - !
allocation-expression: (C++ specific)
<::> new <placement> new-type-name <initializer>
<::> new <placement> (type-name) <initializer>
placement: (C++ specific)
(expression-list)
new-type-name: (C++ specific)
type-specifiers <new-declarator>
new-declarator: (C++ specific)
ptr-operator <new-declarator>
new-declarator [<expression>]
deallocation-expression: (C++ specific)
<::> delete cast-expression
<::> delete [] cast-expression
cast-expression:
unary-expression
( type-name ) cast-expression
pm-expression:
cast-expression
pm-expression .* cast-expression (C++ specific)
pm-expression ->* cast-expression (C++ specific)
multiplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expressionequality-expression:
relational-expression
equality expression == relational-expression
equality expression != relational-expression
AND-expression:
equality-expression 3
AND-expression & equality-expression
exclusive-OR-expression:
AND-expression
exclusive-OR-expression ^ AND-expression
inclusive-OR-expression:
exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression
logical-AND-expression:
621
C++ Language Guide RAD Studio 3.1 C++ Reference
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression
logical-OR-expression:
logical-AND-expression
logical-OR-expression || logical-AND-expression
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator: one of
= *= /= %= += -=
Where duplicates of operators appear in the table, the first occurrence is unary, the second binary. Each category has an
associativity rule: left to right, or right to left. In the absence of parentheses, these rules resolve the grouping of expressions with
operators of equal precedence.
The precedence of each operator in the following table is indicated by its order in the table. The first category (on the first line)
has the highest precedence. Operators on the same line have equal precedence.
Operators Associativity
() left to right
[]
->
::
.
! right to left
~
+
-
++
--
&
*
3 sizeof
new
delete
.* left to right
->*
622
3.1 C++ Reference RAD Studio C++ Language Guide
* left to right
/
%
+ left to right
-
<< left to right
>>
< left to right
<=
>
>=
== left to right
!=
& left to right
^ left to right
| left to right
&& left to right
|| right to left
?: left to right
= right to left
*=
/=
%=
+=
-=
&=
^=
|=
<<=
>>=
, left to right
623
C++ Language Guide RAD Studio 3.1 C++ Reference
The compiler regroups expressions, rearranging associative and commutative operators regardless of parentheses, in order to
create an efficiently compiled expression; in no case will the rearrangement affect the value of the expression
3.1.3.4.6 Functions
This section contains Function topics.
Topics
Name Description
Declarations And Definitions ( see page 625) Each program must have a single external function named main or WinMain
marking the entry point of the program. Functions are usually declared as
prototypes in standard or user-supplied header files, or within program files.
Functions are external by default and are normally accessible from any file in the
program. You can restrict visibility of functions by using the static storage class
specifier (see Linkage ( see page 595)).
Functions are defined in your source files or made available by linking
precompiled libraries.
3 A given function can be declared several times in a program, provided the
declarations are compatible. Nondefining function declarations using... more (
see page 625)
The main() Function ( see page 626)
624
3.1 C++ Reference RAD Studio C++ Language Guide
Declarations And Prototypes ( see page 633) In the Kernighan and Ritchie style of declaration, a function could be implicitly
declared by its appearance in a function call, or explicitly declared as follows
<type> func()
where type is the optional return type defaulting to int. In C++, this declaration
means <type> func(void). A function can be declared to return any type except
an array or function type. This approach does not allow the compiler to check that
the type or number of arguments used in a function call match the declaration.
This problem was eased by the introduction of function prototypes with... more
( see page 633)
Definitions ( see page 634) The general syntax for external function definitions is as follows:
External function definitions
Extended Types Formatted I/O ( see page 634) The following table shows new format specifiers implemented in C++ Builder for
the printf and scanf family of functions. This implementation allows the input and
output of 64-bit integers and provides greater I/O flexibility for other types.
Formal Parameter Declarations ( see page 635) The formal parameter declaration list follows a syntax similar to that of the
declarators found in normal identifier declarations. Here are a few examples:
Function Calls And Argument Conversions ( see page 635) A function is called with actual arguments placed in the same sequence as their
matching formal parameters. The actual arguments are converted as if by
initialization to the declared types of the formal parameters.
Here is a summary of the rules governing how the compiler deals with language
modifiers and formal parameters in function calls, both with and without
prototypes:
Functions are defined in your source files or made available by linking precompiled libraries.
A given function can be declared several times in a program, provided the declarations are compatible. Nondefining function
declarations using the function prototype format provide the compiler with detailed parameter information, allowing better control
over argument number and type checking, and type conversions.
Note: In C++ you must always use function prototypes. We recommend that you also use them in C.
Excluding C++ function overloading, only one definition of any given function is allowed. The declarations, if any, must also
match this definition. (The essential difference between a definition and a declaration is that the definition has a function body.
See Also
Functions
625
C++ Language Guide RAD Studio 3.1 C++ Reference
626
3.1 C++ Reference RAD Studio C++ Language Guide
Multithread Programs ( see page 629) Win32 programs can create more than one thread of execution. If your program
creates multiple threads, and these threads also use the C++ runtime library, you
must use the CW32MT.LIB or CW32MTI library instead.
The multithread libraries provide the following functions which you use to create
threads:
• _beginthread
• _beginthreadex
• _beginthreadNT
The multithread libraries also provide the following
corresponding functions that terminate threads:
• _endthread
• _endthreadex
• _threadid a global variable that contains the current
identification number of the thread also known as the
thread ID).
The header file stddef.h contains the declaration of
_threadid.
When you compile or link a... more ( see page 629)
Passing File Information To Child Processes ( see page 630) If your program uses the exec or spawn functions to create a new process, the
new process will normally inherit all of the open file handles created by the
original process. Some information, however, about these handles will be lost,
including the access mode used to open the file. For example, if your program
opens a file for read-only access in binary mode, and then spawns a child
process, the child process might corrupt the file by writing to it, or by reading from
it in text mode.
To allow child processes to inherit such information about open files, you... more
( see page 630)
Static Runtime Libraries ( see page 630) Listed below is each of the C++Builder static library names and its use.
Directory of BCB\LIB (LIB files)
The Value main() Returns ( see page 632) The value returned by main is the status code of the program; it must be an int.
If, however, your program uses the routine exit (or _exit) to terminate, the value
returned by main is the argument passed to the call to exit (or to _exit).
For example, if your program contains the call
Using --p (Pascal Calling Conventions) ( see page 632) If you compile your program using Pascal calling conventions, you must
remember to explicitly declare main as a C type. Do this with the __cdecl
keyword, like this:
Wildcard Arguments ( see page 632) Command-line arguments containing wildcard characters can be expanded to all
the matching file names, much the same way DOS expands wildcards when
used with commands like COPY. All you have to do to get wildcard expansion is
to link your program with the WILDARGS.OBJ object file, which is included with
CodeGear C++.
Note: Wildcard arguments are used only in console-mode applications.
Once WILDARGS.OBJ is linked into your program code, you can send wildcard
arguments (such as *.* ) to your main function. The argument will be expanded
(in the argv array) to all files matching the wildcard mask. The maximum... more
( see page 632)
627
C++ Language Guide RAD Studio 3.1 C++ Reference
• argc, an integer, is the number of command-line arguments passed to main, including the name of the executable itself.
• argv is an array of pointers to strings (char *[])argv[0] is the full path name of the program being run.argv[1] points to the first
string typed on the operating system command line after the program name.argv[2] points to the second string typed after the
program name.argv[argc-1] points to the last argument passed to main.argv[argc] contains NULL.
• env is also an array of pointers to strings. Each element of env[] holds a string of the form ENVVAR=value.ENVVAR is the
name of an environment variable, such as PATHvalue is the value to which ENVVAR is set, such as C:\APPS;C:\TOOLS.
If you declare any of these parameters, you must declare them exactly in the order given: argc, argv, env. For example, the
following are all valid declarations of arguments to main:
int main()
int main(int argc) /* legal but very unlikely */
int main(int argc, char * argv[])
it ain(int argc, char * argv[], char * env[])]
The declaration int main(int argc) is legal, but it is very unlikely that you would use argc in your program without also using the
elements of argv.
The argument env is also available through the global variable _environ..
For all platforms, argc and argv are also available via the global variables _argc and _argv.
The following _tmain function is a macro that expands to the appropriate version of the main function depending upon the type
of application:
int _tmain (int argc, _TCHAR *argv[])
See Also
The main() Function ( see page 627)
3
3.1.3.4.6.2.3 Default Runtime Libraries
BCC32.EXE is the command-line compiler. The default libraries used with this compiler are C0W32.OBJ (startup code),
CW32.LIB (static single-threaded runtime library), and IMPORT32.LIB (import library for Win32).
See Also
The main() Function ( see page 627)
628
3.1 C++ Reference RAD Studio C++ Language Guide
Directory: BIN
File Name
CC3260.DLL 32-bit, single-threaded
CC3260MT.DLL 32-bit, multithreaded
See Also
The main() Function ( see page 627)
The multithread libraries provide the following functions which you use to create threads:
• _beginthread
• _beginthreadex
• _beginthreadNT
The multithread libraries also provide the following corresponding functions that terminate threads:
• _endthread
• _endthreadex
• _threadid a global variable that contains the current identification number of the thread also known as the thread ID).
The header file stddef.h contains the declaration of _threadid.
When you compile or link a program that uses multiple threads, you must use the -tWM compiler switch. For example:
BCC32 -tWM THREAD.C
Note: Take special care when using the signal
function in a multithread program. The SIGINT, SIGTERM, and SIGBREAK signals can be used only by the main thread (thread
one) in a non-Win32 application. When one of these signals occurs, the currently executing thread is suspended, and control
transfers to the signal handler (if any) set up by thread one. Other signals can be handled by any thread.A signal handler should
not use C++ runtime library functions, because a semaphore deadlock might occur. Instead, the handler should simply set a flag
or post a semaphore, and return immediately.
See Also
The main() Function ( see page 627)
629
C++ Language Guide RAD Studio 3.1 C++ Reference
To allow child processes to inherit such information about open files, you must link your program with the object file
FILEINFO.OBJ.
For example:
BCC32 TEST.C \BCB\LIB\FILEINFO.OBJ
The file information is passed in the environment variable _C_FILE_INFO. This variable contains encoded binary information.
Your program should not attempt to read or modify its value. The child program must have been built with the C++ runtime library
to inherit this information correctly.
Other programs can ignore _C_FILE_INFO, and will not inherit file information.
See Also
The main() Function ( see page 627)
630
3.1 C++ Reference RAD Studio C++ Language Guide
dclbcbsmp.lib
dclbde.lib
dcldb.lib
dclisp.lib
dclmid.lib
dclnet.lib
dclsoap.lib
dclstd.lib
dclwebsnap.lib
designdgm.lib
dxextra.lib DirectX static library
ibevnt.lib
import32.lib Import library; includes Winsock 1.x
memmgr.lib Import library for BORLNDMM.DLL
mswsock.lib Import library for MSWSOCK.DLL
noeh32.lib No exception handling support library
obsolete.lib Old functions
ole2w32.lib Import library for the 32-bit OLE 2.0 API
oleaut32.lib Import library for the 32-bit OLE 2.0 API
usebormm.lib
uuid.lib GUID static library for miscellaneous Direct 3D, DirectDraw, DirectSound, Shell
extensions, DAO, Active Scripting, and so on
vcl.lib VCL library, contains references to all other VCL libs; use in MAKEFILES with no
version #
vcllink.lib
vclstd.lib
vcljpg50.lib Static library for VCL JPEG component
w32inet.lib Import library for MS Internet DLLs
ws2_32.lib Import library for the 32-bit WinSock 2.0 API
wininet.lib Import library for the wininet.dll
631
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
The main() Function ( see page 627)
If no matching files are found, the argument is passed unchanged. (That is, a string consisting of the wildcard mask is passed to
main.)
632
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
About The Main Function ( see page 627)
<type> func()
where type is the optional return type defaulting to int. In C++, this declaration means <type> func(void). A function can be
declared to return any type except an array or function type. This approach does not allow the compiler to check that the type or
number of arguments used in a function call match the declaration.
This problem was eased by the introduction of function prototypes with the following declaration syntax:
<type> func(parameter-declarator-list);
Note: You can enable a warning within the IDE or with the command-line compiler: "Function called without a prototype."
Declarators specify the type of each function parameter. The compiler uses this information to check function calls for validity.
The compiler is also able to coerce arguments to the proper type. Suppose you have the following code fragment:
extern long lmax(long v1, long v2); /* prototype */
foo()
{
int limit = 32;
char ch = 'A';
long mval;
mval = lmax(limit,ch); /* function call */
}
Since it has the function prototype for lmax, this program converts limit and ch to long, using the standard rules of assignment,
before it places them on the stack for the call to lmax. Without the function prototype, limit and ch would have been placed on the
stack as an integer and a character, respectively; in that case, the stack passed to lmax would not match in size or content what
lmax was expecting, leading to problems. The classic declaration style does not allow any checking of parameter type or
number, so using function prototypes aids greatly in tracking down programming errors.
Function prototypes also aid in documenting code. For example, the function strcpy takes two parameters: a source string and a
destination string. The question is, which is which? The function prototype
char *strcpy(char *dest, const char *source);
makes it clear. If a header file contains function prototypes, then you can print that file to get most of the information you need for
writing programs that call those functions. If you include an identifier in a prototype parameter, it is used only for any later error
messages involving that parameter; it has no other effect.
A function declarator with parentheses containing the single word void indicates a function that takes no arguments at all:
func(void);
In C++, func() also declares a function taking no arguments
3
A function prototype normally declares a function as accepting a fixed number of parameters. For functions that accept a variable
number of parameters (such as printf), a function prototype can end with an ellipsis (...), like this:
f(int *count, long total, ...)
With this form of prototype, the fixed parameters are checked at compile time, and the variable parameters are passed with no
type checking.
Note: stdarg.h and varargs.h contain macros that you can use in user-defined functions with variable numbers of parameters.
633
C++ Language Guide RAD Studio 3.1 C++ Reference
3.1.3.4.6.4 Definitions
The general syntax for external function definitions is as follows:
Note that the above table uses the %d format as an example. The I8, I16, I32, I64 prefixes can be used with the d, i, o, x, X
formats, as well as the new L prefix previously allowed only on float to specify long double type.
634
3.1 C++ Reference RAD Studio C++ Language Guide
The ellipsis (...) indicates that the function will be called with different sets of arguments on different occasions. The ellipsis can
follow a sublist of known argument declarations. This form of prototype reduces the amount of checking the compiler can make.
The parameters declared all have automatic scope and duration for the duration of the function. The only legal storage class
specifier is register.
The const and volatile modifiers can be used with formal parameter declarators
Here is a summary of the rules governing how the compiler deals with language modifiers and formal parameters in function
calls, both with and without prototypes:
• The language modifiers for a function definition must match the modifiers used in the declaration of the function at all calls to
the function.
• A function can modify the values of its formal parameters, but this has no effect on the actual arguments in the calling routine,
except for reference arguments in C++.
When a function prototype has not been previously declared, the compiler converts integral arguments to a function call
according to the integral widening (expansion) rules described in Standard arithmetic conversions. When a function prototype
is in scope, the compiler converts the given argument to the type of the declared parameter as if by assignment
When a function prototype includes an ellipsis (...), the compiler converts all given function arguments as in any other prototype
(up to the ellipsis). The compiler widens any arguments given beyond the fixed parameters, according to the normal rules for
function arguments without prototypes.
If a prototype is present, the number of arguments must match (unless an ellipsis is present in the prototype). The types need to
be compatible only to the extent that an assignment can legally convert them. You can always use an explicit cast to convert
an argument to a type that is acceptable to a function prototype.
Note: If your function prototype does not match the actual function definition, the compiler will detect this if and only if that
definition is in the same compilation unit as the prototype. If you create a library of routines with a corresponding header file of
prototypes, consider including that header file when you compile the library, so that any discrepancies between the prototypes
3
and the actual definitions will be caught. C++ provides type-safe linkage, so differences between expected and actual
parameters will be caught by the linker.
635
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Operators Summary ( see page 636) Operators are tokens that trigger some computation when applied to variables
and other objects in an expression.
Arithmetic ( see page 656)
Assignment ( see page 591)
Bitwise ( see page 589)
C++ specific ( see page 590)
Comma ( see page 592)
Conditional ( see page 592)
Equality ( see page 590)
Logical ( see page 590)
Postfix Expression Operators
Primary Expression Operators ( see page 645)
Preprocessor
Reference/Indirect operators ( see page 658)
Relational ( see page 591)
sizeof ( see page 563)
typeid ( see page 570)
All operators can be overloaded except the following:
Preprocessor
636
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.4.8 Pointers
This section contains Pointer topics.
Topics
Name Description
Arrays ( see page 638) The declaration
type declarator [<constant-expression>]
declares an array composed of elements of type. An array consists of a
contiguous region of storage exactly large enough to hold all of its elements.
If an expression is given in an array declarator, it must evaluate to a positive
constant integer. The value is the number of elements in the array. Each of the
elements of an array is numbered from 0 through the number of elements minus
one.
Multidimensional arrays are constructed by declaring arrays of array type. The
following example shows one way to declare a two-dimensional array. The
implementation... more ( see page 638)
C++ Reference Declarations ( see page 639) C++ reference types are closely related to pointer types. Reference types create
aliases for objects and let you pass arguments to functions by reference. C
passes arguments only by value. In C++ you can pass arguments by value or by
reference. See Referencing ( see page 452) for complete details.
Pointer Arithmetic ( see page 639) Pointer arithmetic is limited to addition, subtraction, and comparison. Arithmetical
operations on object pointers of type "pointer to type" automatically take into
account the size of type; that is, the number of bytes needed to store a type
object.
3
The internal arithmetic performed on pointers depends on the memory model in
force and the presence of any overriding pointer modifiers.
When performing arithmetic with pointers, it is assumed that the pointer points to
an array of objects. Thus, if a pointer is declared to point to type, adding an
integral value to the pointer advances the pointer... more ( see page 639)
Pointer Constants ( see page 640) A pointer or the pointed-at object can be declared with the const modifier.
Anything declared as a const cannot be have its value changed. It is also illegal
to create a pointer that might violate the nonassignability of a constant object.
Consider the following examples:
637
C++ Language Guide RAD Studio 3.1 C++ Reference
Pointer Conversions ( see page 640) Pointer types can be converted to other pointer types using the typecasting
mechanism:
Pointer Declarations ( see page 641) A pointer must be declared as pointing to some particular type, even if that type
is void (which really means a pointer to anything). Once declared, though, a
pointer can usually be reassigned so that it points to an object of another type.
The compiler lets you reassign pointers like this without typecasting, but the
compiler will warn you unless the pointer was originally declared to be of type
pointer to void. In C, but not C++, you can assign a void* pointer to a non-void*
pointer. See void for details.
Warning: You need to initialize pointers... more ( see page 641)
Pointers ( see page 641) Pointers fall into two main categories: pointers to objects and pointers to
functions. Both types of pointers are special objects for holding memory
addresses.
The two pointer categories have distinct properties, purposes, and rules for
manipulation, although they do share certain characteristics. Generally speaking,
pointers to functions are used to access functions and to pass functions as
arguments to other functions; performing arithmetic on pointers to functions is not
allowed. Pointers to objects, on the other hand, are regularly incremented and
decremented as you scan arrays or more complex data structures in memory.
Although pointers are numbers with most of... more ( see page 641)
Pointers To Functions ( see page 642) A pointer to a function is best thought of as an address, usually in a code
segment, where that function's executable code is stored; that is, the address to
which control is transferred when that function is called.
A pointer to a function has a type called "pointer to function returning type,"
where type is the function’s return type. For example,
Pointers To Objects ( see page 642) A pointer of type "pointer to object of type" holds the address of (that is, points
to) an object of type. Since pointers are objects, you can have a pointer pointing
to a pointer (and so on). Other objects commonly pointed at include arrays,
structures, unions, and classes.
3.1.3.4.8.1 Arrays
The declaration
declares an array composed of elements of type. An array consists of a contiguous region of storage exactly large enough to
hold all of its elements.
If an expression is given in an array declarator, it must evaluate to a positive constant integer. The value is the number of
elements in the array. Each of the elements of an array is numbered from 0 through the number of elements minus one.
Multidimensional arrays are constructed by declaring arrays of array type. The following example shows one way to declare a
two-dimensional array. The implementation is for three rows and five columns but it can be very easily modified to accept
run-time user input.
/* DYNAMIC MEMORY ALLOCATION FOR A MULTIDIMENSIONAL OBJECT. */
#include <stdio.h>
#include <stdlib.h>
typedef long double TYPE;
typedef TYPE *OBJECT;
unsigned int rows = 3, columns = 5;
void de_allocate(OBJECT);
int main(void) {
OBJECT matrix;
unsigned int i, j;
3 /* STEP 1: SET UP THE ROWS. */
matrix = (OBJECT) calloc( rows, sizeof(TYPE *));
/* STEP 2: SET UP THE COLUMNS. */
for (i = 0; i < rows; ++i)
matrix[i] = (TYPE *) calloc( columns, sizeof(TYPE));
for (i = 0; i < rows; i++)
for (j = 0; j < columns; j++)
matrix[i][j] = i + j; /* INITIALIZE */
for (i = 0; i < rows; ++i) {
printf("\n\n");
638
3.1 C++ Reference RAD Studio C++ Language Guide
For example, an extern declaration of an array object does not need the exact dimension of the array; neither does an array
function parameter. As a special extension to ANSI C, CodeGear C++ also allows an array of indeterminate size as the final
member of a structure. Such an array does not increase the size of the structure, except that padding can be added to ensure
that the array is properly aligned. These structures are normally used in dynamic allocation, and the size of the actual array
needed must be explicitly added to the size of the structure in order to properly reserve space.
Except when it is the operand of a sizeof or & operator, an array type expression is converted to a pointer to the first element of
the array.
See Also
Arrays
The internal arithmetic performed on pointers depends on the memory model in force and the presence of any overriding pointer
modifiers.
When performing arithmetic with pointers, it is assumed that the pointer points to an array of objects. Thus, if a pointer is
declared to point to type, adding an integral value to the pointer advances the pointer by that number of objects of type. If type
has size 10 bytes, then adding an integer 5 to a pointer to type advances the pointer 50 bytes in memory. The difference has as
its value the number of array elements separating the two pointer values. For example, if ptr1 points to the third element of an 3
array, and ptr2 points to the tenth element, then the result of ptr2 - ptr1 would be 7.
The difference between two pointers has meaning only if both pointers point into the same array
When an integral value is added to or subtracted from a "pointer to type," the result is also of type "pointer to type."
There is no such element as "one past the last element," of course, but a pointer is allowed to assume such a value. If P points
to the last array element, P + 1 is legal, but P + 2 is undefined. If P points to one past the last array element, P - 1 is legal, giving
a pointer to the last element. However, applying the indirection operator * to a "pointer to one past the last element" leads to
639
C++ Language Guide RAD Studio 3.1 C++ Reference
undefined behavior.
Informally, you can think of P + n as advancing the pointer by (n * sizeof(type)) bytes, as long as the pointer remains within the
legal range (first element to one beyond the last element).
Subtracting two pointers to elements of the same array object gives an integral value of type ptrdiff_t defined in stddef.h. This
value represents the difference between the subscripts of the two referenced elements, provided it is in the range of ptrdiff_t. In
the expression P1 - P2, where P1 and P2 are of type pointer to type (or pointer to qualified type), P1 and P2 must point to
existing elements or to one past the last element. If P1 points to the i-th element, and P2 points to the j-th element, P1 - P2 has
the value (i - j).
640
3.1 C++ Reference RAD Studio C++ Language Guide
A null pointer value is an address that is guaranteed to be different from any valid pointer in use in a program. Assigning the
integer constant 0 to a pointer assigns a null pointer value to it.
The mnemonic NULL (defined in the standard library header files, such as stdio.h) can be used for legibility. All pointers can be
successfully tested for equality or inequality to NULL.
The pointer type "pointer to void" must not be confused with the null pointer. The declaration
void *vptr;
declares that vptr is a generic pointer capable of being assigned to by any "pointer to type" value, including null, without
complaint. Assignments without proper casting between a "pointer to type1" and a "pointer to type2," where type1 and type2
are different types, can invoke a compiler warning or error. If type1 is a function and type2 isn't (or vice versa), pointer
assignments are illegal. If type1 is a pointer to void, no cast is needed. Under C, if type2 is a pointer to void, no cast is needed.
3.1.3.4.8.7 Pointers
Pointers fall into two main categories: pointers to objects and pointers to functions. Both types of pointers are special objects for
holding memory addresses.
The two pointer categories have distinct properties, purposes, and rules for manipulation, although they do share certain
characteristics. Generally speaking, pointers to functions are used to access functions and to pass functions as arguments to
other functions; performing arithmetic on pointers to functions is not allowed. Pointers to objects, on the other hand, are regularly
incremented and decremented as you scan arrays or more complex data structures in memory.
Although pointers are numbers with most of the characteristics of unsigned integers, they have their own rules and restrictions
for assignments, conversions, and arithmetic. The examples in the next few sections illustrate these rules and restrictions.
See Also
Pointers To Objects ( see page 642)
641
C++ Language Guide RAD Studio 3.1 C++ Reference
A pointer to a function has a type called "pointer to function returning type," where type is the function’s return type. For
example,
void (*func)();
In C++, this is a pointer to a function taking no arguments, and returning void. In C, it's a pointer to a function taking an
unspecified number of arguments and returning void. In this example,
void (*func)(int);
*func is a pointer to a function taking an int argument and returning void.
For C++, such a pointer can be used to access static member functions. Pointers to class members must use pointer-to-member
operators. See static_cast for details.
Topics
Name Description
. (direct Member Selector) ( see page 642) Syntax
-> (indirect Member Selector) ( see page 643) Syntax
Array Subscript Operator ( see page 643) Brackets ([ ]) indicate single and multidimensional array subscripts. The
expression
Increment/decrement Operators ( see page 643) Increment operator ( ++ )
Syntax
Function Call Operator ( see page 644) Syntax
Use the selection operator (.) to access structure and union members.
Suppose that the object s is of struct type S and sptr is a pointer to S. Then, if m is a member identifier of type M declared in S,
this expression:
s.m
are of type M, and represent the member object m in s.
642
3.1 C++ Reference RAD Studio C++ Language Guide
The expression designates a member of a structure or union object. The value of the expression is the value of the selected
member it will be an lvalue if and only if the postfix expression is an lvalue.
Remarks
You use the selection operator -> to access structure and union members.
Suppose that the object s is of struct type S and sptr is a pointer to S. Then, if m is a member identifier of type M declared in S,
this expression:
sptr->m
is of type M, and represents the member object m in s.
The expression
s->sptr
is a convenient synonym for (*sptr).m.
Syntax
postfix-expression ++ (postincrement)
++ unary-expression (preincrement)
The expression is called the operand. It must be of scalar type (arithmetic or pointer types) and must be a modifiable lvalue..
3
Postincrement operator
The value of the whole expression is the value of the postfix expression before the increment is applied.
Preincrement operator
The operand is incremented by 1 before the expression is evaluated. The value of the whole expression is the incremented value
643
C++ Language Guide RAD Studio 3.1 C++ Reference
of the operand.
Decrement operator ( -- )
Syntax
postfix-expression -- (postdecrement)
-- unary-expression (predecrement)
The decrement operator follows the same rules as the increment operator, except that the operand is decremented by 1 after or
before the whole expression is evaluated.
Parentheses ()
• group expressions
• isolate conditional expressions
• indicate function calls and function parameters
The value of the function call expression, if it has a value, is determined by the return statement in the function definition.
This is a call to the function given by the postfix expression.
arg-expression-list is a comma-delimited list of expressions of any type representing the actual (or real) function arguments.
644
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Primary Expression Operators ( see page 645) For ANSI C, the primary expressions are literal (also sometimes referred to as
constant), identifier, and ( expression ). The C++ language extends this list of
primary expressions to include the keyword this, scope resolution operator ::,
name, and the class destructor ~ (tilde).
The primary expressions are summarized in the following list.
primary-expression:
primary-expression:
645
C++ Language Guide RAD Studio 3.1 C++ Reference
name:
1. identifieroperator-function-name (C++ specific)
2. conversion-function-name (C++ specific)
3. ~ class-name (C++ specific)
4. qualified-name (C++ specific)
qualified-name: (C++ specific)
qualified-class-name :: name
For a discussion of the primary expression this, see this (keyword). The keyword this cannot be used outside a class member
function body.
The discussion of the scope resolution operator :: begins on page 104. The scope resolution operator allows reference to a type,
object, function, or enumerator even though its identifier is hidden.
The parenthesis surrounding an expression do not change the unadorned expression itself.
The primary expression name is restricted to the category of primary expressions that sometimes appear after the member
access operators . (dot) and –> . Therefore, name must be either an lvalue or a function. See also the discussion of member
access operators.
An identifier is a primary expression, provided it has been suitably declared. The description and formal definition of identifiers is
shown in Lexical Elements: Identifiers.
See the discussion on how to use the destructor operator ~ (tilde).
3.1.3.4.11 Statements
This section contains Statement topics.
Topics
Name Description
Blocks ( see page 647) A compound statement, or block, is a list (possibly empty) of statements
enclosed in matching braces ({ }). Syntactically, a block can be considered to be
a single statement, but it also plays a role in the scoping of identifiers. An
identifier declared within a block has a scope starting at the point of declaration
and ending at the closing brace. Blocks can be nested to any depth up to the
limits of memory.
C++ Specifics ( see page 647) C++ is an object-oriented programming language based on C. Generally
speaking, you can compile C programs under C++, but you can’t compile a C++
program under C if the program uses any constructs specific to C++. Some
situations require special care. For example, the same function func declared
twice in C with different argument types causes a duplicated name error. Under
C++, however, func will be interpreted as an overloaded function; whether or not
this is legal depends on other circumstances.
Although C++ introduces new keywords and operators to handle classes, some
of the capabilities of C++ have applications outside... more ( see page 647)
Expression Statements ( see page 647) Any expression followed by a semicolon forms an expression statement:
Iteration Statements ( see page 648) Iteration statements let you loop a set of statements. There are three forms of
iteration in C++: while, do while, and for loops.
Jump Statements ( see page 648) A jump statement, when executed, transfers control unconditionally. There are
four such statements: break, continue, goto, and return
3
646
3.1 C++ Reference RAD Studio C++ Language Guide
Labeled Statements ( see page 648) A statement can be labeled in two ways:
• label-identifier : statement
* The label identifier serves as a target for the unconditional
goto statement. Label identifiers have their own name
space and have function scope. In C++ you can label both
declaration and non-declaration statements.
• case constant-expression : statement
* default : statement
Case and default labeled statements are used only in
conjunction with switch statements.
Selection Statements ( see page 648) Selection or flow-control statements select from alternative courses of action by
testing certain values. There are two types of selection statements: the if...else
and the switch.
Statements ( see page 648) Statements specify the flow of control as a program executes. In the absence of
specific jump and selection statements, statements are executed sequentially in
the order of appearance in the source code. CodeGear C++ statements shows
the syntax for statements.
CodeGear C++ statements
3.1.3.4.11.1 Blocks
A compound statement, or block, is a list (possibly empty) of statements enclosed in matching braces ({ }). Syntactically, a block
can be considered to be a single statement, but it also plays a role in the scoping of identifiers. An identifier declared within a
block has a scope starting at the point of declaration and ending at the closing brace. Blocks can be nested to any depth up to
the limits of memory.
Although C++ introduces new keywords and operators to handle classes, some of the capabilities of C++ have applications
outside of any class context. This topic discusses the aspects of C++ that can be used independently of classes, then describes
the specifics of classes and class mechanisms.
See C++ Exception Handling and C-Based Structured Exceptions for details on compiling C and C++ programs with exception
handling.
See Also
Referencing ( see page 452)
647
C++ Language Guide RAD Studio 3.1 C++ Reference
<expression>;
The compiler executes an expression statement by evaluating the expression. All side effects from this evaluation are completed
before the next statement is executed. Most expression statements are assignment statements or function calls
The null statement is a special case, consisting of a single semicolon (;). The null statement does nothing, and is therefore useful
in situations where C++ syntax expects a statement but your program does not need one.
• label-identifier : statement
* The label identifier serves as a target for the unconditional goto statement. Label identifiers have their own name space and
have function scope. In C++ you can label both declaration and non-declaration statements.
• case constant-expression : statement
* default : statement
Case and default labeled statements are used only in conjunction with switch statements.
3.1.3.4.11.8 Statements
Statements specify the flow of control as a program executes. In the absence of specific jump and selection statements,
statements are executed sequentially in the order of appearance in the source code. CodeGear C++ statements shows the
syntax for statements.
statement labeled-statement
compound-statement
expression-statement
selection-statement
3
iteration-statement
jump-statement
asm-statement
declaration (C++ specific)
labeled-statement: identifier : statement
case constant-expression : statement
default : statement
648
3.1 C++ Reference RAD Studio C++ Language Guide
3.1.3.4.12 Structures
This section contains Structure topics.
Topics
Name Description
Structures ( see page 650) A structure is a derived type usually representing a user-defined collection of
named members (or components). The members can be of any type, either
fundamental or derived (with some restrictions to be noted later), in any
sequence. In addition, a structure member can be a bit field type not allowed
elsewhere. The structure type lets you handle complex data structures almost as
easily as single variables. Structure initialization is discussed in Arrays,
structures, and unions in the help topic Initialization ( see page 611).
In C++, a structure type is treated as a class type with certain differences: default
access is public, and... more ( see page 650)
Untagged Structures And Typedefs ( see page 650) If you omit the structure tag, you can get an untagged structure. You can use
untagged structures to declare the identifiers in the comma-delimited struct-id-list
to be of the given structure type (or derived from it), but you cannot declare
additional objects of this type elsewhere
Structure Member Declarations ( see page 651) The member-decl-list within the braces declares the types and names of the
structure members using the declarator syntax shown in CodeGear C++ 3
declaration syntax.
A structure member can be of any type, with two exceptions
The member type cannot be the same as the struct type being currently
declared:
Structures And Functions ( see page 651) A function can return a structure type or a pointer to a structure type:
649
C++ Language Guide RAD Studio 3.1 C++ Reference
Structure Member Access ( see page 651) Structure and union members are accessed using the following two selection
operators:
• . (period)
• -> (right arrow)
Suppose that the object s is of struct type S, and sptr is a
pointer to S. Then if m is a member identifier of type M
declared in S, the expressions s.m and sptr->m are of
type M, and both represent the member object m in S.
The expression sptr->m is a convenient synonym for
(*sptr).m.
The operator . is called the direct member selector and the
operator -> is called the indirect (or pointer) member
selector. For example:
Structure Name Spaces ( see page 652) Structure tag names share the same name space with union tags and
enumeration tags (but enums within a structure are in a different name space in
C++). This means that such tags must be uniquely named within the same
scope. However, tag names need not differ from identifiers in the other three
name spaces: the label name space, the member name space(s), and the single
name space (which consists of variables, functions, typedef names, and
enumerators).
Member names within a given structure or union must be unique, but they can
share the names of members in other structures or unions.... more ( see page
652)
Incomplete Declarations ( see page 653) Incomplete declarations are also known as forward declarations.
A pointer to a structure type A can legally appear in the declaration of another
structure B before A has been declared:
Bit Fields ( see page 653) Bit fields are specified numbers of bits that may or may not have an associated
identifier. Bit fields offer a way of subdividing structures (structs, unions, classes)
into named parts of user-defined sizes.
Declaring bit fields
You specify the bit-field width and optional identifier as follows:
3.1.3.4.12.1 Structures
A structure is a derived type usually representing a user-defined collection of named members (or components). The members
can be of any type, either fundamental or derived (with some restrictions to be noted later), in any sequence. In addition, a
structure member can be a bit field type not allowed elsewhere. The structure type lets you handle complex data structures
almost as easily as single variables. Structure initialization is discussed in Arrays, structures, and unions in the help topic
Initialization ( see page 611).
In C++, a structure type is treated as a class type with certain differences: default access is public, and the default for the base
class is also public. This allows more sophisticated control over access to structure members by using the C++ access
specifiers: public (the default), private, and protected. Apart from these optional access mechanisms, and from exceptions as
noted, the following discussion on structure syntax and usage applies equally to C and C++ structures.
650
3.1 C++ Reference RAD Studio C++ Language Guide
The member type cannot be the same as the struct type being currently declared:
struct mystruct { mystruct s } s1, s2; // illegal
However, a member can be a pointer to the structure being declared, as in the following example:
struct mystruct { mystruct *ps } s1, s2; // OK
Also, a structure can contain previously defined structure types when declaring an instance of a declared structure.
Except in C++, a member cannot have the type "function returning...," but the type "pointer to function returning..." is allowed. In
C++, a struct can have member functions.
keyword in C++.
• . (period) 3
• -> (right arrow)
Suppose that the object s is of struct type S, and sptr is a pointer to S. Then if m is a member identifier of type M declared in S,
the expressions s.m and sptr->m are of type M, and both represent the member object m in S. The expression sptr->m is a
convenient synonym for (*sptr).m.
The operator . is called the direct member selector and the operator -> is called the indirect (or pointer) member selector. For
example:
651
C++ Language Guide RAD Studio 3.1 C++ Reference
struct mystruct
{
int i;
char str[21];
double d;
} s, *sptr = &s;
.
.
.
s.i = 3; // assign to the i member of mystruct s
sptr -> d = 1.23; // assign to the d member of mystruct s
The expression s.m is an lvalue, provided that s is an lvalue and m is not an array type. The expression sptr->m is an lvalue
unless m is an array type.
If structure B contains a field whose type is structure A, the members of A can be accessed by two applications of the member
selectors
struct A {
int j;
double x;
};
struct B {
int i;
struct A a;
double d;
} s, *sptr;
.
.
.
s.i = 3; // assign to the i member of B
s.a.j = 2; // assign to the j member of A
sptr->d = 1.23; // assign to the d member of B
sptr->a.x = 3.14 // assign to x member of A
Each structure declaration introduces a unique structure type, so that in
struct A {
int i,j;
double d;
} a, a1;
struct B {
int i,j;
double d;
} b;
the objects a and a1 are both of type struct A, but the objects a and b are of different structure types. Structures can be assigned
only if the source and destination have the same type:
a = a1; // OK: same type, so member by member assignment
a = b; // ILLEGAL: different types
a.i = b.i; a.j = b.j; a.d = b.d /* but you can assign member-by-member */
Member names within a given structure or union must be unique, but they can share the names of members in other structures
or unions. For example
goto s;
.
.
652
3.1 C++ Reference RAD Studio C++ Language Guide
.
s: // Label
struct s { // OK: tag and label name spaces different
int s; // OK: label, tag and member name spaces different
float s; // ILLEGAL: member name duplicated
} s; // OK: var name space different. In C++, this can only
// be done if s does not have a constructor.
union s { // ILLEGAL: tag space duplicate
int s; // OK: new member space
float f;
} f; // OK: var name space
struct t {
int s; // OK: different member space
.
.
.
} s; // ILLEGAL: var name duplicate
A pointer to a structure type A can legally appear in the declaration of another structure B before A has been declared:
struct A; // incomplete
struct B { struct A *pa };
struct A { struct B *pb };
The first appearance of A is called incomplete because there is no definition for it at that point. An incomplete declaration is
allowed here, because the definition of B doesn't need the size of A.
The expression width must be present and must evaluate to a constant integer. In C++, the width of a bit field may be declared of
any size. In strict ANSI C, the width of a bit field may be declared only up to the size of the declared type. A zero length bit field
skips to the next allocation unit.
If the bit field identifier is omitted, the number of bits specified in width is allocated, but the field is not accessible. This lets you
match bit patterns in, say, hardware registers where some bits are unused.
Bit fields can be declared only in structures, unions, and classes. They are accessed with the same member selectors ( . and ->)
used for non-bit-field members.
3
Limitations of using bit fields
• The code will be non-portable since the organization of bits-within-bytes and bytes-within-words is machine dependent.
• You cannot take the address of a bit field; so the expression &mystruct.x is illegal if x is a bit field identifier, because there is
no guarantee that mystruct.x lies at a byte address.
• Bit fields are used to pack more variables into a smaller data space, but causes the compiler to generate additional code to
653
C++ Language Guide RAD Studio 3.1 C++ Reference
manipulate these variables. This costs in terms of code size and execution time.
Because of these disadvantages, using bit fields is generally discouraged, except for certain low-level programming. A
recommended alternative to having one-bit variables, or flags, is to use defines. For example:
#define Nothing 0x00
#define bitOne 0x01
#define bitTwo 0x02
#define bitThree 0x04
#define bitFour 0x08
#define bitFive 0x10
#define bitSix 0x20
#define bitSeven 0x40
#define bitEight 0x80
can be used to write code like:
if (flags & bitOne) {...} // is bit One turned on
flags |= bitTwo; // turn bit Two on
flags &= ~bitThree; // turn bit Three off
Similar schemes can be made for bit fields of any size.
In C++, if the width size is larger than the type of the bit field, the compiler will insert padding equal to the requested width size
minus the size of the type of the bit field. So, declaration:
struct mystruct
{
int i : 40;
int j : 8;
};
will create a 32 bit storage for 'i', an 8 bit padding, and 8 bit storage for 'j'. To optimize access, the compiler will consider 'i' to be a
regular int variable, not a bit field.
Bit fields are broken up into groups of consecutive bit fields of the same type, without regard to signedness. Each group of bit
fields is aligned to the current alignment of the type of the members of the group. This alignment is determined by the type AND
by the setting of the overall alignment (set by the byte alignment option –aN). Within each group, the compiler will pack the bit
fields inside of areas as large as the type size of the bit fields. However, no bit field is allowed to straddle the boundary between
2 of those areas. The size of the total structure will be aligned, as determined by the current alignment.
In the following C++ declaration, my_struct contains 6 bit fields of 3 different types, int, long, and char:
struct my_struct
{
3 int one : 8;
unsigned int two : 16;
unsigned long three : 8;
long four : 16;
long five : 16;
char six : 4;
};
Bit fields 'one' and 'two' will be packed into one 32-bit area.
Next, the compiler inserts padding, if necessary, based on the current alignment, and the type of three, because the type
654
3.1 C++ Reference RAD Studio C++ Language Guide
changes between the declarations of variables two and three. For example, if the current alignment is byte alignment (-a1), no
padding is needed; whereas, if the alignment is 4 bytes (-a4), then 8-bit padding is inserted.
Next, variables three, four, and five are all of type long. Variables three and four are packed into one 32 bit area, but five can not
be packed into that same area, since that would create an area of 40 bits, which is more than the 32 bit allowed for the long
type. To start a new area for five, the compiler would insert no padding if the current alignment is byte alignment, or would insert
8 bits of padding if the current alignment is dword (4 byte) alignment.
With variable six, the type changes again. Since char is always byte aligned, no padding is needed. To force alignment for the
whole struct, the compiler will finish up the last area with 4 bits of padding if byte alignment is used, or 12 bits of padding if dword
alignment is used.
The total size of my_struct is 9 bytes with byte alignment, or 12 bytes with dword alignment.
To get the best results when using bit fields you should:
Notes on compatibility
Between versions of the compiler, changes can be made to default alignment, or for purposes of compatibility with other
compilers. Consequently, this could change the alignment of bit fields. Therefore, there is no guarantee that the alignment of bit
655
C++ Language Guide RAD Studio 3.1 C++ Reference
fields will be consistent between versions of the compiler. To check the backward compatibility of bit fields in your code you can
add an assert statement that checks for the structure size you are expecting.
According to the C and C++ language specifications, the alignment and storage of bit fields is implementation defined. Therefore,
compilers can align and store bit fields differently. If you want complete control over the layout of bit fields, it is advisable to write
your own bit field accessing routines and create your own bit fields.
Topics
Name Description
Unary Operators ( see page 656) Syntax
Arithmetic Operators ( see page 656) Syntax
Plus And Minus Operators ( see page 657) Unary
In these unary + - expressions
Reference/Deference Operators ( see page 658) Syntax
• ! Logical negation
• * Indirection
• ++ Increment
• ~ Bitwise complement
• -- Decrement
• - Unary minus
• + Unary plus
656
3.1 C++ Reference RAD Studio C++ Language Guide
Remarks
The unary expressions of + and - assign a positive or negative value to the cast-expression.
• (addition), - (subtraction), * (multiplication), and / (division) perform their basic algebraic arithmetic on all data types, integer
and floating point.
% (modulus operator) returns the remainder of integer division and cannot be used with floating points.
++ (increment) adds one to the value of the expression. Postincrement adds one to the value of the expression after it evaluates;
while preincrement adds one before it evaluates.
-- (decrement) subtracts one from the value of the expression. Postdecrement subtracts one from the value of the expression
after it evaluates; while predecrement subtracts one before it evaluates.
Results
657
C++ Language Guide RAD Studio 3.1 C++ Reference
The & and * operators work together to reference and dereference pointers that are passed to functions.
Use the reference operator to pass the address of a pointer to a function outside of main().
• a function designator
• an lvalue designating an object that is not a bit field and is not declared with a register storage class specifier
If the operand is of type <type>, the result is of type pointer to <type>.
Some non-lvalue identifiers, such as function names and array names, are automatically converted into “pointer-to-X” types
when they appear in certain contexts. The & operator can be used with such objects, but its use is redundant and therefore
discouraged.
Consider the following example:
T t1 = 1, t2 = 2;
T *ptr = &t1; // Initialized pointer
*ptr = t2; // Same effect as t1 = t2
T *ptr = &t1 is treated as
T *ptr;
ptr = &t1;
So it is ptr, or *ptr, that gets assigned. Once ptr has been initialized with the address &t1, it can be safely dereferenced to give
the lvalue *ptr.
Indirection operator ( * )
Use the asterisk (*) in a variable expression to create pointers. And use the indirect operator in external functions to get a
pointer's value that was passed by reference.
If the operand is a pointer to an object, the result is an lvalue designating that object.
3.1.3.4.14 Unions
This section contains Union topics.
658
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Unions ( see page 659) Union types are derived types sharing many of the syntactic and functional
features of structure types. The key difference is that a union allows only one of
its members to be "active" at any one time. The size of a union is the size of its
largest member. The value of only one of its members can be stored at any time.
In the following simple case,
Anonymous Unions ( see page 659) A union that does not have a tag and is not used to declare a named object (or
other type) is called an anonymous union. It has the following form:
Union Declarations ( see page 660) The general declaration syntax for unions is similar to that for structures. The
differences are:
• Unions can contain bit fields, but only one can be active.
They all start at the beginning of the union. (Note that,
because bit fields are machine dependent, they can pose
problems when writing portable code.)
• Unlike C++ structures, C++ union types cannot use the
class access specifiers: public, private, and protected.
All fields of a union are public.
• Unions can be initialized only through their first declared
member:
3.1.3.4.14.1 Unions
Union types are derived types sharing many of the syntactic and functional features of structure types. The key difference is that
a union allows only one of its members to be "active" at any one time. The size of a union is the size of its largest member. The
value of only one of its members can be stored at any time. In the following simple case,
union myunion { /* union tag = myunion */
int i;
double d;
char ch;
} mu, *muptr=μ
the identifier mu, of type union myunion, can be used to hold an int, an 8-byte double, or a single-byte char, but only one of
these at the same time
sizeof(union myunion) and sizeof(mu) both return 8, but 4 bytes are unused (padded) when mu holds an int object, and 7
bytes are unused when mu holds a char. You access union members with the structure member selectors (. and ->), but care is
needed:
mu.d = 4.016;
printf("mu.d = %f\n",mu.d); //OK: displays mu.d = 4.016printf("mu.i = %d\n",mu.i); //peculiar
resultmu.ch = 'A';
printf("mu.ch = %c\n",mu.ch); //OK: displays mu.ch = Aprintf("mu.d = %f\n",mu.d); //peculiar
resultmuptr->i = 3;
printf("mu.i = %d\n",mu.i); //OK: displays mu.i = 3
The second printf is legal, since mu.i is an integer type. However, the bit pattern in mu.i corresponds to parts of the double
previously assigned, and will not usually provide a useful integer interpretation. 3
When properly converted, a pointer to a union points to each of its members, and vice versa.
659
C++ Language Guide RAD Studio 3.1 C++ Reference
union { member-list };
Its members can be accessed directly in the scope where this union is declared, without using the x.y or p->y syntax.
Anonymous unions can be global, nested, or unnested. ANSI-C never allows anonymous unions. ANSI-C++ allows all three
types of anonymous unions.
An anonymous union cannot have member functions or private or protected members. At file level an anonymous union must be
declared static. Local anonymous unions must be either automatic or static; in other words, an anonymous union cannot have
external linkage. Unnested anonymous unions are only allowed in C++.
The outer structure, class, or union of a nested anonymous union must have a tag. CodeGear C and C++ allow nested
anonymous unions by default. In C only, a nested anonymous union can, optionally, have a tag.
Example
struct outer {
int x;
};
int main(void)
{
struct outer o;
}
• Unions can contain bit fields, but only one can be active. They all start at the beginning of the union. (Note that, because bit
fields are machine dependent, they can pose problems when writing portable code.)
• Unlike C++ structures, C++ union types cannot use the class access specifiers: public, private, and protected. All fields of a
union are public.
• Unions can be initialized only through their first declared member:
union local87 {
int i;
double d;
} a = { 20 };
A union can't participate in a class hierarchy. It can't be derived from any class, nor can it be a base class. A union can have a
constructor.
Topics
3 Name Description
Lexical Elements ( see page 661) These topics provide a formal definition of C++ lexical elements. They describe
the different categories of word-like units (tokens) recognized by a language.
The tokens in a C++ source file are derived from a series of operations
performed on your programs by the compiler and its built-in preprocessor.
The preprocessor first scans the program text for special preprocessor directives
(see Preprocessor directives for details). For example, the directive #include
<inc_file> adds (or includes) the contents of the file inc_file to the program before
the compilation phase. The preprocessor also expands any macros found in the
program and include files.
A... more ( see page 661)
660
3.1 C++ Reference RAD Studio C++ Language Guide
Tokens Overview ( see page 661) This section contains Token topics.
Whitespace Overview ( see page 684) This section contains Whitespace Overview topics.
The tokens in a C++ source file are derived from a series of operations performed on your programs by the compiler and its
built-in preprocessor.
The preprocessor first scans the program text for special preprocessor directives (see Preprocessor directives for details). For
example, the directive #include <inc_file> adds (or includes) the contents of the file inc_file to the program before the
compilation phase. The preprocessor also expands any macros found in the program and include files.
A C++ program starts as a sequence of ASCII characters representing the source code, created using a suitable text editor
(such as the IDE’s editor). The basic program unit in C++ is a source file (usually designated by a ".c", or ".cpp" in its name), and
all of the header files and other source files included with the #include preprocessor directive. Source files are usually
designated by a ".c" or ".cpp" in the name, while header files are usually designated with a ".h" or ".hpp".
In the tokenizing phase of compilation, the source code file is parsed (that is, broken down) into tokens and whitespace.
See Also
Whitespace ( see page 686)
Topics
Name Description
Constants Overview ( see page 662) This section contains Constant topics.
Tokens ( see page 678) Tokens are word-like units recognized by a language. The compiler recognizes
six classes of tokens.
Here is the formal definition of a token:
• keyword
• identifier
• constant
• string-literal
• operator
• punctuator (also known as separators)
As the source code is scanned, tokens are extracted in such
a way that the longest possible token from the character 3
sequence is selected. For example, external would be
parsed as a single identifier, rather than as the keyword
extern followed by the identifier al.
See Token Pasting with ## for a description of token pasting.
Identifiers Overview ( see page 679) This section contains Identifier topics.
Keywords Overview ( see page 680) This section contains Keyword topics.
Punctuators Overview ( see page 681) This section contains Punctuator topics.
661
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Character Constants Overview ( see page 662) This section contains Character Constant topics.
Constants ( see page 667) Constants are tokens representing fixed numeric or character values.
The compiler supports four classes of constants: integer, floating point, character
(including strings), and enumeration.
Internal representation of numerical types shows how these types are
represented internally.
The data type of a constant is deduced by the compiler using such clues as
numeric value and the format used in the source code. The formal definition of a
constant is shown in the following table.
Constants: Formal Definitions
Integer Constant Without L Or U ( see page 669) Decimal constants
Constant Expressions ( see page 670) This section contains Constant Expression topics.
Constants and Internal Representation ( see page 670) This section contains Constants and Internal Representation topics.
Floating Point Constants ( see page 672) A floating-point constant consists of:
• Decimal integer
• Decimal point
• Decimal fraction
• e or E and a signed integer exponent (optional)
• Type suffix: f or F or l or L (optional)
You can omit either the decimal integer or the decimal
fraction (but not both). You can omit either the decimal
point or the letter e (or E) and the signed integer exponent
(but not both). These rules allow for conventional and
scientific (exponent) notations.
Negative floating constants are taken as positive constants
with the unary operator minus (-) prefixed.
Here are some examples:
Enumeration Constants ( see page 673) This section contains Enumeration Constant topics.
Integer Constants ( see page 674) Integer constants can be decimal (base 10), octal (base 8) or hexadecimal (base
16). In the absence of any overriding suffixes, the data type of an integer
constant is derived from its value, as shown in Integer constants without L or U..
Note that the rules vary between decimal and nondecimal constants.
Decimal
Decimal constants from 0 to 4,294,967,295 are allowed. Constants exceeding
this limit are truncated. Decimal constants must not use an initial zero. An integer
constant that has an initial zero is interpreted as an octal constant. Thus,
Internal Representation of Numerical Types ( see page 675) This section contains Internal Representation of Numerical Type topics.
String Constants ( see page 677) This section contains String Constant topics.
662
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Character Constants ( see page 663) A character constant is one or more characters enclosed in single quotes, such
as 'A', '+', or '\n'. In C, single-character constants have data type int. In C++, a
character constant has type char. Multicharacter constants in both C and C++
have data type int.
To learn more about character constants, see the following topics.
Escape Sequences ( see page 664) The backslash character (\) is used to introduce an escape sequence, which
allows the visual representation of certain nongraphic characters. For example,
the constant \n is used to the single newline character.
A backslash is used with octal or hexadecimal numbers to represent the ASCII
symbol or control code corresponding to that value; for example, '\03' for Ctrl-C or
'\x3F' for the question mark. You can use any string of up to three octal or any
number of hexadecimal numbers in an escape sequence, provided that the value
is within legal range for data type char (0 to 0xff). Larger... more ( see page
664)
The Three Char Types ( see page 666) One-character constants, such as 'A', '\t' and '007', are represented as int values.
In this case, the low-order byte is sign extended into the high bit; that is, if the
value is greater than 127 (base 10), the upper bit is set to -1 (=0xFF). This can
be disabled by declaring that the default char type is unsigned.
The three character types, char, signed char, and unsigned char, require an
8-bit (one byte) storage. By default, the compiler treats character declarations as
signed. Use the –K compiler option to treat character declarations as unsigned.
The behavior of C... more ( see page 666)
Wide-character And Multi-character Constants ( see page 666) Wide-character types can be used to represent a character that does not fit into
the storage space allocated for a char type. A wide character is stored in a
two-byte space. A character constant preceded immediately by an L is a
wide-character constant of data type wchar_t (defined in stddef.h). For example:
#include <stdio.h> 3
#define CH 'x' /* A CHARACTER CONSTANT */
void main(void) {
char ch = 'x'; /* A char VARIABLE */
printf("\nSizeof int = %d", sizeof(int) );
printf("\nSizeof char = %d", sizeof(char) );
printf("\nSizeof ch = %d", sizeof(ch) );
printf("\nSizeof CH = %d", sizeof(CH) );
printf("\nSizeof wchar_t = %d", sizeof(wchar_t) );
}
663
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
Constants ( see page 667)
A backslash is used with octal or hexadecimal numbers to represent the ASCII symbol or control code corresponding to that
value; for example, '\03' for Ctrl-C or '\x3F' for the question mark. You can use any string of up to three octal or any number of
hexadecimal numbers in an escape sequence, provided that the value is within legal range for data type char (0 to 0xff). Larger
numbers generate the compiler error Numeric constant too large. For example, the octal number \777 is larger than the
maximum value allowed (\377) and will generate an error. The first nonoctal or nonhexadecimal character encountered in an
octal or hexadecimal escape sequence marks the end of the sequence.
3
Take this example.
printf("\x0072.1A Simple Operating System");
This is intended to be interpreted as \x007 and "2.1A Simple Operating System". However, the compiler treats it as the
hexadecimal number \x0072 and the literal string "2.1A Simple Operating System".
664
3.1 C++ Reference RAD Studio C++ Language Guide
Ambiguities might also arise if an octal escape sequence is followed by a nonoctal digit. For example, because 8 and 9 are not
legal octal digits, the constant \258 would be interpreted as a two-character constant made up of the characters \25 and 8.
Escape sequences
Note: You must use \\ to represent an ASCII backslash, as used in operating system paths.
See Also
Constants ( see page 667)
665
C++ Language Guide RAD Studio 3.1 C++ Reference
The three character types, char, signed char, and unsigned char, require an 8-bit (one byte) storage. By default, the compiler
treats character declarations as signed. Use the –K compiler option to treat character declarations as unsigned. The behavior of
C programs is unaffected by the distinction between the three character types.
In a C++ program, a function can be overloaded with arguments of type char, signed char, or unsigned char. For example, the
following function prototypes are valid and distinct:
void func(char ch);
void func(signed char ch);
void func(unsigned char ch);
If only one of the above prototypes exists, it will accept any of the three character types. For example, the following is
acceptable:
void func(unsigned char ch);
void main(void)
{
signed char ch = 'x';
func(ch);
}
See Also
Constants ( see page 667)
666
3.1 C++ Reference RAD Studio C++ Language Guide
A string preceded immediately by an L is a wide-character string. The memory allocation for a string is two bytes per character.
For example:
wchar_t *str = L"ABCD";
Multi-character constants
The compiler also supports multi-character constants. Multi-character constants can consist of as many as four characters. For
example, the constant, '\006\007\008\009' is valid only in a CodeGear C++ program. Multi-character constants are always 32-bit
int values. The constants are not portable to other C++ compilers.
See Also
Constants ( see page 667)
3.1.3.5.2.1.2 Constants
Constants are tokens representing fixed numeric or character values.
The compiler supports four classes of constants: integer, floating point, character (including strings), and enumeration.
Internal representation of numerical types shows how these types are represented internally.
The data type of a constant is deduced by the compiler using such clues as numeric value and the format used in the source
code. The formal definition of a constant is shown in the following table.
667
C++ Language Guide RAD Studio 3.1 C++ Reference
exponent-part: integer-suffix:
e <sign> digit-sequence unsigned-suffix <long-suffix>
E <sign> digit-sequence long-suffix <unsigned-suffix>
sign: one of unsigned-suffix: one of
• - uU
See Also
Integer Constants ( see page 674)
668
3.1 C++ Reference RAD Studio C++ Language Guide
0 to 32,767 int
32,768 to 2,147,483,647 long
2,147,483,648 to 4,294,967,295 unsigned long
> 4294967295 truncated
Octal constants
00 to 077777 int
010000 to 0177777 unsigned int
02000000 to 017777777777 long
020000000000 to 037777777777 unsigned long
> 037777777777 truncated
Hexadecimal constants
See Also
Constants ( see page 667)
669
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Constant Expressions ( see page 670) A constant expression is an expression that always evaluates to a constant (it is
evaluated at compile-time and it must evaluate to a constant that is in the range
of representable values for its type). Constant expressions are evaluated just as
regular expressions are. You can use a constant expression anywhere that a
constant is legal. The syntax for constant expressions is:
• Assignment
• Comma
• Decrement
• Function call
• Increment
See Also
Constants ( see page 667)
670
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Constants And Internal Representation ( see page 671) ANSI C acknowledges that the size and numeric range of the basic data types
(and their various permutations) are implementation-specific and usually derive
from the architecture of the host computer. For CodeGear C++, the target
platform is the IBM PC family (and compatibles), so the architecture of the Intel
80x86 and the Pentium family of microprocessors governs the choices of internal
representations for the various data types.
The following tables list the sizes and resulting ranges of the data types. Internal
representation of numerical types shows how these types are represented
internally.
32-bit data types, sizes, and ranges
The following tables list the sizes and resulting ranges of the data types. Internal representation of numerical types shows how
these types are represented internally.
See Also
Constants ( see page 667)
671
C++ Language Guide RAD Studio 3.1 C++ Reference
• Decimal integer
• Decimal point
• Decimal fraction
• e or E and a signed integer exponent (optional)
• Type suffix: f or F or l or L (optional)
You can omit either the decimal integer or the decimal fraction (but not both). You can omit either the decimal point or the letter e
(or E) and the signed integer exponent (but not both). These rules allow for conventional and scientific (exponent) notations.
Negative floating constants are taken as positive constants with the unary operator minus (-) prefixed.
Here are some examples:
Constant Value
23.45e6 23.45 ( 10^6
.0 0
0. 0.0
1. 1.0
-1.23 -1.23
2e-5 2.0 ( 10^-5
3E+10 3.0 ( 10^10
.09E34 0.09 ( 10^34
3
In the absence of any suffixes, floating-point constants are of type double. However, you can coerce a floating constant to be of
type float by adding an f or F suffix to the constant. Similarly, the suffix l or L forces the constant to be data type long double.
The table below shows the ranges available for float, double, and long double.
672
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Constants ( see page 667)
Topics
Name Description
Enumeration Constants ( see page 673) Enumeration constants are identifiers defined in enum type declarations. The
identifiers are usually chosen as mnemonics to assist legibility. Enumeration
constants are integer data types. They can be used in any expression where
integer constants are valid. The identifiers used must be unique within the scope
of the enum declaration. Negative initializers are allowed. See Enumerations and
enum (keyword) for a detailed look at enum declarations.
The values acquired by enumeration constants depend on the format of the
enumeration declaration and the presence of optional initializers. In this example,
The values acquired by enumeration constants depend on the format of the enumeration declaration and the presence of
optional initializers. In this example,
enum team { giants, cubs, dodgers };
giants, cubs, and dodgers are enumeration constants of type team that can be assigned to any variables of type team or to any
other variable of integer type. The values acquired by the enumeration constants are
673
C++ Language Guide RAD Studio 3.1 C++ Reference
Decimal
Decimal constants from 0 to 4,294,967,295 are allowed. Constants exceeding this limit are truncated. Decimal constants must
not use an initial zero. An integer constant that has an initial zero is interpreted as an octal constant. Thus,
int i = 10; /*decimal 10 */
int i = 010; /*decimal 8 */
int i = 0; /*decimal 0 = octal 0 */
Octal
All constants with an initial zero are taken to be octal. If an octal constant contains the illegal digits 8 or 9, an error is reported.
3
Octal constants exceeding 037777777777 are truncated.
Hexadecimal
All constants starting with 0x (or 0X) are taken to be hexadecimal. Hexadecimal constants exceeding 0xFFFFFFFF are truncated.
The suffix L (or l) attached to any constant forces the constant to be represented as a long. Similarly, the suffix U (or u) forces
the constant to be unsigned. It is unsigned long if the value of the number itself is greater than decimal 65,535, regardless of
674
3.1 C++ Reference RAD Studio C++ Language Guide
which base is used. You can use both L and U suffixes on the same constant in any order or case: ul, lu, UL, and so on.
The data type of a constant in the absence of any suffix (U, u, L, or l) is the first of the following types that can accommodate its
value:
If the constant has a U or u suffix, its data type will be the first of unsigned int, unsigned long int that can accommodate its
value.
If the constant has an L or l suffix, its data type will be the first of long int, unsigned long int that can accommodate its value.
If the constant has both u and l suffixes, (ul, lu, Ul, lU, uL, Lu, LU or UL), its data type will be unsigned long int.
Integer constants without L or U summarizes the representations of integer constants in all three bases. The data types indicated
assume no overriding L or U suffix has been used.
See Also
Constants ( see page 667)
675
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Internal Representation Of Numerical Types ( see page 676) 32-bit integers
676
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Constants ( see page 667)
Topics
Name Description
String Constants ( see page 677) String constants, also known as string literals, form a special category of
constants used to handle fixed sequences of characters. A string literal is of data
type array-of- const char and storage class static, written as a sequence of any
number of characters surrounded by double quotes:
The characters inside the double quotes can include escape sequences. This code, for example:
"\t\t\"Name\"\\\tAddress\n\n"
prints like this:
"Name"\ Address
"Name" is preceded by two tabs; Address is preceded by one tab. The line is followed by two new lines. The \" provides interior 3
double quotes.
If you compile with the -A option for ANSI compatibility, the escape character sequence "\\", is translated to "\" by the compiler.
A literal string is stored internally as the given sequence of characters plus a final null character ('\0'). A null string is stored as a
single '\0' character.
Adjacent string literals separated only by whitespace are concatenated during the parsing phase. In the following example,
#include <stdio.h>
677
C++ Language Guide RAD Studio 3.1 C++ Reference
int main() {
char *p;
p = "This is an example of how the compiler " " will\nconcatenate very long strings for
you" " automatically, \nresulting in nicer" " looking programs.";
printf(p);
return(0);
}
The output of the program is
This is an example of how the compiler will
concatenate very long strings for you automatically,
resulting in nicer looking programs.
You can also use the backslash (\) as a continuation character to extend a string constant across line boundaries:
puts("This is really \
a one-line string");
See Also
Constants ( see page 667)
3.1.3.5.2.2 Tokens
Tokens are word-like units recognized by a language. The compiler recognizes six classes of tokens.
• keyword
• identifier
• constant
• string-literal
3 • operator
• punctuator (also known as separators)
As the source code is scanned, tokens are extracted in such a way that the longest possible token from the character sequence
is selected. For example, external would be parsed as a single identifier, rather than as the keyword extern followed by the
identifier al.
See Token Pasting with ## for a description of token pasting.
678
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Lexical Elements ( see page 661)
Topics
Name Description
Identifiers ( see page 679) Here is the formal definition of an identifier:
identifier:
• nondigit
• identifier nondigit
• identifier digit
nondigit: one of
• abcdefghijklmnopqrstuvwxyz_
• ABCDEFGHIJKLMNOPQRSTUVWXYZ
digit: one of
• 01234
• ef5 6 7 8 9
Naming and length restrictions
Identifiers are arbitrary names of any length given to classes,
objects, functions, variables,... more ( see page 679)
3.1.3.5.2.3.1 Identifiers
Here is the formal definition of an identifier:
identifier:
• nondigit
• identifier nondigit
• identifier digit
nondigit: one of
• abcdefghijklmnopqrstuvwxyz_
• ABCDEFGHIJKLMNOPQRSTUVWXYZ
digit: one of
• 01234 3
• ef5 6 7 8 9
Naming and length restrictions
Identifiers are arbitrary names of any length given to classes, objects, functions, variables, user-defined data types, and so on.
(Identifiers can contain the letters a to z and A to Z, the underscore character "_", and the digits 0 to 9.) There are only two
restrictions:
• The first character must be a letter or an underscore.
679
C++ Language Guide RAD Studio 3.1 C++ Reference
• By default, the compiler recognizes only the first 250 characters as significant. The number of significant characters can be
reduced by menu and command-line options, but not increased. To change the significant character length, use the spin
control in Project|Options|Advanced Compiler|Source|Identifier Length.
Case sensitivity
Identifiers in C and C++ are case sensitive, so that Sum, sum and suM are distinct identifiers.
Global identifiers imported from other modules follow the same naming and significance rules as normal identifiers. However,
you have the option of suspending case sensitivity to allow compatibility when linking with case-insensitive languages. With
the case-insensitive option, the globals Sum and sum are considered identical, resulting in a possible. "Duplicate symbol"
warning during linking.
An exception to these rules is that identifiers of type __pascal are always converted to all uppercase for linking purposes.
Uniqueness and scope
Although identifier names are arbitrary (within the rules stated), errors result if the same name is used for more than one
identifier within the same scope and sharing the same name space. Duplicate names are legal for different name spaces
regardless of scope rules.
Topics
Name Description
Keywords ( see page 680) Keywords are words reserved for special purposes and must not be used as
normal identifier names.
If you use non-ANSI keywords in a program and you want the program to be
ANSI compliant, always use the non-ANSI keyword versions that are prefixed
with double underscores. Some keywords have a version prefixed with only one
underscore; these keywords are provided to facilitate porting code developed
with other compilers. For ANSI-specified keywords there is only one version.
Note: Note that the keywords __try
and try are an exception to the discussion above. The keyword try is required to
match the catch keyword... more ( see page 680)
Keyword Extensions ( see page 681) CodeGear C++Builder provides a number of keywords that are not part of the
ANSI Standard.
Please see the Help table of contents for a complete categorical and alphabetical
listing of Library Routines.
C++-Specific Keywords ( see page 681) A number of keywords are specific to C++ and are not available if you are writing
a program in C only. Please see the Help table of contents for a complete
categorical and alphabetical listing of these and other keywords.
Table Of CodeGear C++ Register Pseudovariables ( see page 681) This table lists all pseudovariables.
3.1.3.5.2.4.1 Keywords
Keywords are words reserved for special purposes and must not be used as normal identifier names.
If you use non-ANSI keywords in a program and you want the program to be ANSI compliant, always use the non-ANSI keyword
versions that are prefixed with double underscores. Some keywords have a version prefixed with only one underscore; these
keywords are provided to facilitate porting code developed with other compilers. For ANSI-specified keywords there is only one
version.
3
Note: Note that the keywords __try
and try are an exception to the discussion above. The keyword try is required to match the catch keyword in the C++
exception-handling mechanism. try cannot be substituted by __try. The keyword __try can only be used to match the __except
or __finally keywords. See the discussions on C++ exception handling and C-based structured exceptions under Win32 for
more information. Please see the Help table of contents for a complete categorical and alphabetical listing of keywords.
680
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Alphabetical Listing of Keywords ( see page 513)
Please see the Help table of contents for a complete categorical and alphabetical listing of Library Routines.
See Also
C++Builder Keyword Extensions ( see page 580)
See Also
Alphabetical Listing of Keywords ( see page 513)
All but the _FLAGS and _EFLAGS register pseudovariables are associated with the general purpose, segment, address, and
special purpose registers.
Use register pseudovariables anywhere that you can use an integer variable to directly access the corresponding 80x86 register.
3
The flags registers contain information about the state of the 80x86 and the results of recent instructions.
681
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Punctuators ( see page 682) The C++ punctuators (also known as separators) are:
• []
• ()
• {}
• ,
• ;
• :
• ...
• =
• #
Most of these punctuators also function as operators.
Brackets
Open and close brackets indicate single and
multidimensional array subscripts:
3.1.3.5.2.5.1 Punctuators
The C++ punctuators (also known as separators) are:
• []
• ()
• {}
• ,
• ;
• :
• ...
• =
• #
Most of these punctuators also function as operators.
Brackets
Open and close brackets indicate single and multidimensional array subscripts:
char ch, str[] = "Stan";
int mat[3][4]; /* 3 x 4 matrix */
ch = str[3]; /* 4th element */
.
3 .
.
Parentheses
Open and close parentheses ( ) are used to group expressions, isolate conditional expressions, and indicate function calls and
function parameters:
d = c * (a + b);/* override normal precedence */
if (d == z) ++x;/* essential with conditional statement */
682
3.1 C++ Reference RAD Studio C++ Language Guide
Braces
Open and close braces { } indicate the start and end of a compound statement:
if (d == z)
{
++x;
func();
}
The closing brace serves as a terminator for the compound statement, so a ; (semicolon) is not required after the }, except in
structure or class declarations. Often, the semicolon is illegal, as in
if (statement)
{}; /* illegal semicolon */
else
Comma
The semicolon (;) is a statement terminator. Any legal C or C++ expression (including the empty expression) followed by a
semicolon is interpreted as a statement, known as an expression statement. The expression is evaluated and its value is
discarded. If the expression statement has no side effects, the compiler might ignore it.
a + b; /* maybe evaluate a + b, but discard value */
++a; /* side effect on a, but discard value of ++a */
; /* empty expression = null statement */
Semicolons are often used to create an empty statement:
for (i = 0; i < n; i++)
{
;
}
Colon
3
Use the colon (:) to indicate a labeled statement:
start: x=0;
...
goto start;
Labels are discussed in Labeled statements.
Ellipsis
The ellipsis
683
C++ Language Guide RAD Studio 3.1 C++ Reference
(...) is three successive periods with no intervening whitespace. Ellipses are used in the formal argument lists of function
prototypes to indicate a variable number of arguments, or arguments with varying types:
void func(int n, char ch,...);
This declaration indicates that func will be defined in such a way that calls must have at least two arguments, an int and a char,
but can also have any number of additional arguments.
The asterisk (*) in a variable declaration denotes the creation of a pointer to a type:
char *char_ptr; /* a pointer to char is declared */
Pointers with multiple levels of indirection can be declared by indicating a pertinent number of asterisks:
int **int_ptr; /* a pointer to an integer array */
double ***double_ptr; /* a pointer to a matrix of doubles */
You can also use the asterisk as an operator to either dereference a pointer or as the multiplication operator:
i = *int_ptr;
a = b * 3.14;
Equal sign (initializer)
The equal sign (=) separates variable declarations from initialization lists:
char array[5] = { 1, 2, 3, 4, 5 };
int x = 5;
In C++, declarations of any type can appear (with some restrictions) at any point within the code. In a C function, no code can
precede any variable declarations.
In a C++ function argument list, the equal sign indicates the default value for a parameter:
int f(int i = 0) { ... } /* Parameter i has default value of zero */
The equal sign is also used as the assignment operator in expressions:
int a, b, c;
a = b + c;
float *ptr = (float *) malloc(sizeof(float) * 100);
Pound sign (preprocessor directive)
The pound sign (#) indicates a preprocessor directive when it occurs as the first nonwhitespace character on a line. It signifies a
compiler action, not necessarily associated with code generation. See Preprocessor directives for more on the preprocessor
directives.
# and ## (double pound signs) are also used as operators to perform token replacement and merging during the preprocessor
scanning phase. See Token pasting.
3
3.1.3.5.3 Whitespace Overview
This section contains Whitespace Overview topics.
684
3.1 C++ Reference RAD Studio C++ Language Guide
Topics
Name Description
Comments ( see page 685) Comments are pieces of text used to annotate a program. Comments are for the
programmer's use only; they are stripped from the source text before parsing.
There are two ways to delineate comments: the C method and the C++ method.
The compiler supports both methods, and provides an additional, optional
extension permitting nested comments. If you are not compiling for ANSI
compatibility, you can use any of these kinds of comments in both C and C++
programs.
You should also follow the guidelines on the use of whitespace and delimiters in
comments discussed later in this topic to avoid other... more ( see page 685)
Whitespace ( see page 686) Whitespace is the collective name given to spaces (blanks), horizontal and
vertical tabs, newline characters, and comments. Whitespace can serve to
indicate where tokens start and end, but beyond this function, any surplus
whitespace is discarded. For example, the two sequences
3.1.3.5.3.1 Comments
Comments are pieces of text used to annotate a program. Comments are for the programmer's use only; they are stripped from
the source text before parsing.
There are two ways to delineate comments: the C method and the C++ method. The compiler supports both methods, and
provides an additional, optional extension permitting nested comments. If you are not compiling for ANSI compatibility, you can
use any of these kinds of comments in both C and C++ programs.
You should also follow the guidelines on the use of whitespace and delimiters in comments discussed later in this topic to avoid
other portability problems.
C comments
A C comment is any sequence of characters placed after the symbol pair /*. The comment terminates at the first occurrence of
the pair */ following the initial /*. The entire sequence, including the four comment-delimiter symbols, is replaced by one space
after macro expansion. Note that some C implementations remove comments without space replacements.
The compiler does not support the nonportable token pasting strategy using /**/. Token pasting is performed with the
ANSI-specified pair ##, as follows:
#define VAR(i,j) (i/**/j) /* won't work */
#define VAR(i,j) (i##j) /* OK */
#define VAR(i,j) (i ## j) /* Also OK */
The compiler parses the declaration,
int /* declaration */ i /* counter */;
as these three tokens:
int i;
See Token Pasting with ## for a description of token pasting.
C++ comments
C++ allows a single-line comment using two adjacent slashes (//). The comment can start in any position, and extends until the
next new line: 3
class X { // this is a comment
... };
You can also use // to create comments in C code. This feature is specific to the CodeGear C++ compiler and is generally not
portable.
Nested comments
ANSI C doesn't allow nested comments. The attempt to comment out a line
685
C++ Language Guide RAD Studio 3.1 C++ Reference
In rare cases, some whitespace before /* and //, and after */, although not syntactically mandatory, can avoid portability
problems. For example, this C++ code:
int i = j//* divide by k*/k;
+m;
parses as int i = j +m; not as
int i = j/k;
+m;
as expected under the C convention. The more legible
int i = j/ /* divide by k*/ k;
+m;
avoids this problem.
See Also
Lexical Elements ( see page 661)
3.1.3.5.3.2 Whitespace
Whitespace is the collective name given to spaces (blanks), horizontal and vertical tabs, newline characters, and comments.
Whitespace can serve to indicate where tokens start and end, but beyond this function, any surplus whitespace is discarded. For
example, the two sequences
int i; float f;
and
int i;
float f;
are lexically equivalent and parse identically to give the six tokens:
• int
• i
• ;
3 • float
• f
• ;
The ASCII characters representing whitespace can occur within literal strings, in which case they are protected from the normal
parsing process (they remain as part of the string). For example,
char name[] = "CodeGear Corporation";
parses to seven tokens, including the single literal-string token "CodeGear Corporation"
686
3.1 C++ Reference RAD Studio C++ Language Guide
A special case occurs if the final newline character encountered is preceded by a backslash (\). The backslash and new line are
both discarded, allowing two physical lines of text to be treated as one unit.
"CodeGear \
Corporation"
is parsed as "CodeGear Corporationl" (see String constants for more information).
See Also
Lexical Elements ( see page 661)
Topics
Name Description
Conditional Compilation Overview ( see page 687) This section contains Conditional Compilation Overview topics.
Defining And Undefining Macros ( see page 689) This section contains Defining And Undefining Macro topics.
The #error Control Directive ( see page 691) This section contains #error Control Directive topics.
File Inclusion With #include ( see page 692) This section contains File Inclusion With #include topics.
The #line Control Directive ( see page 693) This section contains #line Control Directive topics.
Macros With Parameters Overview ( see page 694) This section contains Macros With Parameters Overview topics.
Pragma Directives Overview ( see page 696) This section contains Pragma Directives Overview topics.
Predefined Macros Overview ( see page 707) This section contains Predefined Macros Overview topics.
Preprocessor Directives ( see page 710) This section contains C++ Preprocessor Directive topics.
Topics
Name Description
Conditional Compilation ( see page 687) The compiler supports conditional compilation by replacing the appropriate
source-code lines with a blank line. The lines thus ignored are those beginning
with # (except the #if, #ifdef, #ifndef, #else, #elif, and #endif directives), as well
as any lines that are not to be compiled as a result of the directives. All
conditional compilation directives must be completed in the source or include file
in which they are begun.
#if, #elif, #else, And #endif ( see page 688) Syntax
#ifdef And #ifndef ( see page 688) Syntax
Defined ( see page 689) Syntax
687
C++ Language Guide RAD Studio 3.1 C++ Reference
The compiler supports conditional compilation by replacing the appropriate source-code lines with a blank line. The lines thus
ignored are those lines that are not to be compiled as a result of the directives. All conditional compilation directives must be
completed in the source or include file in which they are begun.
The conditional directives #if, #elif, #else, and #endif work like the normal C conditional operators. If the constant-expression-1
(subject to macro expansion) evaluates to nonzero (true), the lines of code (possibly empty) represented by section-1, whether
preprocessor command lines or normal source lines, are preprocessed and, as appropriate, passed to the compiler. Otherwise, if
constant-expression-1 evaluates to zero (false), section-1 is ignored (no macro expansion and no compilation).
In the true case, after section-1 has been preprocessed, control passes to the matching #endif (which ends this conditional
sequence) and continues with next-section. In the false case, control passes to the next #elif line (if any) where
constant-expression-2 is evaluated. If true, section-2 is processed, after which control moves on to the matching #endif.
Otherwise, if constant-expression-2 is false, control passes to the next #elif, and so on, until either #else or #endif is reached.
The optional #else is used as an alternative condition for which all previous tests have proved false. The #endif ends the
conditional sequence.
The processed section can contain further conditional clauses, nested to any depth; each #if must be matched with a closing
#endif.
The net result of the preceding scenario is that only one section (possibly empty) is passed on for further processing. The
bypassed sections are relevant only for keeping track of any nested conditionals, so that each #if can be matched with its correct
#endif.
See Also
defined ( see page 689)
The #ifdef and #ifndef conditional directives let you test whether an identifier is currently defined or not; that is, whether a
previous #define command has been processed for that identifier and is still in force. The line
#ifdef identifier
688
3.1 C++ Reference RAD Studio C++ Language Guide
The syntax thereafter follows that of the #if, #elif, #else, and #endif.
3.1.3.6.1.4 Defined
Syntax
#if defined[(] <identifier> [)]
#elif defined[(] <identifier> [)]
Description
Use the defined operator to test if an identifier was previously defined using #define. The defined operator is only valid in #if
and #elif expressions.
Defined evaluates to 1 (true) if a previously defined symbol has not been undefined (using #undef); otherwise, it evaluates to 0
(false).
689
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Using The -D And -U Command-line Options ( see page 690) Identifiers can be defined and undefined using the command-line compiler
options -D and -U.
The command line
Keywords And Protected Words In Macros ( see page 690) It is legal but ill-advised to use C++ keywords as macro identifiers:
#define ( see page 690) Syntax
#undef ( see page 691) Syntax
See Also
#define ( see page 690)
3.1.3.6.2.3 #define
Syntax
#define macro_identifier <token_sequence>
Description
The #define directive defines a macro. Macros provide a mechanism for token replacement with or without a set of formal,
function-like parameters.
3 Each occurrence of macro_identifier in your source code following this control line will be replaced in the original position with
the possibly empty token_sequence (there are some exceptions, which are noted later). Such replacements are known as
macro expansions. The token sequence is sometimes called the body of the macro.
An empty token sequence results in the removal of each affected macro identifier from the source code.
After each individual macro expansion, a further scan is made of the newly expanded text. This allows for the possibility of
nested macros: The expanded text can contain macro identifiers that are subject to replacement. However, if the macro expands
into what looks like a preprocessing directive, the directive will not be recognized by the preprocessor. There are these
690
3.1 C++ Reference RAD Studio C++ Language Guide
• Any occurrences of the macro identifier found within literal strings, character constants, or comments in the source code are
not expanded.
• A macro won't be expanded during its own expansion (so #define A A won't expand indefinitely).
Example
#define HI "Have a nice day!"
#define empty
See Also
Keywords And Protected Words In Macros ( see page 690)
3.1.3.6.2.4 #undef
Syntax
#undef macro_identifier
Description
You can undefine a macro using the #undef directive. #undef detaches any previous token sequence from the macro identifier;
the macro definition has been forgotten, and the macro identifier is undefined. No macro expansion occurs within #undef lines.
The state of being defined or undefined turns out to be an important property of an identifier, regardless of the actual definition.
The #ifdef and #ifndef conditional directives, used to test whether any identifier is currently defined or not, offer a flexible
mechanism for controlling many aspects of a compilation.
After a macro identifier has been undefined, it can be redefined with #define, using the same or a different token sequence.
Attempting to redefine an already defined macro identifier will result in a warning unless the new definition is exactly the same
token-by-token definition as the existing one. The preferred strategy where definitions might exist in other header files is as
follows:
#ifndef BLOCK_SIZE
#define BLOCK_SIZE 512
The middle line is bypassed if BLOCK_SIZE is currently defined; if BLOCK_SIZE is not currently defined, the middle line is
invoked to define it.
No semicolon (;) is needed to terminate a preprocessor directive. Any character found in the token sequence, including
semicolons, will appear in the macro expansion. The token sequence terminates at the first non-backslashed new line
encountered. Any sequence of whitespace, including comments in the token sequence, is replaced with a single-space character.
See Also
#define ( see page 690) 3
Preprocessor Directives ( see page 710)
691
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
#error ( see page 692) Syntax
3.1.3.6.3.1 #error
Syntax
#error errmsg
Description
Topics
Name Description
#include ( see page 692) Syntax
Header File Search With <header_name> ( see page 693) The <header_name> version specifies a standard include file; the search is made
successively in each of the include directories in the order they are defined. If the
file is not located in any of the default directories, an error message is issued.
Header File Search With "header_name" ( see page 693) The "header_name" version specifies a user-supplied include file; the file is
searched in the following order:
3.1.3.6.4.1 #include
Syntax
#include <header_name>
#include "header_name"
#include <macro_definition>
Description
3 The #include directive pulls in other named files, known as include files, header files, or headers, into the source code. The
syntax has three versions:
• The first and second versions imply that no macro expansion will be attempted; in other words, header_name is never
scanned for macro identifiers. header_name must be a valid file name with an extension (traditionally .h for header) and
optional path name and path delimiters.
• The third version assumes that neither < nor " appears as the first non-whitespace character following #include; further, it
assumes a macro definition exists that will expand the macro identifier into a valid delimited header name with either of the
<header_name> or "header_name" formats.
692
3.1 C++ Reference RAD Studio C++ Language Guide
The preprocessor removes the #include line and conceptually replaces it with the entire text of the header file at that point in the
source code. The source code itself is not changed, but the compiler "sees" the enlarged text. The placement of the #include
can therefore influence the scope and duration of any identifiers in the included file.
If you place an explicit path in the header_name, only that directory will be searched.
The difference between the <header_name> and "header_name" formats lies in the searching algorithm employed in trying to
locate the include file.
See Also
Header File Search with <header_name> ( see page 693)
See Also
Header File Search With "header_name" ( see page 693)
1. The same directory of the file that contains the #include statement
2. The directories of files that include (#include) that file
3. The current directory
4. The path specified by the /I compiler option
See Also
Header File Search With <header_name> ( see page 693)
Topics
Name Description
#line ( see page 693) Syntax
3.1.3.6.5.1 #line
Syntax
#line integer_constant <"filename">
3
Description
You can use the #line directive to supply line numbers to a program for cross-reference and error reporting. If your program
consists of sections derived from some other program file, it is often useful to mark such sections with the line numbers of the
original source rather than the normal sequential line numbers derived from the composite program.
The #line directive indicates that the following source line originally came from line number integer_constant of filename. Once
the filename has been registered, subsequent #line commands relating to that file can omit the explicit filename argument.
693
C++ Language Guide RAD Studio 3.1 C++ Reference
Macros are expanded in #line arguments as they are in the #include directive.
The #line directive is primarily used by utilities that produce C code as output, and not in human-written code.
Topics
Name Description
Macros With Parameters ( see page 694) The following syntax is used to define a macro with parameters:
Nesting Parentheses And Commas ( see page 695) The actual_arg_list can contain nested parentheses provided that they are
balanced; also, commas appearing within quotes or parentheses are not treated
like argument delimiters.
Token Pasting With ## ( see page 695) You can paste (or merge) two tokens together by separating them with ## (plus
optional whitespace on either side). The preprocessor removes the whitespace
and the ##, combining the separate tokens into one new token. You can use this
to construct identifiers.
Given the definition
Converting To Strings With # ( see page 695) The # symbol can be placed in front of a formal macro argument in order to
convert the actual argument to a string after replacement.
Given the following definition:
Using The Backslash (\) For Line Continuation ( see page 695) A long token sequence can straddle a line by using a backslash (\). The
backslash and the following newline are both stripped to provide the actual token
sequence used in expansions.
Side Effects And Other Dangers ( see page 696) The similarities between function and macro calls often obscure their differences.
A macro call has no built-in type checking, so a mismatch between formal and
actual argument data types can produce bizarre, hard-to-debug results with no
immediate warning. Macro calls can also give rise to unwanted side effects,
especially when an actual argument is evaluated more than once.
Compare CUBE and cube in the following example.
Note there can be no whitespace between the macro identifier and the (. The optional arg_list is a sequence of identifiers
separated by commas, not unlike the argument list of a C function. Each comma-delimited identifier plays the role of a formal
argument or placeholder.
The optional actual_arg_list must contain the same number of comma-delimited token sequences, known as actual arguments,
as found in the formal arg_list of the #define line: There must be an actual argument for each formal argument. An error will be
3 reported if the number of arguments in the two lists is different.
A macro call results in two sets of replacements. First, the macro identifier and the parenthesis-enclosed arguments are replaced
by the token sequence. Next, any formal arguments occurring in the token sequence are replaced by the corresponding real
arguments appearing in the actual_arg_list.
As with simple macro definitions, rescanning occurs to detect any embedded macro identifiers eligible for expansion.
694
3.1 C++ Reference RAD Studio C++ Language Guide
See Also
Converting To Strings With # ( see page 695)
Using The Backslash (\) For Line Continuation ( see page 695)
695
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
#pragma ( see page 696) Syntax
#pragma alignment ( see page 698) Syntax
#pragma anon_struct ( see page 698) Syntax
#pragma argsused ( see page 699) Syntax
#pragma checkoption ( see page 699) Syntax
#pragma codeseg ( see page 699) Syntax
#pragma comment ( see page 699) Syntax
#pragma defineonoption and #pragma undefineonoption ( see page 700) Syntax
#pragma exit and #pragma startup ( see page 700) Syntax
#pragma hdrfile ( see page 700) Syntax
#pragma hdrstop ( see page 701) Syntax
#pragma inline ( see page 701) Syntax
#pragma intrinsic ( see page 701) Syntax
#pragma link ( see page 701) Syntax
#pragma message ( see page 702) Syntax
#pragma nopushoptwarn ( see page 702) Syntax
#pragma obsolete ( see page 702) Syntax
#pragma option ( see page 703) Syntax
#pragma pack ( see page 704) Syntax
#pragma package ( see page 706) Syntax
#pragma region and #pragma end_region ( see page 707) Syntax
#pragma resource ( see page 707) Syntax
#pragma warn ( see page 707) Syntax
3.1.3.6.7.1 #pragma
3 Syntax
#pragma directive-name
Description
With #pragma, you can set compiler directives in your source code, without interfering with other compilers that also support
#pragma. If the compiler doesn't recognize directive-name, it ignores the #pragma directive without any error or warning
message.
The CodeGear C++ supports the following #pragma directives: (Links to these topics are at the bottom of this topic.)
696
3.1 C++ Reference RAD Studio C++ Language Guide
• #pragma alignment
• #pragma anon_struct
• #pragma argsused
• #pragma checkoption
• #pragma codeseg
• #pragma comment
• #pragma defineonoption
• #pragma exit
• #pragma hdrfile
• #pragma hdrstop
• #pragma inline
• #pragma intrinsic
• #pragma link
• #pragma message
• #pragma nopushoptwarn
• #pragma obsolete
• #pragma option
• #pragma pack
• #pragma package
• #pragma region/end_region
• #pragma resource
• #pragma startup
• #pragma undefineonoption
• #pragma warn
See Also
#pragma alignment ( see page 698)
697
C++ Language Guide RAD Studio 3.1 C++ Reference
This pragma prints out the current byte alignment and enum size.
The anon_struct directive allows you to compile anonymous structures embedded in classes.
#pragma anon_struct on
struct S {
int i;
3 struct { // Embedded anonymous struct
int j ;
float x ;
};
class { // Embedded anonymous class
public:
long double ld;
};
S() { i = 1; j = 2; x = 3.3; ld = 12345.5;}
};
#pragma anon_struct off
698
3.1 C++ Reference RAD Studio C++ Language Guide
void main()
{
S mystruct;
mystruct.x = 1.2; // Assign to embedded data.
}
The argsused pragma is allowed only between function definitions, and it affects only the next function. It disables the warning
message:
"Parameter name is never used in function func-name"
Description
Error E2471 filename: pragma checkoption failed: options are not as expected
The codeseg directive lets you name the segment, class, or group where functions are allocated. If the pragma is used without
any of its options, the default code segment is used for function allocation.
The comment directive lets you write a comment record into an output file. The comment type can be one of the following
values:
Value Explanation
exestr The linker writes string into an .obj file. Your specified string is placed in the executable file. Such a string is never
loaded into memory but can be found in the executable file by use of a suitable file search utility.
699
C++ Language Guide RAD Studio 3.1 C++ Reference
lib Writes a comment record into an .obj file. A library module that is not specified in the linker's response-file can be
specified by the comment LIB directive. The linker includes the library module name specified in string as the last
library. Multiple modules can be named and linked in the order in which they are named.
user The compiler writes string into the .obj file. The linker ignores the specified string.
Description
The pragma #pragma defineonoption defines a macro name when specified options are set. The macro name is defined if
all the switches in are turned on, either from the command line or through a pragma.
The pragma #pragma undefineonoption undefines a macro name when specified options are set.
These two pragmas allow the program to specify function(s) that should be called either upon program startup (before the main
function is called), or program exit (just before the program terminates through _exit).
The specified function-name must be a previously declared function taking no arguments and returning void; in other words, it
should be declared as:
void func(void);
The optional priority parameter should be an integer in the range 64 to 255. The highest priority is 0. Functions with higher
3 priorities are called first at startup and last at exit. If you don't specify a priority, it defaults to 100.
Warning: Do not use priority values less than 64. Priorities from 0 to 63 are reserved for ISO startup and shutdown
mechanisms.
700
3.1 C++ Reference RAD Studio C++ Language Guide
This directive sets the name of the file in which to store precompiled headers.
If you aren't using precompiled headers, this directive has no effect. You can use the command-line compiler option -H=filename
or Use Precompiled Headers to change the name of the file used to store precompiled headers.
This directive terminates the list of header files eligible for precompilation. You can use it to reduce the amount of disk space
used by precompiled headers.
Precompiled header files can be shared between the source files of your project only if the #include directives before #pragma
hdrstop are identical. Therefore, you get the best compiler performance if you include common header files of your project
before the #pragma hdrstop, and specific ones after it. Make sure the #include directives before the #pragma hdrstop are
identical in all the source files, or that there are only very few variations.
The integrated development environment generates code to enhance precompiled header performance. For example, after a
New Application, source file "Unit1.cpp" will look like this (comments added):
#include <clxvcl.h> // common header file
#pragma hdrstop // terminate list here
Use this pragma directive only in source files. The pragma has no effect when it is used in a header file.
This is best placed at the top of the file, because the compiler restarts itself with the -B option when it encounters #pragma
inline.
When inlining an intrinsic function, always include a prototype for that function before using it.
701
C++ Language Guide RAD Studio 3.1 C++ Reference
Description
The directive instructs the linker to link the file into an executable file.
By default, the linker searches for modulename in the local directory and any path specified by the -L option. You can use the
path argument to specify a directory.
Use #pragma message to specify a user-defined message within your program code.
The first form requires that the text consist of one or more string constants, and the message must be enclosed in parentheses.
(This form is compatible with Microsoft C.) This form will output the constant contained between the double quotes regardless of
whether it is a macro or not.
The second form uses the text following the #pragma for the text of the warning message. With this form of the #pragma, any
macro references are expanded before the message is displayed.
The third form will output the macro-expanded value of text following the #pragma, if it is #defined. If is not #defined, you'll get
an ill-formed pragma warning.
Display of user-defined messages is on by default and can be turned on or off with the Show Messages option. This option
corresponds to the compiler's -wmsg switch.
Messages are only displayed in the IDE if Show general messages is checked on the C++ Project Properties under
Project Options Project Propertes.
See Also
Preprocessor Directives ( see page 710)
The nopushoptwarn pragma allows the use of pragma option push without pop and pragma option pop without push // in a file.
Normally a warning would be given.
3
3.1.3.6.7.17 #pragma obsolete
Syntax
#pragma obsolete identifier
Description
Use #pragma obsolete to give a warning the first time the preprocessor encounters identifier in your program code after the
702
3.1 C++ Reference RAD Studio C++ Language Guide
Use #pragma option to include command-line options within your program code. #pragma option can also be used with the
push or pop arguments.
options can be any command-line option (except those listed in the following paragraph). Any number of options can appear in
one directive. For example, both of the following are valid:
#pragma option -C
#pragma option -C -A
Any of the toggle options (such as -a or -K) can be turned on and off as on the command line. For these toggle options, you can
also put a period following the option to return the option to its command-line, configuration file, or option-menu setting. This
allows you to temporarily change an option, and then return it to its default, without having to remember (or even needing to
know) what the exact default setting was.
B c dname
Dname=string efilename E
Fx h Ifilename
lexset M o
P Q S
T Uname V
X Y
• You can use #pragmas, #includes, #define, and some #ifs in the following cases:
• Before the use of any macro name that begins with two underscores (and is therefore a possible built-in macro) in an #if,
#ifdef, #ifndef or #elif directive.
• Before the occurrence of the first real token (the first C or C++ declaration).
Certain command-line options can appear only in a #pragma option command before these events. These options are:
Efilename f i#
m* npath ofilename 3
U W z
*
Other options can be changed anywhere. The following options will only affect the compiler if they get changed between
functions or object declarations:
703
C++ Language Guide RAD Studio 3.1 C++ Reference
1 h r
2 k rd
A N v
Ff O y
G p Z
The following options can be changed at any time and take effect immediately:
A gn zE
b jn zF
C K zH
d wxxx
The options can appear followed by a dot (.) to reset the option to its command-line state.
The #pragma option directive can also be used with the push and pop arguments to enable you to easily modify compiler
directives.
Using the #pragma option push allows you to save all (or a selected subset of) options before including any files that could
potentially change many compiler options and warnings, and then, with the single statement, #pragma option pop, return to the
previous state. For example:
#pragma option push
#include <theworld.h>
#pragma option pop
#include "mystuff.h"
The #pragma option push directive first pushes all compiler options and warning settings on a stack and then handles any
options (if supplied). The following examples show how the #pragma option push can be used with or without options:
#pragma option push -C -A
#pragma option push
The #pragma option pop directive changes compiler options and warnings by popping the last set of options and warnings from
the stack. It gives a warning, "Pragma option pop with no matching option push", if the stack is empty, in which case nothing
happens.
If you try to specify any options after pop, you get the error, "Nothing allowed after pragma option pop." For example, the
3 following produces an error:
#pragma option pop -C/* ERROR */
If your stack of pushed options is not the same at the start of a file as at the end of a file, you receive a warning: "Previous
options and warnings not restored." To turn off this warning, use the directive, #pragma nopushoptwarn .
704
3.1 C++ Reference RAD Studio C++ Language Guide
The #pragma pack(n).directive is the same as using the #pragma option specifically with the -a compiler option. n is the byte
alignment that determines how the compiler aligns data in stored memory. For more information see the -a compiler option.
#pragma pack can also be used with push and pop arguments, which provide the same functionality as the #pragma option
directive using push and pop. The following table compares the use of #pragma pack with #pragma option.
The #pragma pack directive also supports an identifier argument which must be used in combination with either push or pop.
705
C++ Language Guide RAD Studio 3.1 C++ Reference
Error conditions
Warning conditions
The #pragma package(smart_init) assures that packaged units are initialized in the order determined by their dependencies.
(Included by default in package source file.) Typically, you would use the #pragma package for .cpp files that are built as
packages.
This pragma affects the order of initialization of that compilation unit. For units, initialization occurs in the following order:
• 1. By their "uses" dependencies, that is, if unitA depends on unitB, unitB must be initialized before unitA.
• 2. The link order.
• 3. Priority order within the unit.
For regular object files (those not built as units), initialization happens first according to priority order and then link order.
Changing the link order of the object files changes the order in which the global object constructors get called.
The following examples show how the initialization differs between units and regular object files.
Take as an example three unit files, A, B and C that are "smart initialized" with #pragma package(smart_init) and have priority
values (defined by the priority parameter of the #pragma startup) set of 10, 20 and 30. The functions are named according to
their priority value and the parent object file, so the names are a10, a20, a30, b10, and so on.
Since all three are units, and if A uses B and C and the link order is A, B then C, the order of initialization is:
B10 B20 B30 C10 C20 C30 A10 A20 A30
3 If the above were object files, not units, the order would be:
A10 B10 C10 A20 B20 C20 A30 B30 C30
The .cpp files that use #pragma package(smart_init) also require that any #pragma link references to other object files from a
.cpp file that declares #pragma package(smart_init), must be resolved by a unit. #pragma link references to non object files
can still be resolved by libraries, etc.
Description: weak packages
The #pragma package(smart_init, weak) directive affects the way an object file is stored in a package’s .bpi and .bpl files. If
#pragma package(smart_init, weak) appears in a unit file, the compiler omits the unit from BPLs when possible, and creates
706
3.1 C++ Reference RAD Studio C++ Language Guide
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".
#pragma package(smart_init, weak) is used to eliminate conflicts among packages that may depend on the same external
library.
Unit files containing the #pragma package(smart_init, weak) directive must not have global variables.
For more information about using weak packages, see Weak packaging.
See Also
Preprocessor Directives ( see page 710)
These two pragmas allow the program to specify a region that can be collapsed and expanded, similar to the facility
automatically provided for functions.
This pragma causes the file to be marked as a form unit and requires matching .dfm and header files. All such files are managed
by the IDE.
If your form requires any variables, they must be declared immediately after the pragma resource is used. The declarations must
be of the form
TFormName *Formname;
707
C++ Language Guide RAD Studio 3.1 C++ Reference
Topics
Name Description
Predefined Macros ( see page 708) The compiler predefines certain global identifiers, known as manifest constants.
Most global identifiers begin and end with two underscores (__).
Note: For readability, underscores are often separated by a single blank space.
In your source code, you should never insert whitespace between underscores.
Note: For readability, underscores are often separated by a single blank space. In your source code, you should never insert
whitespace between underscores.
708
3.1 C++ Reference RAD Studio C++ Language Guide
709
C++ Language Guide RAD Studio 3.1 C++ Reference
See Also
Side Effects And Other Dangers ( see page 696)
Using The Backslash (\) For Line Continuation ( see page 695)
Topics
Name Description
Preprocessor Directives ( see page 710) Preprocessor directives are usually placed at the beginning of your source code,
but they can legally appear at any point in a program. The preprocessor detects
preprocessor directives (also known as control lines) and parses the tokens
embedded in them. The preprocessor supports these directives:
# (null Directive) ( see page 711) Syntax
3
3.1.3.6.9.1 Preprocessor Directives
Preprocessor directives are usually placed at the beginning of your source code, but they can legally appear at any point in a
program. The preprocessor detects preprocessor directives (also known as control lines) and parses the tokens embedded in
them. The preprocessor supports these directives:
710
3.1 C++ Reference RAD Studio C Runtime Library Reference
Any line with a leading # is taken as a preprocessing directive, unless the # is within a string literal, in a character constant, or
embedded in a comment. The initial # can be preceded or followed by whitespace (excluding new lines).
The null directive consists of a line containing the single character #. This line is always ignored.
Note: In the online help, each function, macro, and class in the C Runtime Library is listed only once . However, some functions,
macros, and classes are defined in more than one header file.
For example, _strerror is defined in both string.h and stdio.h. For functions that are defined in several header files, the online
help assigns the function to the first header file in alphabetic order. Thus, you will find _strerror listed in the help in stdio.h but
not in string.h.
To find a function, macro, or class that is not listed in a header file in which you expect it, please use the help Index.
Topics
Name Description
alloc.h ( see page 712) The following functions, macros, and classes are provided in alloc.h:
assert.h ( see page 730) The following functions, macros, and classes are provided in assert.h:
conio.h ( see page 732) The following functions, macros, and classes are provided in conio.h:
ctype.h ( see page 766) The following functions, macros, and classes are provided in ctype.h:
delayimp.h ( see page 787) The following functions, macros, and classes are provided in delayimp.h:
3
direct.h ( see page 790) The following functions, macros, and classes are provided in direct.h:
dirent.h ( see page 792) The following functions, macros, and classes are provided in dirent.h:
dir.h ( see page 799) The following functions, macros, and classes are provided in dir.h:
dos.h ( see page 818) The following functions, macros, and classes are provided in dos.h:
errno.h ( see page 831) The following functions, macros, and classes are provided in errno.h:
except.h ( see page 838) The following functions, macros, and classes are provided in except.h:
fastmath.h ( see page 842) The following functions, macros, and classes are provided in fastmath.h:
711
C Runtime Library Reference RAD Studio 3.1 C++ Reference
fcntl.h ( see page 844) The following functions, macros, and classes are provided in fcntl.h:
float.h ( see page 853) The following functions, macros, and classes are provided in float.h:
io.h ( see page 864) The following functions, macros, and classes are provided in io.h:
limits.h ( see page 913) The following functions, macros, and classes are provided in limits.h:
locale.h ( see page 915) The following functions, macros, and classes are provided in locale.h:
malloc.h ( see page 920) The following functions, macros, and classes are provided in malloc.h:
math.h ( see page 921) The following functions, macros, and classes are provided in math.h:
mem.h ( see page 959) The following functions, macros, and classes are provided in mem.h:
new.h ( see page 968) The following functions, macros, and classes are provided in new.h:
process.h ( see page 971) The following functions, macros, and classes are provided in process.h:
setjmp.h ( see page 993) The following functions, macros, and classes are provided in setjmp.h:
share.h ( see page 996) The following functions, macros, and classes are provided in share.h:
signal.h ( see page 997) The following functions, macros, and classes are provided in signal.h:
stdarg.h ( see page 1003) The following functions, macros, and classes are provided in stdarg.h:
stddef.h ( see page 1004) The following functions, macros, and classes are provided in stddef.h:
stdio.h ( see page 1006) The following functions, macros, and classes are provided in stdio.h:
stdlib.h ( see page 1080) The following functions, macros, and classes are provided in stdlib.h:
string.h ( see page 1139) The following functions, macros, and classes are provided in string.h:
sys\stat.h ( see page 1186) The following functions, macros, and classes are provided in sys\stat.h:
sys\timeb.h ( see page 1190) The following functions, macros, and classes are provided in sys\timeb.h:
sys\types.h ( see page 1192) The following functions, macros, and classes are provided in sys\types.h:
time.h ( see page 1193) The following functions, macros, and classes are provided in time.h:
typeinfo.h ( see page 1211) The following functions, macros, and classes are provided in typeinfo.h:
utime.h ( see page 1213) The following functions, macros, and classes are provided in utime.h:
values.h ( see page 1214) The following functions, macros, and classes are provided in values.h:
3.1.4.1 alloc.h
The following functions, macros, and classes are provided in alloc.h:
Topics
Name Description
_heapchk ( see page 716) Header File
malloc.h
Category
Memory Routines
Syntax
int _heapchk(void);
Description
Checks and verifies the heap.
_heapchk walks through the heap and examines each block, checking its
pointers, size, and other critical attributes.
Return Value
One of the following values:
712
3.1 C++ Reference RAD Studio C Runtime Library Reference
713
C Runtime Library Reference RAD Studio 3.1 C++ Reference
714
3.1 C++ Reference RAD Studio C Runtime Library Reference
715
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.1.1 _heapchk
Header File
malloc.h
Category
Memory Routines
Syntax
int _heapchk(void);
Description
_heapchk walks through the heap and examines each block, checking its pointers, size, and other critical attributes.
Return Value
Portability
716
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.1.2 _heapmin
Header File
malloc.h
Category
Memory Routines
Prototype
int _heapmin(void);
Description
The _heapmin function returns unused areas of the heap to the operating system. This allows other processes to use blocks that
have been allocated and then freed. Due to fragmentation of the heap, _heapmin might not always be able to return unused
memory to the operating system; this is not an error.
Return Value
Portability
3.1.4.1.3 _heapset
Header File
malloc.h
Category
Memory Routines
Prototype
int _heapset(unsigned int fillvalue);
Description 3
Fills the free blocks on the heap with a constant value.
_heapset checks the heap for consistency using the same methods as _heapchk. It then fills each free block in the heap with the
value contained in the least significant byte of fillvalue. This function can be used to find heap-related problems. It does not
guarantee that subsequently allocated blocks will be filled with the specified value.
Return Value
717
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <windowsx.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
BOOL InitApplication(HINSTANCE hInstance);
HWND InitInstance(HINSTANCE hInstance, int nCmdShow);
LRESULT FAR PASCAL _export MainWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
void ExampleHeapSet(HWND hWnd);
#pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; // message
if (!InitApplication(hInstance)) // Initialize shared things
return (FALSE); // Exits if unable to initialize
/* Perform initializations that apply to a specific instance */
if (!(InitInstance(hInstance, nCmdShow)))
return (FALSE);
/* Acquire and dispatch messages until a WM_QUIT message is received. */
while (GetMessage(&msg, // message structure
NULL, // handle of window receiving the message
NULL, // lowest message to examine
NULL)) // highest message to examine
{
TranslateMessage(&msg); // Translates virtual key codes
DispatchMessage(&msg); // Dispatches message to window
}
return (msg.wParam); // Returns the value from PostQuitMessage
}
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
// Fill in window class structure with parameters that describe the
// main window.
wc.style = CS_HREDRAW | CS_VREDRAW; // Class style(s).
wc.lpfnWndProc = (long (FAR PASCAL*)(void *,unsigned int,unsigned int, long ))MainWndProc;
// Function to retrieve messages for
// windows of this class.
wc.cbClsExtra = 0; // No per-class extra data.
wc.cbWndExtra = 0; // No per-window extra data.
wc.hInstance = hInstance; // Application that owns the class.
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL; // Name of menu resource in .RC file.
wc.lpszClassName = "Example"; // Name used in call to CreateWindow.
3 /* Register the window class and return success/failure code. */
return (RegisterClass(&wc));
}
HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd; // Main window handle.
/* Create a main window for this application instance. */
hWnd = CreateWindow(
"Example", // See RegisterClass() call.
"Example _heapset 32 bit only", // Text for window title bar.
718
3.1 C++ Reference RAD Studio C Runtime Library Reference
719
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.1.4 _msize
Header File
malloc.h
Category
Memory Routines
Prototype
size_t _msize(void *block);
Description
_msize returns the size of the allocated heap block whose address is block. The block must have been allocated with malloc,
calloc, or realloc. The returned size can be larger than the number of bytes originally requested when the block was allocated.
Return Value
Example
#include <malloc.h> /* malloc() _msize() */
#include <stdio.h> /* printf() */
int main( )
{
int size;
int *buffer;
buffer = malloc(100 * sizeof(int));
size = _msize(buffer);
printf("Allocated %d bytes for 100 integers\n", size);
return(0);
}
Portability
3.1.4.1.5 _rtl_heapwalk
Header File
malloc.h
Category
3 Memory Routines
Prototype
int _rtl_heapwalk(_HEAPINFO *hi);
Description
720
3.1 C++ Reference RAD Studio C Runtime Library Reference
_rtl_heapwalk assumes the heap is correct. Use _heapchk to verify the heap before using _rtl_heapwalk. _HEAPOK is returned
with the last block on the heap. _HEAPEND will be returned on the next call to _rtl_heapwalk.
_rtl_heapwalk receives a pointer to a structure of type _HEAPINFO (declared in malloc.h). Note that the _HEAPINFO structure
must be allocated on the heap (using malloc()). You can’t pass the address of a variable declared on the stack.
For the first call to _rtl_heapwalk, set the hi._pentry field to NULL. _rtl_heapwalk returns with hi._pentry containing the address of
the first block.
Return Value
Example
#include <stdio.h>
#include <malloc.h>
#include <alloc.h>
#define NUM_PTRS 10
#define NUM_BYTES 16
int main( void )
{
_HEAPINFO *hi;
char *array[ NUM_PTRS ];
int i;
hi = (_HEAPINFO *) malloc( sizeof(_HEAPINFO) );
for( i = 0; i < NUM_PTRS; i++ )
array[ i ] = (char *) malloc( NUM_BYTES );
for( i = 0; i < NUM_PTRS; i += 2 )
free( array[ i ] );
hi->_pentry = NULL;
printf( " Size Status\n" );
printf( " ---- ------\n" );
while( _rtl_heapwalk( hi ) == _HEAPOK )
printf( "%7u %s\n", hi->_size, hi->_useflag ? "used" : "free" );
free( hi );
return 0;
}
Portability
3
POSIX Win32 ANSI C ANSI C++
+
3.1.4.1.6 calloc
Header File
721
C Runtime Library Reference RAD Studio 3.1 C++ Reference
alloc.h, stdlib.h
Category
Memory Routines
Prototype
void *calloc(size_t nitems, size_t size);
Description
calloc provides access to the C memory heap. The heap is available for dynamic allocation of variable-sized blocks of memory.
Many data structures, such as trees and lists, naturally employ heap memory allocation.
Return Value
calloc returns a pointer to the newly allocated block. If not enough space exists for the new block or if nitems or size is 0, calloc
returns NULL.
Example
#include <stdio.h>
#include <alloc.h>
#include <string.h>
int main(void)
{
char *str = NULL;
/* allocate memory for string */
str = (char *) calloc(10, sizeof(char));
/* copy "Hello" into string */
strcpy(str, "Hello");
/* display string */
printf("String is %s\n", str);
/* free memory */
free(str);
return 0;
}
Portability
3.1.4.1.7 free
Header File
alloc.h, stdlib.h
3
Category
Memory Routines
Prototype
void free(void *block);
Description
722
3.1 C++ Reference RAD Studio C Runtime Library Reference
free deallocates a memory block allocated by a previous call to calloc, malloc, or realloc.
Return Value
None.
Example
#include <string.h>
#include <stdio.h>
#include <alloc.h>
int main(void)
{
char *str;
/* allocate memory for string */
str = (char *) malloc(10);
/* copy "Hello" to string */
strcpy(str, "Hello");
/* display string */
printf("String is %s\n", str);
/* free memory */
free(str);
return 0;
}
Portability
3.1.4.1.8 heapcheck
Header File
alloc.h
Category
Memory Routines
Prototype
int heapcheck(void);
Description
heapcheck walks through the heap and examines each block, checking its pointers, size, and other critical attributes.
Return Value
The return value is less than 0 for an error and greater than 0 for success. The return values and their meaning are as follows: 3
_HEAPCORRUPT Heap has been corrupted
_HEAPEMPTY No heap
_HEAPOK Heap is verified
Example
723
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <stdio.h>
#include <alloc.h>
#define NUM_PTRS 10
#define NUM_BYTES 16
int main(void)
{
char *array[ NUM_PTRS ];
int i;
for( i = 0; i < NUM_PTRS; i++ )
array[ i ] = (char *) malloc( NUM_BYTES );
for( i = 0; i < NUM_PTRS; i += 2 )
free( array[ i ] );
if( heapcheck() == _HEAPCORRUPT )
printf( "Heap is corrupted.\n" );
else
printf( "Heap is OK.\n" );
return 0;
}
Portability
3.1.4.1.9 heapcheckfree
Header File
alloc.h
Category
Memory Routines
Prototype
int heapcheckfree(unsigned int fillvalue);
Description
Return Value
The return value is less then 0 for an error and greater than 0 for success. The return values and their meaning are as follows:
3
Portability
724
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.1.10 heapchecknode
Header File
alloc.h
Category
Memory Routines
Prototype
int heapchecknode(void *node);
Description
If a node has been freed and heapchecknode is called with a pointer to the freed block, heapchecknode can return _BADNODE
rather than the expected _FREEENTRY. This is because adjacent free blocks on the heap are merged, and the block in question
no longer exists.
Return Value
Example
#include <stdio.h>
#include <alloc.h>
#define NUM_PTRS 10
#define NUM_BYTES 16
int main(void)
{
char *array[ NUM_PTRS ];
int i;
for( i = 0; i < NUM_PTRS; i++ )
array[ i ] = (char *) malloc( NUM_BYTES );
for( i = 0; i < NUM_PTRS; i += 2 )
free( array[ i ] );
for( i = 0; i < NUM_PTRS; i++ )
{
printf( "Node %2d ", i );
switch( heapchecknode( array[ i ] ) )
{ 3
case _HEAPEMPTY:
printf( "No heap.\n" );
break;
case _HEAPCORRUPT:
printf( "Heap corrupt.\n" );
break;
case _BADNODE:
printf( "Bad node.\n" );
break;
case _FREEENTRY:
725
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.1.11 heapfillfree
Header File
alloc.h
Category
Memory Routines
Prototype
int heapfillfree(unsigned int fillvalue);
Description
Return Value
Example
#include <stdio.h>
#include <alloc.h>
#include <mem.h>
#define NUM_PTRS 10
#define NUM_BYTES 16
3 int main(void)
{
char *array[ NUM_PTRS ];
int i;
int res;
for( i = 0; i < NUM_PTRS; i++ )
array[ i ] = (char *) malloc( NUM_BYTES );
for( i = 0; i < NUM_PTRS; i += 2 )
free( array[ i ] );
if( heapfillfree( 1 ) < 0 )
{
726
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.1.12 heapwalk
Header File
alloc.h
Category
Memory Routines
Prototype
int heapwalk(struct heapinfo *hi);
Description
heapwalk assumes the heap is correct. Use heapcheck to verify the heap before using heapwalk. _HEAPOK is returned with the
last block on the heap. _HEAPEND will be returned on the next call to heapwalk.
heapwalk receives a pointer to a structure of type heapinfo (declared in alloc.h). For the first call to heapwalk, set the hi.ptr field
to null. heapwalk returns with hi.ptr containing the address of the first block. hi.size holds the size of the block in bytes. hi.in_use
is a flag that’s set if the block is currently in use.
Return Value
3
727
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
Portability
<table htmltable<tr><th>POSIX</th><th>Win32</th><th>ANSI C</th><th>ANSI C++</th></tr><tr><td>
</td><td>+</td><td> </td><td> </td></tr></table
3.1.4.1.13 malloc
Header File
alloc.h, stdlib.h
Category
Memory Routines
Prototype
void *malloc(size_t size);
Description
malloc allocates a block of size bytes from the memory heap. It allows a program to allocate memory explicitly as it’s needed,
and in the exact amounts needed.
Allocates main memory.The heap is used for dynamic allocation of variable-sized blocks of memory. Many data structures, for
example, trees and lists, naturally employ heap memory allocation.
In the large data models, all the space beyond the program stack to the end of available memory is available for the heap.
Return Value
On success, malloc returns a pointer to the newly allocated block of memory. If not enough space exists for the new block, it
returns NULL. The contents of the block are left unchanged. If the argument size == 0, malloc returns NULL.
Example
#include <stdio.h>
#include <string.h>
#include <alloc.h>
#include <process.h>
int main(void)
{
char *str;
/* allocate memory for string */
if ((str = (char *) malloc(10)) == NULL)
{
printf("Not enough memory to allocate buffer\n");
exit(1); /* terminate program if out of memory */
}
/* copy "Hello" into string */
strcpy(str, "Hello");
/* display string */
printf("String is %s\n", str);
/* free memory */
3 free(str);
return 0;
}
Portability
728
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.1.14 realloc
Header File
alloc.h, stdlib.h
Category
Memory Routines
Prototype
void *realloc(void *block, size_t size);
Description
realloc attempts to shrink or expand the previously allocated block to size bytes. If size is zero, the memory block is freed and
NULL is returned. The block argument points to a memory block previously obtained by calling malloc, calloc, or realloc. If block
is a NULL pointer, realloc works just like malloc.
realloc adjusts the size of the allocated block to size, copying the contents to a new location if necessary.
Return Value
realloc returns the address of the reallocated block, which can be different than the address of the original block.
If the value of size is 0, the memory block is freed and realloc returns NULL.
Example
#include <stdio.h>
#include <alloc.h>
#include <string.h>
int main(void)
{
char *str;
/* allocate memory for string */
str = (char *) malloc(10);
/* copy "Hello" into string */
strcpy(str, "Hello");
printf("String is %s\n Address is %p\n", str, str);
str = (char *) realloc(str, 20);
printf("String is %s\n New address is %p\n", str, str);
/* free memory */
free(str);
return 0;
}
Portability
3.1.4.1.15 stackavail
Header File
malloc.h
729
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Memory Routines
Prototype
size_t stackavail(void);
Description
stackavail returns the number of bytes available on the stack. This is the amount of dynamic memory that alloca can access.
Return Value
Example
#include <malloc.h>
#include <stdio.h>
int main(void)
{
char *buf;
3.1.4.2 assert.h
The following functions, macros, and classes are provided in assert.h:
Topics
Name Description
NDEBUG #define ( see page 731) Header File
assert.h
Description
NDEBUG means "Use #define to treat assert as a macro or a true function".
Can be defined in a user program. If defined, assert is a true function; otherwise
assert is a macro.
730
3.1 C++ Reference RAD Studio C Runtime Library Reference
assert.h
Description
Can be defined in a user program. If defined, assert is a true function; otherwise assert is a macro.
3.1.4.2.2 assert
Header File
assert.h
Category
Diagnostic Routines
Prototype
void assert(int test);
Description
assert is a macro that expands to an if statement; if test evaluates to zero, the assert macro calls the _assert function
void _RTLENTRY _EXPFUNC _assert(char * __cond, char * __file, int __line);
and aborts the program. The _assert function calls abort and asserts the following a message on stderr:
3
Assertion failed: test, file filename, line linenum
The filename and linenum listed in the message are the source file name and line number where the assert macro appears.
If you place the #define NDEBUG directive ("no debugging") in the source code before the #include <assert.h> directive, the
macro expands to a no-op, the effect is to comment out the assert statement.
Return Value
None.
731
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
struct ITEM {
int key;
int value;
};
/* add item to list, make sure list is not null */
void additem(struct ITEM *itemptr) {
assert(itemptr != NULL);
/* add item to list */
}
int main(void)
{
additem(NULL);
return 0;
}
Portability
3.1.4.3 conio.h
The following functions, macros, and classes are provided in conio.h:
Topics
Name Description
_setcursortype ( see page 740) Header File
conio.h
Category
Console I/O Routines
Prototype
void _setcursortype(int cur_t);
Description
Selects cursor appearance.
Sets the cursor type to
cgets ( see page 741) Header File
conio.h
Category
Console I/O Routines
Prototype
char *cgets(char *str);
Description
Reads a string from the console.
cgets reads a string of characters from the console, storing the string (and the
string length) in the location pointed to by str.
3 cgets reads characters until it encounters a carriage-return/linefeed (CR/LF)
combination, or until the maximum allowable number of characters have been
read. If cgets reads a CR/LF combination, it replaces the combination with a \0
(null terminator) before storing the string.
Before cgets is called, set str[0] to the maximum length of the string to be read.
On return, str[1]... more ( see page 741)
732
3.1 C++ Reference RAD Studio C Runtime Library Reference
733
C Runtime Library Reference RAD Studio 3.1 C++ Reference
734
3.1 C++ Reference RAD Studio C Runtime Library Reference
735
C Runtime Library Reference RAD Studio 3.1 C++ Reference
736
3.1 C++ Reference RAD Studio C Runtime Library Reference
737
C Runtime Library Reference RAD Studio 3.1 C++ Reference
738
3.1 C++ Reference RAD Studio C Runtime Library Reference
739
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.1 _setcursortype
Header File
conio.h
Category
3
Console I/O Routines
Prototype
void _setcursortype(int cur_t);
Description
740
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
None.
Example
#include <conio.h>
int main( )
{
// tell the user what to do
clrscr();
cputs("Press any key three times.\n\r");
cputs("Each time the cursor will change shape.\n\r");
gotoxy(1,5); // show a solid cursor
cputs("Now the cursor is solid.\n\r");
_setcursortype(_SOLIDCURSOR);
while(!kbhit()) {}; // wait to proceed
getch();
gotoxy(1,5); // remove the cursor
cputs("Now the cursor is gone.");
clreol();
gotoxy(1,6);
_setcursortype(_NOCURSOR);
while(!kbhit()) {}; // wait to proceed
getch();
gotoxy(1,5); // show a normal cursor
cputs("Now the cursor is normal.");
clreol();
gotoxy(1,6);
_setcursortype(_NORMALCURSOR);
while(!kbhit()) {}; // wait to proceed
getch();
clrscr();
return(0);
}
Portability
3.1.4.3.2 cgets
Header File 3
conio.h
Category
Prototype
char *cgets(char *str);
741
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
cgets reads a string of characters from the console, storing the string (and the string length) in the location pointed to by str.
cgets reads characters until it encounters a carriage-return/linefeed (CR/LF) combination, or until the maximum allowable
number of characters have been read. If cgets reads a CR/LF combination, it replaces the combination with a \0 (null terminator)
before storing the string.
Before cgets is called, set str[0] to the maximum length of the string to be read. On return, str[1] is set to the number of
characters actually read. The characters read start at str[2] and end with a null terminator. Thus, str must be at least str[0] plus 2
bytes long.
Return Value
Example
#include <stdio.h>
#include <conio.h>
int main(void)
{
char buffer[83];
char *p;
/* There is space for 80 characters plus the NULL terminator */
buffer[0] = 81;
printf("Input some chars:");
p = cgets(buffer);
printf("\ncgets read %d characters: \"%s\"\n", buffer[1], p);
printf("The returned pointer is %p, buffer[0] is at %p\n", p, &buffer);
/* Leave room for 5 characters plus the NULL terminator */
buffer[0] = 6;
printf("Input some chars:");
p = cgets(buffer);
printf("\ncgets read %d characters: \"%s\"\n", buffer[1], p);
printf("The returned pointer is %p, buffer[0] is at %p\n", p, &buffer);
return 0;
}
Portability
3.1.4.3.3 clreol
Header File
3 conio.h
Category
Prototype
void clreol(void);
Description
742
3.1 C++ Reference RAD Studio C Runtime Library Reference
clreol clears all characters from the cursor position to the end of the line within the current text window, without moving the cursor.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
clrscr();
cprintf("The function CLREOL clears all characters from the\r\n");
cprintf("cursor position to the end of the line within the\r\n");
cprintf("current text window, without moving the cursor.\r\n");
cprintf("Press any key to continue . . .");
gotoxy(14, 4);
getch();
clreol();
getch();
return 0;
}
Portability
3.1.4.3.4 clrscr
Header File
conio.h
Category
Prototype
void clrscr(void);
Description
clrscr clears the current text window and places the cursor in the upper left corner (at position 1,1).
Return Value 3
None.
Example
#include <conio.h>
int main(void)
{
int i;
clrscr();
743
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.5 cprintf
Header File
conio.h
Category
Prototype
int cprintf(const char *format[, argument, ...]);
Description
cprintf accepts a series of arguments, applies to each a format specifier contained in the format string pointed to by format, and
outputs the formatted data directly to the current text window on the screen. There must be the same number of format specifiers
as arguments.
The string is written either directly to screen memory or by way of a BIOS call, depending on the value of the global variable
_directvideo.
Unlike fprintf and printf, cprintf does not translate linefeed characters (\n) into carriage-return/linefeed character pairs (\r\n). Tab
characters (specified by \t) are not expanded into spaces.
Return Value
Example
3 #include <conio.h>
int main(void)
{
/* clear the screen */
clrscr();
/* create a text window */
window(10, 10, 80, 25);
/* output some text in the window */
cprintf("Hello world\r\n");
/* wait for a key */
744
3.1 C++ Reference RAD Studio C Runtime Library Reference
getch();
return 0;
}
Portability
3.1.4.3.6 cputs
Header File
conio.h
Category
Prototype
int cputs(const char *str);
Description
cputs writes the null-terminated string str to the current text window. It does not append a newline character.
The string is written either directly to screen memory or by way of a BIOS call, depending on the value of the global variable
_directvideo. Unlike puts, cputs does not translate linefeed characters (\n) into carriage-return/linefeed character pairs (\r\n).
Return Value
Example
#include <conio.h>
int main(void)
{
/* clear the screen */
clrscr();
/* create a text window */
window(10, 10, 80, 25);
/* output some text in the window */
cputs("This is within the window\r\n");
/* wait for a key */
getch();
return 0;
}
Portability 3
745
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.7 cscanf
Header File
conio.h
Category
Prototype
int cscanf(char *format[, address, ...]);
Description
cscanf scans a series of input fields one character at a time, reading directly from the console. Then each field is formatted
according to a format specifier passed to cscanf in the format string pointed to by format. Finally, cscanf stores the formatted
input at an address passed to it as an argument following format, and echoes the input directly to the screen. There must be the
same number of format specifiers and addresses as there are input fields.
cscanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace) character, or it might
terminate entirely for a number of reasons. See scanf for a discussion of possible causes.
Return Value
cscanf returns the number of input fields successfully scanned, converted, and stored; the return value does not include scanned
fields that were not stored. If no fields were stored, the return value is 0.
Example
#include <conio.h>
int main(void)
{
char string[80];
/* clear the screen */
clrscr();
/* Prompt the user for input */
cprintf("Enter a string with no spaces:");
/* read the input */
cscanf("%s", string);
/* display what was read */
cprintf("\r\nThe string entered is: %s", string);
return 0;
}
3 Portability
746
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.3.8 delline
Header File
conio.h
Category
Prototype
void delline(void);
Description
delline deletes the line containing the cursor and moves all lines below it one line up. delline operates within the currently active
text window.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
clrscr();
cprintf("The function DELLINE deletes the line containing the\r\n");
cprintf("cursor and moves all lines below it one line up.\r\n");
cprintf("DELLINE operates within the currently active text\r\n");
cprintf("window. Press any key to continue . . .");
gotoxy(1,2); /* Move the cursor to the second line and first column */
getch();
delline();
getch();
return 0;
}
Portability
3.1.4.3.9 getch
Header File 3
conio.h
Category
Prototype
int getch(void);
747
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
getch reads a single character directly from the keyboard, without echoing to the screen.
Return Value
Example
#include <conio.h>
#include <stdio.h>
int main(void)
{
int c;
int extended = 0;
c = getch();
if (!c)
extended = getch();
if (extended)
printf("The character is extended\n");
else
printf("The character isn't extended\n");
return 0;
}
Portability
3.1.4.3.10 getche
Header File
conio.h
Category
Prototype
int getche(void);
Description
getche reads a single character from the keyboard and echoes it to the current text window using direct video or BIOS.
3
Note: Do not use this function in Win32 GUI applications.
Return Value
Example
#include <stdio.h>
#include <conio.h>
748
3.1 C++ Reference RAD Studio C Runtime Library Reference
int main(void)
{
char ch;
printf("Input a character:");
ch = getche();
printf("\nYou input a '%c'\n", ch);
return 0;
}
Portability
3.1.4.3.11 getpass
Header File
conio.h
Category
Prototype
char *getpass(const char *prompt);
Description
Reads a password.
getpass reads a password from the system console after prompting with the null-terminated string prompt and disabling the
echo. A pointer is returned to a null-terminated string of up to eight characters (not counting the null-terminator).
Return Value
The return value is a pointer to a static string that is overwritten with each call.
Example
#include <conio.h>
int main(void)
{
char *password;
749
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.12 gettext
Header File
conio.h
Category
Prototype
int gettext(int left, int top, int right, int bottom, void *destin);
Description
gettext stores the contents of an onscreen text rectangle defined by left, top, right, and bottom into the area of memory pointed to
by destin.
All coordinates are absolute screen coordinates not window-relative. The upper left corner is (1,1). gettext reads the contents of
the rectangle into memory sequentially from left to right and top to bottom.
Each position onscreen takes 2 bytes of memory: The first byte is the character in the cell and the second is the cell's video
attribute. The space required for a rectangle w columns wide by h rows high is defined as
Return Value
On error, it returns 0 (for example, if it fails because you gave coordinates outside the range of the current screen mode).
Example
#include <conio.h>
char buffer[4096];
int main(void)
{
int i;
clrscr();
for (i = 0; i <= 20; i++)
cprintf("Line #%d\r\n", i);
gettext(1, 1, 80, 25, buffer);
gotoxy(1, 25);
cprintf("Press any key to clear screen...");
getch();
clrscr();
gotoxy(1, 25);
3 cprintf("Press any key to restore screen...");
getch();
puttext(1, 1, 80, 25, buffer);
gotoxy(1, 25);
cprintf("Press any key to quit...");
getch();
return 0;
}
Portability
750
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.3.13 gettextinfo
Header File
conio.h
Category
Prototype
void gettextinfo(struct text_info *r);
Description
gettextinfo fills in the text_info structure pointed to by r with the current text video information.
Return Value
751
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.14 gotoxy
Header File
conio.h
Category
Prototype
void gotoxy(int x, int y);
Description
gotoxy moves the cursor to the given position in the current text window. If the coordinates are in any way invalid the call to
gotoxy is ignored. An example of this is a call to gotoxy(40,30) when (35,25) is the bottom right position in the window. Neither
argument to gotoxy can be zero.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
clrscr();
gotoxy(35, 12);
cprintf("Hello world");
3 getch();
return 0;
}
3.1.4.3.15 highvideo
Header File
conio.h
752
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Prototype
void highvideo(void);
Description
highvideo selects high-intensity characters by setting the high-intensity bit of the currently selected foreground color.
This function does not affect any characters currently onscreen, but does affect those displayed by functions (such as cprintf)
that perform direct video, text mode output after highvideo is called.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
clrscr();
lowvideo();
cprintf("Low Intensity text\r\n");
highvideo();
gotoxy(1,2);
cprintf("High Intensity Text\r\n");
return 0;
}
Portability
3.1.4.3.16 insline
Header File
conio.h
Category
Prototype
void insline(void); 3
Description
insline inserts an empty line in the text window at the cursor position using the current text background color. All lines below the
empty one move down one line, and the bottom line scrolls off the bottom of the window.
753
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
None.
Example
#include <conio.h>
int main(void)
{
clrscr();
cprintf("INSLINE inserts an empty line in the text window\r\n");
cprintf("at the cursor position using the current text\r\n");
cprintf("background color. All lines below the empty one\r\n");
cprintf("move down one line and the bottom line scrolls\r\n");
cprintf("off the bottom of the window.\r\n");
cprintf("\r\nPress any key to continue:");
gotoxy(1, 3);
getch();
insline();
getch();
return 0;
}
Portability
3.1.4.3.17 kbhit
Header File
conio.h
Category
Prototype
int kbhit(void);
Description
kbhit checks to see if a keystroke is currently available. Any available keystrokes can be retrieved with getch or getche.
Return Value
754
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
3.1.4.3.18 lowvideo
Header File
conio.h
Category
Prototype
void lowvideo(void);
Description
lowvideo selects low-intensity characters by clearing the high-intensity bit of the currently selected foreground color.
This function does not affect any characters currently onscreen. It affects only those characters displayed by functions that
perform text mode, direct console output after this function is called.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
clrscr();
highvideo();
cprintf("High Intensity Text\r\n");
lowvideo();
gotoxy(1,2);
cprintf("Low Intensity Text\r\n");
return 0;
}
Portability
3.1.4.3.19 movetext
Header File
conio.h
Category
755
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
int movetext(int left, int top, int right, int bottom, int destleft, int desttop);
Description
movetext copies the contents of the onscreen rectangle defined by left, top, right, and bottom to a new rectangle of the same
dimensions. The new rectangle’s upper left corner is position (destleft, desttop).
All coordinates are absolute screen coordinates. Rectangles that overlap are moved correctly.
Return Value
On error (for example, if it failed because you gave coordinates outside the range of the current screen mode), movetext returns
0.
Example
#include <conio.h>
#include <string.h>
int main(void)
{
char *str = "This is a test string";
clrscr();
cputs(str);
getch();
movetext(1, 1, strlen(str), 2, 10, 10);
getch();
return 0;
}
Portability
3.1.4.3.20 normvideo
Header File
conio.h
Category
3
Console I/O Routines
Prototype
void normvideo(void);
Description
756
3.1 C++ Reference RAD Studio C Runtime Library Reference
normvideo selects normal characters by returning the text attribute (foreground and background) to the value it had when the
program started.
This function does not affect any characters currently on the screen, only those displayed by functions (such as cprintf)
performing direct console output functions after normvideo is called.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
normvideo();
cprintf("NORMAL Intensity Text\r\n");
return 0;
}
Portability
3.1.4.3.21 putch
Header File
conio.h
Category
Prototype
int putch(int c);
Description
putch outputs the character c to the current text window. It is a text mode function performing direct video output to the console.
putch does not translate linefeed characters (\n) into carriage-return/linefeed pairs.
The string is written either directly to screen memory or by way of a BIOS call, depending on the value of the global variable
_directvideo.
Return Value 3
On success, putch returns the character printed, c. On error, it returns EOF.
Example
#include <stdio.h>
#include <conio.h>
int main(void)
{
757
C Runtime Library Reference RAD Studio 3.1 C++ Reference
char ch = 0;
printf("Input a string:");
while ((ch != '\r'))
{
ch = getch();
putch(ch);
}
return 0;
}
Portability
3.1.4.3.22 puttext
Header File
conio.h
Category
Prototype
int puttext(int left, int top, int right, int bottom, void *source);
Description
puttext writes the contents of the memory area pointed to by source out to the onscreen rectangle defined by left, top, right, and
bottom.
All coordinates are absolute screen coordinates, not window-relative. The upper left corner is (1,1).
puttext places the contents of a memory area into the defined rectangle sequentially from left to right and top to bottom.
Each position onscreen takes 2 bytes of memory: The first byte is the character in the cell, and the second is the cell’s video
attribute. The space required for a rectangle w columns wide by h rows high is defined as
Return Value
puttext returns a nonzero value if the operation succeeds; it returns 0 if it fails (for example, if you gave coordinates outside the
range of the current screen mode).
3
Example
#include <conio.h>
int main(void)
{
char buffer[512];
/* put some text to the console */
clrscr();
gotoxy(20, 12);
cprintf("This is a test. Press any key to continue ...");
758
3.1 C++ Reference RAD Studio C Runtime Library Reference
getch();
/* grab screen contents */
gettext(20, 12, 36, 21,buffer);
clrscr();
/* put selected characters back to the screen */
gotoxy(20, 12);
puttext(20, 12, 36, 21, buffer);
getch();
return 0;
}
Portability
3.1.4.3.23 textattr
Header File
conio.h
Category
Prototype
void textattr(int newattr);
Description
textattr lets you set both the foreground and background colors in a single call. (Normally, you set the attributes with textcolor
and textbackground.)
This function does not affect any characters currently onscreen; it affects only those characters displayed by functions (such as
cprintf) performing text mode, direct video output after this function is called.
759
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <conio.h>
int main(void)
{
int i;
clrscr();
for (i=0; i<9; i++)
{
textattr(i + ((i+1) << 4));
cprintf("This is a test\r\n");
}
return 0;
}
Portability
3.1.4.3.24 textbackground
Header File
conio.h
Category
Prototype
void textbackground(int newcolor);
Description
textbackground selects the background color. This function works for functions that produce output in text mode directly to the
screen. newcolor selects the new background color. You can set newcolor to an integer from 0 to 7, or to one of the symbolic
constants defined in conio.h. If you use symbolic constants, you must include conio.h.
Once you have called textbackground, all subsequent functions using direct video output (such as cprintf) will use newcolor.
textbackground does not affect any characters currently onscreen.
The following table lists the symbolic constants and the numeric values of the allowable colors:
BLACK 0
BLUE 1
3 GREEN 2
CYAN 3
RED 4
MAGENTA 5
BROWN 6
LIGHTGRAY 7
760
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
None.
Example
#include <conio.h>
int main(void)
{
int i, j;
clrscr();
for (i=0; i<9; i++)
{
for (j=0; j<80; j++)
cprintf("C");
cprintf("\r\n");
textcolor(i+1);
textbackground(i);
}
return 0;
}
Portability
3.1.4.3.25 textcolor
Header File
conio.h
Category
Prototype
void textcolor(int newcolor);
Description
textcolor selects the foreground character color. This function works for the console output functions. newcolor selects the new
foreground color. You can set newcolor to an integer as given in the table below, or to one of the symbolic constants defined in
conio.h. If you use symbolic constants, you must include conio.h.
Once you have called textcolor, all subsequent functions using direct video output (such as cprintf) will use newcolor. textcolor
does not affect any characters currently onscreen.
3
The following table lists the allowable colors (as symbolic constants) and their numeric values:
BLACK 0
BLUE 1
GREEN 2
CYAN 3
761
C Runtime Library Reference RAD Studio 3.1 C++ Reference
RED 4
MAGENTA 5
BROWN 6
LIGHTGRAY 7
DARKGRAY 8
LIGHTBLUE 9
LIGHTGREEN 10
LIGHTCYAN 11
LIGHTRED 12
LIGHTMAGENTA 13
YELLOW 14
WHITE 15
BLINK 128
You can make the characters blink by adding 128 to the foreground color. The predefined constant BLINK exists for this purpose.
For example:
textcolor(CYAN + BLINK);
Note: Some monitors do not recognize the intensity signal used to create the eight “light” colors (8-15). On such monitors, the
light colors are displayed as their “dark” equivalents (0-7). Also, systems that do not display in color can treat these numbers as
shades of one color, special patterns, or special attributes (such as underlined, bold, italics, and so on). Exactly what you’ll see
on such systems depends on your hardware.
Return Value
None.
Portability
3.1.4.3.26 textmode
Header File
conio.h
Category
Prototype
void textmode(int newmode);
Description
762
3.1 C++ Reference RAD Studio C Runtime Library Reference
You can give the text mode (the argument newmode) by using a symbolic constant from the enumeration type text_modes
(defined in conio.h).
The most commonly used text_modes type constants and the modes they specify are given in the following table. Some
additional values are defined in conio.h.
When textmode is called, the current window is reset to the entire screen, and the current text attributes are reset to normal,
corresponding to a call to normvideo.
Specifying LASTMODE to textmode causes the most recently selected text mode to be reselected.
textmode should be used only when the screen or window is in text mode (presumably to change to a different text mode). This
is the only context in which textmode should be used. When the screen is in graphics mode, use restorecrtmode instead to
escape temporarily to text mode.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
textmode(BW40);
cprintf("ABC");
getch();
textmode(C40);
cprintf("ABC");
getch();
textmode(BW80);
cprintf("ABC");
getch();
textmode(C80);
cprintf("ABC");
getch();
textmode(MONO);
cprintf("ABC");
getch();
return 0;
} 3
Portability
763
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.27 ungetch
Header File
conio.h
Category
Prototype
int ungetch(int ch);
Description
ungetch pushes the character ch back to the console, causing ch to be the next character read. The ungetch function fails if it is
called more than once before the next read.
Return Value
Example
#include <stdio.h>
#include <ctype.h>
#include <conio.h>
int main( void )
{
int i=0;
char ch;
puts("Input an integer followed by a char:");
/* read chars until non digit or EOF */
while((ch = getche()) != EOF && isdigit(ch))
i = 10 * i + ch - 48; /* convert ASCII into int value */
/* if non digit char was read, push it back into input buffer */
if (ch != EOF)
ungetch(ch);
printf("\n\ni = %d, next char in buffer = %c\n", i, getch());
return 0;
}
Portability
conio.h
Category
764
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
int wherex(void);
Description
wherex returns the x-coordinate of the current cursor position (within the current text window).
Return Value
wherex returns an integer in the range 1 to the number of columns in the current video mode.
Example
#include <conio.h>
int main(void)
{
clrscr();
gotoxy(10,10);
cprintf("Current location is X: %d Y: %d\r\n", wherex(), wherey());
getch();
return 0;
}
Portability
3.1.4.3.29 wherey
Header File
conio.h
Category
Prototype
int wherey(void);
Description
Return Value
wherey returns an integer in the range 1 to the number of rows in the current video mode.
Portability
765
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.3.30 window
Header File
conio.h
Category
Prototype
void window(int left, int top, int right, int bottom);
Description
window defines a text window onscreen. If the coordinates are in any way invalid, the call to window is ignored.
left and top are the screen coordinates of the upper left corner of the window.
right and bottom are the screen coordinates of the lower right corner.
The minimum size of the text window is one column by one line. The default window is full screen, with the coordinates:
1,1,C,R
where C is the number of columns in the current video mode, and R is the number of rows.
Return Value
None.
Example
#include <conio.h>
int main(void)
{
window(10,10,40,11);
textcolor(BLACK);
textbackground(WHITE);
cprintf("This is a test\r\n");
return 0;
}
Portability
3 POSIX Win32 ANSI C ANSI C++
+
3.1.4.4 ctype.h
The following functions, macros, and classes are provided in ctype.h:
766
3.1 C++ Reference RAD Studio C Runtime Library Reference
Topics
Name Description
_ctype ( see page 772) Header File
ctype.h
Syntax
extern char _ctype[];
Description
_ctype is an array of character attribute information indexed by ASCII value + 1.
Each entry is a set of bits describing the character. This array is used by isdigit,
isprint, and so on.
_IS_xxx #defines ( see page 772) Header File
ctype.h
Description
Bit settings in the _ctype[] used by the is... character macros.
_tolower ( see page 772) Header File
ctype.h
Category
Conversion Routines
Prototype
int _tolower(int ch);
Description
_tolower is a macro that does the same conversion as tolower, except that it
should be used only when ch is known to be uppercase (AZ).
To use _tolower, you must include ctype.h.
Return Value
_tolower returns the converted value of ch if it is uppercase; otherwise, the result
is undefined.
Example
_toupper ( see page 773) Header File
ctype.h
Category
Conversion Routines
Prototype
int _toupper(int ch);
Description
Translates characters to uppercase.
_toupper is a macro that does the same conversion as toupper, except that it
should be used only when ch is known to be lowercase (a to z).
To use _toupper, you must include ctype.h.
Return Value
_toupper returns the converted value of ch if it is lowercase; otherwise, the result
is undefined.
Example
isalnum, __iscsym, iswalnum, _ismbcalnum ( see page 774) Header File
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isalnum(int c);
int __iscsym(int c);
int iswalnum(wint_t c);
int _ismbcalnum(unsigned int c);
Description
Tests for an alphanumeric character. 3
isalnum is a macro that classifies ASCII-coded integer values by table lookup.
The macro is affected by the current locale’s LC_CTYPE category. For the
default C locale, c is a letter (A to Z or a to z) or a digit (0 to 9).
You can make this macro available as a function by undefining (#undef) it.
Return Value
It is a predicate returning nonzero for true and 0 for false.... more ( see page
774)
767
C Runtime Library Reference RAD Studio 3.1 C++ Reference
768
3.1 C++ Reference RAD Studio C Runtime Library Reference
769
C Runtime Library Reference RAD Studio 3.1 C++ Reference
770
3.1 C++ Reference RAD Studio C Runtime Library Reference
771
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.4.1 _ctype
Header File
ctype.h
Syntax
extern char _ctype[];
Description
_ctype is an array of character attribute information indexed by ASCII value + 1. Each entry is a set of bits describing the
character. This array is used by isdigit, isprint, and so on.
ctype.h
Description
Name Meaning
_IS_SP Is space
_IS_DIG Is digit
_IS_UPP Is uppercase
_IS_LOW Is lowercase
3 _IS_HEX [A-F] or [a-f]
_IS_CTL Control
_IS_PUN Punctuation
3.1.4.4.3 _tolower
Header File
772
3.1 C++ Reference RAD Studio C Runtime Library Reference
ctype.h
Category
Conversion Routines
Prototype
int _tolower(int ch);
Description
_tolower is a macro that does the same conversion as tolower, except that it should be used only when ch is known to be
uppercase (AZ).
Return Value
_tolower returns the converted value of ch if it is uppercase; otherwise, the result is undefined.
Example
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int length, i;
char *string = "THIS IS A STRING.";
length = strlen(string);
for (i = 0; i < length; i++) {
if ((string[i] >= 'A') && (string[i] <= 'Z')){
string[i] = _tolower(string[i]);
}
}
printf("%s\n",string);
return 0;
}
Portability
3.1.4.4.4 _toupper
Header File
ctype.h
Category
Conversion Routines 3
Prototype
int _toupper(int ch);
Description
_toupper is a macro that does the same conversion as toupper, except that it should be used only when ch is known to be
773
C Runtime Library Reference RAD Studio 3.1 C++ Reference
lowercase (a to z).
Return Value
_toupper returns the converted value of ch if it is lowercase; otherwise, the result is undefined.
Example
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int length, i;
char *string = "this is a string.";
length = strlen(string);
for (i = 0; i < length; i++) {
if ((string[i] >= 'a') && (string[i] <= 'z')){
string[i] = _toupper(string[i]);
}
}
printf("%s\n",string);
return 0;
}
Portability
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isalnum(int c);
int __iscsym(int c);
int iswalnum(wint_t c);
int _ismbcalnum(unsigned int c);
Description
isalnum is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a letter (A to Z or a to z) or a digit (0 to 9).
You can make this macro available as a function by undefining (#undef) it.
Return Value
774
3.1 C++ Reference RAD Studio C Runtime Library Reference
_ismbcalnum returns true if and only if the argument c is a single-byte ASCII English letter.
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isalnum(c))
printf("%c is alphanumeric\n",c);
else
printf("%c is not alphanumeric\n",c);
return 0;
}
Portability
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isalpha(int c);
int __iscsymf(int c);
int iswalpha(wint_t c);
int _ismbcalpha(unsigned int c);
Description
3
Classifies an alphabetical character.
isalpha is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a letter (A to Z or a to z).
You can make this macro available as a function by undefining (#undef) it.
Return Value
775
C Runtime Library Reference RAD Studio 3.1 C++ Reference
iswalpha returns nonzero if c is a wchar_t in the character set defined by the implementation.
_ismbcalpha returns true if and only if the argument c is a single-byte ASCII English letter.
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isalpha(c))
printf("%c is alphabetical\n",c);
else
printf("%c is not alphabetical\n",c);
return 0;
}
Portability
ctype.h, wctype.h
Category
Classification Routines
Prototype
int isascii(int c);
int iswascii(wint_t c);
Description
isascii is a macro that classifies ASCII-coded integer values by table lookup. It is a predicate returning nonzero for true and 0 for
3
false.
Return Value
776
3.1 C++ Reference RAD Studio C Runtime Library Reference
Each of these routines returns 0 if c does not satisfy the test condition.
Example
#include <stdio.h>
#include <ctype.h>
#include <stdio.h>
int main(void)
{
char c = 'C';
if (isascii(c))
printf("%c is ascii\n",c);
else
printf("%c is not ascii\n",c);
return 0;
}
Portability
ctype.h
Category
Classification Routines
Prototype
int iscntrl(int c);
int iswcntrl(wint_t c);
Description
iscntrl is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a delete character or control character (0x7F or 0x00 to 0x1F).
You can make this macro available as a function by undefining (#undef) it.
Return Value
Example
3
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (iscntrl(c))
printf("%c is a control character\n",c);
else
printf("%c is not a control character\n",c);
return 0;
777
C Runtime Library Reference RAD Studio 3.1 C++ Reference
}
Portability
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isdigit(int c);
int iswdigit(wint_t c);
int _ismbcdigit(unsigned int c);
Description
isdigit is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a digit (0 to 9).
You can make this macro available as a function by undefining (#undef) it.
Return Value
_ismbcdigit returns true if and only if the argument c is a single-byte representation of an ASCII digit.
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isdigit(c))
printf("%c is a digit\n",c);
else
printf("%c is not a digit\n",c);
return 0;
3 }
Portability
778
3.1 C++ Reference RAD Studio C Runtime Library Reference
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isgraph(int c);
int iswgraph(wint_t c);
int _ismbcgraph( unsigned int c);
Description
isgraph is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a printing character except blank space (‘ ‘).
You can make this macro available as a function by undefining (#undef) it.
Return Value
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isgraph(c))
printf("%c is a graphic character\n",c);
else
printf("%c is not a graphic character\n",c);
return 0;
}
Portability
3
3.1.4.4.11 islower, iswlower, _ismbclower
Header File
ctype.h, mbstring.h
Category
Classification Routines
779
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
int islower(int c);
int iswlower(wint_t c);
int _ismbclower(unsigned int c);
Description
islower is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a lowercase letter (a to z).
You can make this macro available as a function by undefining (#undef) it.
Return Value
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (islower(c))
printf("%c is a lowercase character\n",c);
else
printf("%c is not a lowercase character\n",c);
return 0;
}
Portability
Category
Classification Routines
3 Prototype
int isprint(int c);
int iswprint(wint_t c);
int _ismbcprint(unsigned int c);
Description
780
3.1 C++ Reference RAD Studio C Runtime Library Reference
isprint is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is a printing character including the blank space (‘ ‘).
You can make this macro available as a function by undefining (#undef) it.
Return Value
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isprint(c))
printf("%c is a printable character\n",c);
else
printf("%c is not a printable character\n",c);
return 0;
}
Portability
Category
Classification Routines
Prototype
int ispunct(int c);
int iswpunct(wint_t c);
int _ismbcpunct(unsigned int c);
Description
ispunct is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s 3
LC_CTYPE category. For the default C locale, c is any printing character that is neither an alphanumeric nor a blank space (‘ ‘).
You can make this macro available as a function by undefining (#undef) it.
Return Value
Example
781
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (ispunct(c))
printf("%c is a punctuation character\n",c);
else
printf("%c is not a punctuation character\n",c);
return 0;
}
Portability
Category
Classification Routines
Prototype
int isspace(int c);
int iswspace(wint_t c);
int _ismbcspace(unsigned int c);
Description
isspace is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category.
You can make this macro available as a function by undefining (#undef) it.
Return Value
isspace returns nonzero if c is a space, tab, carriage return, new line, vertical tab, formfeed (0x09 to 0x0D, 0x20), or any other
locale-defined space character.
3 Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isspace(c))
printf("%c is white space\n",c);
else
printf("%c is not white space\n",c);
782
3.1 C++ Reference RAD Studio C Runtime Library Reference
return 0;
}
Portability
Category
Classification Routines
Prototype
int isupper(int c);
int iswupper(wint_t c);
int _ismbcupper(unsigned int c);
Description
isupper is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category. For the default C locale, c is an uppercase letter (A to Z).
You can make this macro available as a function by undefining (#undef) it.
Return Value
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isupper(c))
printf("%c is an uppercase character\n",c);
else
printf("%c is not an uppercase character\n",c);
return 0; 3
}
Portability
783
C Runtime Library Reference RAD Studio 3.1 C++ Reference
ctype.h, wctype.h
Category
Classification Routines
Prototype
int isxdigit(int c);
int iswxdigit(wint_t c);
Description
isxdigit is a macro that classifies ASCII-coded integer values by table lookup. The macro is affected by the current locale’s
LC_CTYPE category.
You can make this macro available as a function by undefining (#undef) it.
Return Value
isxdigit returns nonzero if c is a hexadecimal digit (0 to 9, A to F, a to f) or any other hexadecimal digit defined by the locale.
Example
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'C';
if (isxdigit(c))
printf("%c is a hexadecimal digit\n",c);
else
printf("%c is not a hexadecimal digit\n",c);
return 0;
}
Portability
3.1.4.4.17 toascii
3 Header File
ctype.h
Category
Conversion Routines
Prototype
int toascii(int c);
784
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
toascii is a macro that converts the integer c to ASCII by clearing all but the lower 7 bits; this gives a value in the range 0 to 127.
Return Value
Portability
ctype.h, mbstring.h
Category
Conversion Routines
Prototype
int tolower(int ch);
int towlower(wint_t ch); // Unicode version
unsigned int _mbctolower(unsigned int c);
Description
tolower is a function that converts an integer ch (in the range EOF to 255) to its lowercase value (a to z; if it was uppercase, A to
Z). All others are left unchanged.
Return Value
tolower returns the converted value of ch if it is uppercase; it returns all others unchanged.
Example
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int length, i;
char *string = "THIS IS A STRING";
length = strlen(string);
for (i=0; i<length; i++) 3
{
string[i] = tolower(string[i]);
}
printf("%s\n",string);
return 0;
}
Portability
785
C Runtime Library Reference RAD Studio 3.1 C++ Reference
ctype.h, mbstring.h
Category
Conversion Routines
Prototype
int toupper(int ch);
int towupper(wint_t ch); // Unicode version
unsigned int _mbctoupper(unsigned int c);
Description
toupper is a function that converts an integer ch (in the range EOF to 255) to its uppercase value (A to Z; if it was lowercase, a to
z). All others are left unchanged.
Return Value
toupper returns the converted value of ch if it is lowercase; it returns all others unchanged.
Example
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int length, i;
char *string = "this is a string";
length = strlen(string);
for (i=0; i<length; i++)
{
string[i] = toupper(string[i]);
}
printf("%s\n",string);
3 return 0;
}
Portability
786
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.5 delayimp.h
The following functions, macros, and classes are provided in delayimp.h:
Topics
Name Description
__pfnDliNotifyHook, __pfnDliFailureHook ( see page 787) Header File
delayimp.h
Category
Delay load hook notification Routines
Prototype
typedef FARPROC (WINAPI *DelayedLoadHook)(dliNotification
dliNotify,
DelayLoadInfo * pdli);
Description
The delay load mechanism provides two hooks for you to modify the runtime
behavior of a delay loaded DLL. By writing your own hook functions using the
function signature below and assigning this to the two hooks you can modify the
delay load process.
DelayLoadProc structure
typedef struct DelayLoadProc
{
BOOL fImportByName;
union
{
LPCSTR szProcName;
DWORD dwOrdinal;
};
} DelayLoadProc;
ImgDelayDescr structure
typedef struct ImgDelayDescr
{
DWORD grAttrs; /* attributes */
LPCSTR szName; /* pointer to dll name */
HMODULE... more ( see page 787)
__FUnloadDelayLoadedDLL ( see page 790) Header File
delayimp.h
Prototype
BOOL WINAPI __FUnloadDelayLoadedDLL(LPCSTR szDll);
Description
Unloads a delay loaded DLL.
szDll is pointer to a name to unload, or NULL to unload all the delay load DLLs in
the list.
Return Value
On successful completion __FUnloadDelayLoadedDLL returns true.
On error it returns false.
delayimp.h 3
Category
Prototype
typedef FARPROC (WINAPI *DelayedLoadHook)(dliNotification dliNotify,
DelayLoadInfo * pdli);
787
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
The delay load mechanism provides two hooks for you to modify the runtime behavior of a delay loaded DLL. By writing your
own hook functions using the function signature below and assigning this to the two hooks you can modify the delay load
process.
DelayLoadProc structure
typedef struct DelayLoadProc
{
BOOL fImportByName;
union
{
LPCSTR szProcName;
DWORD dwOrdinal;
};
} DelayLoadProc;
ImgDelayDescr structure
typedef struct ImgDelayDescr
{
DWORD grAttrs; /* attributes */
LPCSTR szName; /* pointer to dll name */
HMODULE hmod; /* address of module handle */
IMAGE_THUNK_DATA * pIAT; /* address of the IAT */
IMAGE_THUNK_DATA * pINT; /* address of the INT */
IMAGE_THUNK_DATA * pBoundIAT; /* address of the optional bound IAT */
IMAGE_THUNK_DATA * pUnloadIAT; /* address of optional copy of
original IAT */
DWORD dwTimeStamp; /* 0 if not bound, */
/* O.W. date/time stamp of DLL bound
to (Old BIND) */
} ImgDelayDescr;
DelayLoadInfo structure
typedef struct DelayLoadInfo
3 {
DWORD cb; /* size of structure */
const ImgDelayDescr * pidd; /* raw form of data (everything is
there) */
FARPROC * ppfn; /* points to address of function to
load */
788
3.1 C++ Reference RAD Studio C Runtime Library Reference
The following structure is the enumerations that are defined for the hook notification events:
typedef enum
{
dliNoteStartProcessing, /* used to bypass or note helper only */
dliNotePreLoadLibrary, /* called just before LoadLibrary, can */
/* override w/ new HMODULE return val */
dliNotePreGetProcAddress, /* called just before GetProcAddress, can */
/* override w/ new FARPROC return value */
dliFailLoadLibrary, /* failed to load library, fix it by */
/* returning a valid HMODULE */
dliFailGetProcAddress, /* failed to get proc address, fix it by */
/* returning a valid FARPROC */
dliNoteEndProcessing, /* called after all processing is done, */
/* no bypass possible at this point */
/* except by longjmp(), throw(), or
RaiseException. */
} dliNotification;
Hook pointers
The “notify hook” gets called for every call to the delay load helper. This allows a user to hook every call and skip the delay load
helper entirely.
extern DelayedLoadHook _EXPDATA __pfnDliNotifyHook;
dliNotify == 3
{
dliNoteStartProcessing |
dliNotePreLoadLibrary |
dliNotePreGetProcAddress |
dliNoteEndProcessing
789
C Runtime Library Reference RAD Studio 3.1 C++ Reference
For further information on when this notify eventsd occur during the delay load process, please see delayhlp.c
3.1.4.5.2 __FUnloadDelayLoadedDLL
Header File
delayimp.h
Prototype
BOOL WINAPI __FUnloadDelayLoadedDLL(LPCSTR szDll);
Description
szDll is pointer to a name to unload, or NULL to unload all the delay load DLLs in the list.
Return Value
3.1.4.6 direct.h
The following functions, macros, and classes are provided in direct.h:
Topics
Name Description
_chdrive ( see page 791) Header File
direct.h
Category
Directory Control Routines
3 Prototype
int _chdrive(int drive);
Description
Sets current disk drive.
_chdrive sets the current drive to the one associated with drive: 1 for A, 2 for B, 3
for C, and so on.
This function changes the current drive of the parent process.
Return Value
_chdrive returns 0 if the current drive was changed successfully; otherwise, it
returns -1.
Example
790
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.6.1 _chdrive
Header File
direct.h
Category
Prototype
int _chdrive(int drive);
Description
_chdrive sets the current drive to the one associated with drive: 1 for A, 2 for B, 3 for C, and so on.
Return Value
_chdrive returns 0 if the current drive was changed successfully; otherwise, it returns -1.
Example
#include <stdio.h>
#include <direct.h>
int main(void)
{
if (_chdrive(3) == 0)
printf("Successfully changed to drive C:\n");
else
printf("Cannot change to drive C:\n");
return 0;
}
Portability
3
POSIX Win32 ANSI C ANSI C++
+
791
C Runtime Library Reference RAD Studio 3.1 C++ Reference
direct.h
Category
Prototype
char * _getdcwd(int drive, char *buffer, int buflen);
wchar_t * _wgetdcwd(int drive, wchar_t *buffer, int buflen);
Description
_getdcwd gets the full path name of the working directory of the specified drive (including the drive name), up to buflen bytes
long, and stores it in buffer. If the full path name length (including the null-terminator) is longer than buflen, an error occurs. The
drive is 0 for the default drive, 1=A, 2=B, and so on.
If the working directory is the root directory, the terminating character for the full path is a backslash. If the working directory is a
subdirectory, there is no terminating backslash after the subdirectory name.
If buffer is NULL, _getdcwd allocates a buffer at least buflen bytes long. You can later free the allocated buffer by passing the
_getdcwd return value to the free function.
Return Value
If successful, _getdcwd returns a pointer to the buffer containing the current directory for the specified drive.
Otherwise it returns NULL, and sets the global variable errno to one of the following values:
Example
#include <direct.h>
#include <stdio.h>
char buf[65];
void main()
{
if (_getdcwd(3, buf, sizeof(buf)) == NULL)
perror("Unable to get current directory of drive C");
else
printf("Current directory of drive C is %s\n",buf);
}
Portability
3.1.4.7 dirent.h
The following functions, macros, and classes are provided in dirent.h:
792
3.1 C++ Reference RAD Studio C Runtime Library Reference
Topics
Name Description
closedir, wclosedir ( see page 794) Header File
dirent.h
Category
Directory Control Routines
Prototype
void closedir(DIR *dirp);
void wclosedir(wDIR *dirp);
Description
Closes a directory stream.
closedir is available on POSIX-compliant UNIX systems.
The closedir function closes the directory stream dirp, which must have been
opened by a previous call to opendir. After the stream is closed, dirp no longer
points to a valid directory stream.
wclosedir is the Unicode version of closedir.
Return Value
If closedir is successful, it returns 0. Otherwise, closedir returns -1 and sets the
global variable errno to
opendir, wopendir ( see page 795) Header File
dirent.h
Category
Directory Control Routines
Prototype
DIR *opendir(const char *dirname);
wDIR *wopendir(const wchar_t *dirname);
Description
Opens a directory stream for reading.
opendir is available on POSIX-compliant UNIX systems.
The opendir function opens a directory stream for reading. The name of the
directory to read is dirname. The stream is set to read the first entry in the
directory.
A directory stream is represented by the DIR structure, defined in dirent.h. This
structure contains no user-accessible fields. Multiple directory streams can be
opened and read simultaneously. Directory entries can be created or deleted
while a directory stream is being... more ( see page 795)
readdir, wreaddir ( see page 796) Header File
dirent.h
Category
Directory Control Routines
Prototype
struct dirent *readdir(DIR *dirp);
struct wdirent *wreaddir(wDIR *dirp)
Description
Reads the current entry from a directory stream.
readdir is available on POSIX-compliant UNIX systems.
The readdir function reads the current directory entry in the directory stream
pointed to by dirp. The directory stream is advanced to the next entry.
The readdir function returns a pointer to a dirent structure that is overwritten by
each call to the function on the same directory stream. The structure is not
overwritten by a readdir call on a different directory stream.
The dirent structure corresponds to... more ( see page 796)
793
C Runtime Library Reference RAD Studio 3.1 C++ Reference
dirent.h
Category
Prototype
void closedir(DIR *dirp);
void wclosedir(wDIR *dirp);
Description
The closedir function closes the directory stream dirp, which must have been opened by a previous call to opendir. After the
stream is closed, dirp no longer points to a valid directory stream.
Return Value
If closedir is successful, it returns 0. Otherwise, closedir returns -1 and sets the global variable errno to
EBADF The dirp argument does not point to a valid open directory stream
Example
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
794
3.1 C++ Reference RAD Studio C Runtime Library Reference
dirent.h
Category
Prototype
DIR *opendir(const char *dirname);
wDIR *wopendir(const wchar_t *dirname);
Description
A directory stream is represented by the DIR structure, defined in dirent.h. This structure contains no user-accessible fields.
Multiple directory streams can be opened and read simultaneously. Directory entries can be created or deleted while a directory
stream is being read.
Use the readdir function to read successive entries from a directory stream. Use the closedir function to remove a directory
795
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
On success, opendir returns a pointer to a directory stream that can be used in calls to readdir, rewinddir, and closedir.
On error (If the directory cannot be opened), the functino returns NULL and sets the global variable errno to
Example
/* opendir.c - test opendir(), readdir(), closedir() */
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
796
3.1 C++ Reference RAD Studio C Runtime Library Reference
dirent.h
Category
Prototype
struct dirent *readdir(DIR *dirp);
struct wdirent *wreaddir(wDIR *dirp)
Description
The readdir function reads the current directory entry in the directory stream pointed to by dirp. The directory stream is advanced
to the next entry.
The readdir function returns a pointer to a dirent structure that is overwritten by each call to the function on the same directory
stream. The structure is not overwritten by a readdir call on a different directory stream.
The dirent structure corresponds to a single directory entry. It is defined in dirent.h and contains (in addition to other
non-accessible members) the following member:
char d_name[];
where d_name is an array of characters containing the null-terminated file name for the current directory entry. The size of the
array is indeterminate; use strlen to determine the length of the file name.
All valid directory entries are returned, including subdirectories, “.” and “..” entries, system files, hidden files, and volume labels.
Unused or deleted directory entries are skipped.
A directory entry can be created or deleted while a directory stream is being read, but readdir might or might not return the
affected directory entry. Rewinding the directory with rewinddir or reopening it with opendir ensures that readdir will reflect the
current state of the directory.
The wreaddir function is the Unicode version of readdir. It uses the wdirent structure but otherwise is similar to readdir.
Return Value
On success, readdir returns a pointer to the current directory entry for the directory stream.
If the end of the directory has been reached, or dirp does not refer to an open directory stream, readdir returns NULL.
Portability
3
3.1.4.7.4 rewinddir, wrewinddir
Header File
dirent.h
Category
797
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
void rewinddir(DIR *dirp);
void wrewinddir(wDIR *dirp);
Description
The rewinddir function repositions the directory stream dirp at the first entry in the directory. It also ensures that the directory
stream accurately reflects any directory entries that might have been created or deleted since the last opendir or rewinddir on
that directory stream.
Return Value
None.
Example
/* opendir.c - test opendir(), readdir(), closedir() */
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
798
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.8 dir.h
The following functions, macros, and classes are provided in dir.h:
Topics
Name Description
chdir ( see page 803) Header File
dir.h
Category
Directory Control Routines
Prototype
int chdir(const char *path);
int _wchdir(const wchar_t *path);
Description
Changes current directory.
chdir causes the directory specified by path to become the current working
directory; path must specify an existing directory.
A drive can also be specified in the path argument, such as
chdir("a:\\BC")
but this method changes only the current directory on that drive; it does not
change the active drive.
799
C Runtime Library Reference RAD Studio 3.1 C++ Reference
800
3.1 C++ Reference RAD Studio C Runtime Library Reference
801
C Runtime Library Reference RAD Studio 3.1 C++ Reference
• must be empty
• must not be the current working directory
• must not be the root directory
Return Value
_rmdir returns 0 if the directory is successfully deleted. A
return value of -1 indicates an error, and the global
variable errno is set to one of the following values:
802
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.8.1 chdir
Header File
dir.h
Category
Prototype
int chdir(const char *path);
int _wchdir(const wchar_t *path);
Description
chdir causes the directory specified by path to become the current working directory; path must specify an existing directory.
but this method changes only the current directory on that drive; it does not change the active drive.
Example
#include <stdio.h>
#include <stdlib.h> 3
#include <dir.h>
char old_dir[MAXDIR];
char new_dir[MAXDIR];
int main(void)
{
if (getcurdir(0, old_dir))
{
perror("getcurdir()");
exit(1);
803
C Runtime Library Reference RAD Studio 3.1 C++ Reference
}
printf("Current directory is: \\%s\n", old_dir);
if (chdir("\\"))
{
perror("chdir()");
exit(1);
}
if (getcurdir(0, new_dir))
{
perror("getcurdir()");
exit(1);
}
printf("Current directory is now: \\%s\n", new_dir);
printf("\nChanging back to original directory: \\%s\n", old_dir);
if (chdir(old_dir))
{
perror("chdir()");
exit(1);
}
return 0;
}
Portability
dir.h
Description
These symbols define the maximum number of characters in a file specification for fnsplit (including room for a terminating
NULL).
Name Meaning
MAXPATH Complete file name with path
MAXDRIVE Disk drive (e.g., "A:")
MAXDIR File subdirectory specification
MAXFILE File name without extension
MAXEXT File extension
dir.h
Category
804
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
int findclose(struct ffblk *ffblk );
int _wfindclose(struct _wffblk *ffblk );
Description
findclose closes any handles and frees up any dynamic memory associated with previous calls to findfirst and findnext.
Return Value
• -1 is returned
• errno is set to
Portability
See Also
findfirst ( see page 805)
dir.h
Category
Prototype
int findfirst(const char *pathname, struct ffblk *ffblk, int attrib);
int _wfindfirst( const wchar_t *pathname, struct _wffblk *ffblk, int attrib);
Description
findfirst begins a search of a disk directory for files specified by attributes or wildcards.
3
pathname is a string with an optional drive specifier path and file name of the file to be found. Only the file name portion can
contain wildcard match characters (such as ? or *). If a matching file is found the ffblk structure is filled with the file-directory
information.
When Unicode is defined, the _wfindfirst function uses the following _wffblk structure.
struct _wffblk {
805
C Runtime Library Reference RAD Studio 3.1 C++ Reference
long ff_reserved;
long ff_fsize;
unsigned long ff_attrib;
unsigned short ff_ftime;
unsigned short ff_fdate;
wchar_t ff_name[256];
};
attrib is a file-attribute byte used in selecting eligible files for the search. attrib should be selected from the following constants
defined in dos.h:
For more detailed information about these attributes refer to your operating system documentation.
ff_ftime and ff_fdate contain bit fields for referring to the current date and time. The structure of these fields was established by
the operating system. Both are 16-bit structures divided into three fields.
ff_ftime:
Bits 0 to 4 The result of seconds divided by 2 (for example 10 here means 20 seconds)
Bits 5 to 10 Minutes
3 Bits 11 to 15 Hours
ff_fdate:
806
3.1 C++ Reference RAD Studio C Runtime Library Reference
The structure ftime declared in io.h uses time and date bit fields similar in structure to ff_ftime and ff_fdate.
Return Value
When no more files can be found, or if there is an error in the file name:
• -1 is returned
• errno is set to
Example
/* findfirst and findnext example */
#include <stdio.h>
#include <dir.h>
int main(void)
{
struct ffblk ffblk;
int done;
printf("Directory listing of *.*\n");
done = findfirst("*.*",&ffblk,0);
while (!done)
{
printf(" %s\n", ffblk.ff_name);
done = findnext(&ffblk);
}
return 0;
}
Portability
See Also
findclose ( see page 804)
dir.h
Category
807
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
int findnext(struct ffblk *ffblk );
int _wfindnext(struct _wffblk *ffblk );
Description
findnext is used to fetch subsequent files that match the pathname given in findfirst. ffblk is the same block filled in by the findfirst
call. This block contains necessary information for continuing the search. One file name for each call to findnext will be returned
until no more files are found in the directory matching the pathname.
Return Value
findnext returns 0 on successfully finding a file matching the search pathname. When no more files can be found or if there is an
error in the file name
-1 is returned
errno is set to
Portability
See Also
findfirst ( see page 805)
dir.h
Category
Description
808
3.1 C++ Reference RAD Studio C Runtime Library Reference
fnmerge makes a path name from its components. The new path name is
X:\DIR\SUBDIR\NAME.EXT
where:
drive = X
dir = \\DIR\\SUBDIR\\
name = NAME
ext = .EXT
If drive is empty or NULL, no drive is inserted in the path name. If it is missing a trailing colon (:), a colon is inserted in the path
name.
If dir is empty or NULL, no directory is inserted in the path name. If it is missing a trailing slash (\ or /), a backslash is inserted in
the path name.
If ext is empty or NULL, no extension is inserted in the path name. If it is missing a leading period (.), a period is inserted in the
path name.
fnmerge assumes there is enough space in path for the constructed path name. The maximum constructed length is MAXPATH.
MAXPATH is defined in dir.h.
fnmerge and fnsplit are invertible; if you split a given path with fnsplit then merge the resultant components with fnmerge you end
up with path.
Return Value
None.
Example
#include <string.h>
#include <stdio.h>
#include <dir.h>
int main(void)
{
char s[MAXPATH];
char drive[MAXDRIVE];
char dir[MAXDIR];
char file[MAXFILE];
char ext[MAXEXT];
getcwd(s,MAXPATH); /* get the current working directory */
strcat(s,"\\"); /* append on a trailing character */
fnsplit(s,drive,dir,file,ext); /* split the string to separate elems */
strcpy(file,"DATA");
strcpy(ext,".TXT");
fnmerge(s,drive,dir,file,ext); /* merge everything into one string */
puts(s); /* display resulting string */ 3
return 0;
}
Portability
809
C Runtime Library Reference RAD Studio 3.1 C++ Reference
dir.h
Category
Prototype
int fnsplit(const char *path, char *drive, char *dir, char *name, char *ext);
int _wfnsplit(const wchar_t *path, wchar_t *drive, wchar_t *dir, wchar_t *name, wchar_t *ext );
Description
fnsplit takes a file's full path name (path) as a string in the form X:\DIR\SUBDIR\NAME.EXT and splits path into its four
components. It then stores those components in the strings pointed to by drive, dir, name, and ext. All five components must be
passed but any of them can be a null which means the corresponding component will be parsed but not stored. If any path
component is null, that component corresponds to a non-NULL, empty string.
The maximum sizes for these strings are given by the constants MAXDRIVE, MAXDIR, MAXPATH, MAXFILE, and MAXEXT
(defined in dir.h) and each size includes space for the null-terminator.
fnsplit assumes that there is enough space to store each non-null component.
EXTENSION An extension
FILENAME A file name
DIRECTORY A directory (and possibly subdirectories)
DRIVE A drive specification (see dir.h)
WILDCARDS Wildcards (* or ?)
3
Example
#include <stdlib.h>
#include <stdio.h>
#include <dir.h>
int main(void)
{
char *s;
char drive[MAXDRIVE];
810
3.1 C++ Reference RAD Studio C Runtime Library Reference
char dir[MAXDIR];
char file[MAXFILE];
char ext[MAXEXT];
int flags;
s=getenv("COMSPEC"); /* get the comspec environment parameter */
flags=fnsplit(s,drive,dir,file,ext);
printf("Command processor info:\n");
if(flags & DRIVE)
printf("\tdrive: %s\n",drive);
if(flags & DIRECTORY)
printf("\tdirectory: %s\n",dir);
if(flags & FILENAME)
printf("\tfile: %s\n",file);
if(flags & EXTENSION)
printf("\textension: %s\n",ext);
return 0;
}
Portability
dir.h
Description
Bit definitions returned from fnsplit to identify which pieces of a file name were found during the split.
Flag Component
DIRECTORY Path includes a directory (and possibly subdirectories)
DRIVE Path includes a drive specification (see DIR.H)
EXTENSION Path includes an extension
FILENAME Path includes a file name
WILDCARDS Path contains wildcards (* or ?)
dir.h
3
Category
Prototype
int getcurdir(int drive, char *directory);
int _wgetcurdir(int drive, wchar_t *directory );
811
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
getcurdir gets the name of the current working directory for the drive indicated by drive. drive specifies a drive number (0 for
default, 1 for A, and so on). directory points to an area of memory of length MAXDIR where the null-terminated directory name
will be placed. The name does not contain the drive specification and does not begin with a backslash.
Return Value
Example
#include <dir.h>
#include <stdio.h>
#include <string.h>
char *current_directory(char *path)
{
strcpy(path, "X:\\"); /* fill string with form of response: X:\ */
path[0] = 'A' + getdisk(); /* replace X with current drive letter */
getcurdir(0, path+3); /* fill rest of string with current directory */
return(path);
}
int main(void)
{
char curdir[MAXPATH];
current_directory(curdir);
printf("The current directory is %s\n", curdir);
return 0;
}
Portability
dir.h
Category
Prototype
char *getcwd(char *buf, int buflen);
Description
getcwd gets the full path name (including the drive) of the current working directory, up to buflen bytes long and stores it in buf. If
the full path name length (including the null terminator) is longer than buflen bytes, an error occurs.
If buf is NULL, a buffer buflen bytes long is allocated for you with malloc. You can later free the allocated buffer by passing the
return value of getcwd to the function free.
812
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
Example
#include <stdio.h>
#include <dir.h>
int main(void)
{
char buffer[MAXPATH];
getcwd(buffer, MAXPATH);
printf("The current directory is: %s\n", buffer);
return 0;
}
Portability
dir.h
Category
Prototype
int getdisk(void);
int setdisk(int drive);
Description
getdisk gets the current drive number. It returns an integer: 0 for A, 1 for B, 2 for C, and so on. 3
setdisk sets the current drive to the one associated with drive: 0 for A, 1 for B, 2 for C, and so on.
The setdisk function changes the current drive of the parent process.
Return Value
getdisk returns the current drive number. setdisk returns the total number of drives available.
Example
813
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <stdio.h>
#include <dir.h>
int main(void)
{
int disk, maxdrives = setdisk(2);
disk = getdisk() + 'A';
printf("\nThe number of logical drives is:%d\n", maxdrives);
printf("The current drive is: %c\n", disk);
return 0;
}
dir.h
Category
Prototype
int mkdir(const char *path);
int _wmkdir(const wchar_t *path);
Description
Creates a directory.
mkdir creates a new directory from the given path name path.
Return Value
A return value of -1 indicates an error, and the global variable errno is set to one of the following values:
Example
#include <stdio.h>
#include <process.h>
#include <dir.h>
#define DIRNAME "testdir.$$$"
int main(void)
{
int stat;
stat = mkdir(DIRNAME);
if (!stat)
3 printf("Directory created\n");
else
{
printf("Unable to create directory\n");
exit(1);
}
getchar();
system("dir/p");
getchar();
stat = rmdir(DIRNAME);
814
3.1 C++ Reference RAD Studio C Runtime Library Reference
if (!stat)
printf("\nDirectory deleted\n");
else
{
perror("\nUnable to delete directory\n");
exit(1);
}
return 0;
}
Portability
dir.h
Category
Prototype
char *_mktemp(char *template);
wchar_t *_wmktemp(wchar_t *template);
Description
_mktemp replaces the string pointed to by template with a unique file name and returns template.
template should be a null-terminated string with six trailing Xs. These Xs are replaced with a unique collection of letters plus a
period, so that there are two letters, a period, and three suffix letters in the new file name.
Starting with AA.AAA, the new file name is assigned by looking up the name on the disk and avoiding pre-existing names of the
same format.
Return Value
If a unique name can be created and template is well formed, _mktemp returns the address of the template string. Otherwise, it
returns null.
Example
#include <dir.h>
#include <stdio.h> 3
int main(void)
{
/* fname defines the template for the
temporary file. */
char *fname = "TXXXXXX", *ptr;
ptr = mktemp(fname);
printf("%s\n",ptr);
return 0;
}
815
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Portability
dir.h
Category
Prototype
int _rmdir(const char *path);
int _wrmdir(const wchar_t *path);
Description
Removes a directory.
_rmdir deletes the directory whose path is given by path. The directory named by path
• must be empty
• must not be the current working directory
• must not be the root directory
Return Value
_rmdir returns 0 if the directory is successfully deleted. A return value of -1 indicates an error, and the global variable errno is set
to one of the following values:
Example
#include <stdio.h>
#include <process.h>
#include <dir.h>
#define DIRNAME "testdir.$$$"
int main(void)
{
int stat;
stat = mkdir(DIRNAME);
3 if (!stat)
printf("Directory created\n");
else
{
printf("Unable to create directory\n");
exit(1);
}
getchar();
system("dir/p");
getchar();
stat = rmdir(DIRNAME);
816
3.1 C++ Reference RAD Studio C Runtime Library Reference
if (!stat)
printf("\nDirectory deleted\n");
else
{
perror("\nUnable to delete directory\n");
exit(1);
}
return 0;
}
Portability
dir.h
Category
Miscellaneous Routines
Prototype
char *searchpath(const char *file);
wchar_t *wsearchpath( const wchar_t *file );
Description
searchpath attempts to locate file, searching along the operating system path, which is the PATH=... string in the environment. A
pointer to the complete path-name string is returned as the function value.
searchpath searches for the file in the current directory of the current drive first. If the file is not found there, the PATH
environment variable is fetched, and each directory in the path is searched in turn until the file is found, or the path is exhausted.
When the file is located, a string is returned containing the full path name. This string can be used in a call to access the file (for
example, with fopen or exec...).
The string returned is located in a static buffer and is overwritten on each subsequent call to searchpath.
Return Value
searchpath returns a pointer to a file name string if the file is successfully located; otherwise, searchpath returns null.
Example
#include <stdio.h>
3
#include <dir.h>
int main(void)
{
char *p;
/* Looks for ILINK32 and returns a pointer
to the path */
p = searchpath("ILINK32.EXE");
printf("Search for ILINK32.EXE : %s\n", p);
/* Looks for nonexistent file */
817
C Runtime Library Reference RAD Studio 3.1 C++ Reference
p = searchpath("NOTEXIST.FIL");
printf("Search for NOTEXIST.FIL : %s\n", p);
return 0;
}
Portability
3.1.4.9 dos.h
The following functions, macros, and classes are provided in dos.h:
Topics
Name Description
FA_xxxx #defines ( see page 822) Header File
dos.h
Description
File attributes
NFDS #define ( see page 822) Header File
dos.h
Description
Maximum number of file descriptors.
_getdrive ( see page 822) Header File
dos.h
Category
Directory Control Routines
Prototype
int _getdrive(void);
Description
Gets the current drive.
_getdrive gets the the current drive number. It returns an integer: 0 for A, 1 for B,
2 for C, and so on.
Return Value
_getdrive returns the current drive number on success or -1 in the event of error.
Example
_osmajor ( see page 823) Header File
dos.h
Syntax
extern unsigned char _osmajor;
Description
The major version number of the operating system is available individually
through _osmajor. For example, if you are running DOS version 3.2, _osmajor
will be 3.
This variable can be useful when you want to write modules that will run on DOS
versions 2.x and 3.x. Some library routines behave differently depending on the
DOS version number, while others only work under DOS 3.x and higher. For
example, refer to creatnew and _rtl_open.
3
818
3.1 C++ Reference RAD Studio C Runtime Library Reference
819
C Runtime Library Reference RAD Studio 3.1 C++ Reference
820
3.1 C++ Reference RAD Studio C Runtime Library Reference
821
C Runtime Library Reference RAD Studio 3.1 C++ Reference
dos.h
Description
File attributes
Constant Description
FA_RDONLY Read-only attribute
FA_HIDDEN Hidden file
FA_SYSTEM System file
FA_LABEL Volume label
FA_DIREC Directory
FA_ARCH Archive
dos.h
Description
3.1.4.9.3 _getdrive
Header File
dos.h
Category
Prototype
int _getdrive(void);
Description
3 _getdrive gets the the current drive number. It returns an integer: 0 for A, 1 for B, 2 for C, and so on.
Return Value
_getdrive returns the current drive number on success or -1 in the event of error.
Example
#include <stdio.h>
#include <direct.h>
int main(void)
822
3.1 C++ Reference RAD Studio C Runtime Library Reference
{
int disk;
disk = _getdrive() + 'A' - 1;
printf("The current drive is: %c\n", disk);
return 0;
}
3.1.4.9.4 _osmajor
Header File
dos.h
Syntax
extern unsigned char _osmajor;
Description
The major version number of the operating system is available individually through _osmajor. For example, if you are running
DOS version 3.2, _osmajor will be 3.
This variable can be useful when you want to write modules that will run on DOS versions 2.x and 3.x. Some library routines
behave differently depending on the DOS version number, while others only work under DOS 3.x and higher. For example, refer
to creatnew and _rtl_open.
3.1.4.9.5 _osminor
Header File
dos.h
Syntax
extern unsigned char _osminor;
Description
The minor version number of the operating system is available individually through _osminor. For example, if you are running
DOS version 3.2, _osminor will be 20.
This variables can be useful when you want to write modules that will run on DOS versions 2.x and 3.x. Some library routines
behave differently depending on the DOS version number, while others only work under DOS 3.x and higher. For example, refer
to creatnew and _rtl_open.
3.1.4.9.6 _osversion
Header File
dos.h
Syntax
3
extern unsigned _osversion;
Description
_osversion contains the operating system version number, with the major version number in the low byte and the minor version
number in the high byte. (For DOS version x.y, the x is the major version number, and y is the minor version number.)
823
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.9.7 _sleep
Header File
dos.h
Category
Prototype
void _sleep(unsigned seconds);
Description
With a call to _sleep, the current program is suspended from execution for the number of seconds specified by the argument
seconds. The interval is accurate only to the nearest hundredth of a second or to the accuracy of the operating system clock,
whichever is less accurate.
Return Value
None.
Example
#include <dos.h>
#include <stdio.h>
int main(void)
{
int i;
for (i=1; i<5; i++)
{
printf("Sleeping for %d seconds\n", i);
_sleep(i);
}
return 0;
}
Portability
3.1.4.9.8 _version
Header File
dos.h
3
Syntax
extern unsigned _version;
Description
_version contains the operating system version number, with the major version number in the low byte and the minor version
number in the high byte. (For DOS version x.y, the x is the major version number, and y is the minor version number.)
824
3.1 C++ Reference RAD Studio C Runtime Library Reference
dos.h
Category
Miscellaneous Routines
Prototype
void disable(void);
void _disable(void);
void enable(void);
void _enable(void);
Description
These macros are designed to provide a programmer with flexible hardware interrupt control.
disable and _disable macros disable interrupts. Only the NMI (non-maskable interrupt) is allowed from any external device.
enable and _enable macros enable interrupts, allowing any device interrupts to occur.
Return Value
None.
Portability
3.1.4.9.10 dostounix
Header File
dos.h
Category
Prototype
long dostounix(struct date *d, struct time *t);
Description
3
Converts date and time to UNIX time format.
dostounix converts a date and time as returned from getdate and gettime into UNIX time format. d points to a date
structure, and t points to a time structure containing valid date and time information.
The date and time must not be earlier than or equal to Jan 1 1980 00:00:00.
Return Value
825
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Returns UNIX version of current date and time parameters: number of seconds since 00:00:00 on January 1, 1970 (GMT).
Example
#include <time.h>
#include <stddef.h>
#include <dos.h>
#include <stdio.h>
int main(void)
{
time_t t;
struct time d_time;
struct date d_date;
struct tm *local;
getdate(&d_date);
gettime(&d_time);
t = dostounix(&d_date, &d_time);
local = localtime(&t);
printf("Time and Date: %s\n", asctime(local));
return 0;
}
Portability
3.1.4.9.11 geninterrupt
Header File
Category
Prototype
void geninterrupt(int intr_num);
Description
Return Value
Portability
Category
Prototype
void getdate(struct date *datep);
void setdate(struct date *datep);
826
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
getdate fills in the date structure (pointed to by datep) with the system's current date.
setdate sets the system date (month, day, and year) to that in the date structure pointed to by datep. Note that a request to set a
date might fail if you do not have the privileges required by the operating system.
Return Value
Example
#include <dos.h>
#include <stdio.h>
int main(void)
{
struct date d;
getdate(&d);
printf("The current year is: %d\n", d.da_year);
printf("The current day is: %d\n", d.da_day);
printf("The current month is: %d\n", d.da_mon);
return 0;
}
3.1.4.9.13 getdfree
Header File
dos.h
Category
Prototype
void getdfree(unsigned char drive, struct dfree *dtable);
Description
getdfree accepts a drive specifier in drive (0 for default, 1 for A, and so on) and fills the dfree structure pointed to by dtable with 3
disk attributes.
827
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
getdfree returns no value. In the event of an error, df_sclus in the dfree structure is set to (unsigned) -1.
Example
#include <stdio.h>
#include <dos.h>
#include <process.h>
int main(void)
{
struct dfree free;
long avail;
getdfree(0, &free);
if ( free.df_sclus == -1)
{
printf("Error in getdfree() call\n");
exit(1);
}
avail = (long) free.df_avail
* (long) free.df_bsec
* (long) free.df_sclus;
printf("The current drive has %ld bytes available\n", avail);
return 0;
}
Portability
dos.h
Category
Prototype
void gettime(struct time *timep);
void settime(struct time *timep);
Description
3
Gets and sets the system time.
gettime fills in the time structure pointed to by timep with the system's current time.
• settime sets the system time to the values in the time structure pointed to by timep.
The time structure is defined as follows:
struct time {
unsigned char ti_min; /* minutes */
828
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.9.15 unixtodos
Header File
dos.h
Category
Prototype
void unixtodos(long time, struct date *d, struct time *t);
Description
unixtodos converts the UNIX-format time given in time to DOS format and fills in the date and time structures pointed to by d and
t.
time must not represent a calendar time earlier than Jan. 1, 1980 00:00:00.
Return Value
None.
Example
#include <stdio.h>
#include <dos.h>
char *month[] = {"---", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
#define SECONDS_PER_DAY 86400L /* the number of seconds in one day */ 3
struct date dt;
struct time tm;
int main(void)
{
unsigned long val;
/* get today's date and time */
getdate(&dt);
gettime(&tm);
printf("today is %d %s %d\n", dt.da_day, month[dt.da_mon], dt.da_year);
/*convert date and time to unix format (num of seconds since Jan 1, 1970*/
829
C Runtime Library Reference RAD Studio 3.1 C++ Reference
dos.h
Category
Input/output Routines
Prototype
int _unlink(const char *filename);
int _wunlink(const wchar_t *filename);
Description
Deletes a file.
_unlink deletes a file specified by filename. Any drive, path, and file name can be used as a filename. Wildcards are not allowed.
Read-only files cannot be deleted by this call. To remove read-only files, first use chmod or _rtl_chmod to change the read-only
attribute.
_wunlink is the Unicode version of _wunlink. The Unicode version accepts a filename that is a wchar_t character string.
Otherwise, the functions perform identically.
Return Value
On error, it returns -1 and sets the global variable errno to one of the following values:
Example
#include <stdio.h>
#include <io.h>
int main(void)
{
FILE *fp = fopen("junk.jnk","w");
int status;
fprintf(fp,"junk");
830
3.1 C++ Reference RAD Studio C Runtime Library Reference
status = access("junk.jnk",0);
if (status == 0)
printf("File exists\n");
else
printf("File doesn't exist\n");
fclose(fp);
unlink("junk.jnk");
status = access("junk.jnk",0);
if (status == 0)
printf("File exists\n");
else
printf("File doesn't exist\n");
return 0;
}
Portability
3.1.4.10 errno.h
The following functions, macros, and classes are provided in errno.h:
Topics
Name Description
EDOM, ERANGE, #defines ( see page 832) Header File
errno.h, math.h
Description
These are the mnemonics and meanings for the error numbers found in math.h
and errno.
_doserrno ( see page 833) Header File
errno.h
Syntax
extern int _doserrno;
Description
_doserrno is a variable that maps many operating system error codes to errno;
however, perror does not use _doserrno directly.
When an operating system call results in an error, _doserrno is set to the actual
operating system error code. errno is a parallel error variable inherited from UNIX.
The following list gives mnemonics for the actual DOS error codes to which
_doserrno can be set. (This value of _doserrno may or may not be mapped
(through errno) to an equivalent error message string in _sys_errlist.
errno (C Runtime Library Reference) ( see page 833) Header File
errno.h
Syntax
extern int errno;
Description
errno is used by perror to print error messages when certain library routines fail
to accomplish their appointed tasks. 3
When an error in a math or system call occurs, errno is set to indicate the type of
error. Sometimes errno and _doserrno are equivalent. At other times, errno does
not contain the actual operating system error code, which is contained in
_doserrno. Still other errors might occur that set only errno, not _doserrno.
831
C Runtime Library Reference RAD Studio 3.1 C++ Reference
errno.h, math.h
3 Description
These are the mnemonics and meanings for the error numbers found in math.h and errno.
Name Meaning
EDOM Error code for math domain error
ERANGE Error code for result out of range
832
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.10.2 _doserrno
Header File
errno.h
Syntax
extern int _doserrno;
Description
_doserrno is a variable that maps many operating system error codes to errno; however, perror does not use _doserrno directly.
When an operating system call results in an error, _doserrno is set to the actual operating system error code. errno is a parallel
error variable inherited from UNIX.
The following list gives mnemonics for the actual DOS error codes to which _doserrno can be set. (This value of _doserrno may
or may not be mapped (through errno) to an equivalent error message string in _sys_errlist.
errno.h 3
Syntax
extern int errno;
Description
errno is used by perror to print error messages when certain library routines fail to accomplish their appointed tasks.
When an error in a math or system call occurs, errno is set to indicate the type of error. Sometimes errno and _doserrno are
833
C Runtime Library Reference RAD Studio 3.1 C++ Reference
equivalent. At other times, errno does not contain the actual operating system error code, which is contained in _doserrno. Still
other errors might occur that set only errno, not _doserrno.
errno.h
Description
These are the mnemonics and meanings for the error numbers found in errno.
Each value listed can be used to index into the sys_errlist array for displaying messages.
Mnemonic Meaning
EZERO Error 0
EINVFNC Invalid function number
ENOFILE File not found
ENOPATH Path not found
ECONTR Memory blocks destroyed
EINVMEM Invalid memory block address
EINVENV Invalid environment
EINVFMT Invalid format
EINVACC Invalid access code
EINVDAT Invalid data
EINVDRV Invalid drive specified
ECURDIR Attempt to remove CurDir
ENOTSAM Not same device
ENMFILE No more files
ENOENT No such file or directory
EMFILE Too many open files
EACCES Permission denied
EBADF Bad file number
ENOMEM Not enough memory
EFAULT Unknown error
ENODEV No such device
3
EINVAL Invalid argument
E2BIG Arg list too long
ENOEXEC Exec format error
EXDEV Cross-device link
ENFILE Too many open files
ECHILD No child process
834
3.1 C++ Reference RAD Studio C Runtime Library Reference
ENOTTY Terminal control function attempted on a file that is not a terminal. (POSIX – Not used in Win32
applications.)
ETXTBSY Not used in Win32 applications
EFBIG An attempt was made to write to a file, beyond the maximum file size. (POSIX – Not used in Win32
applications.)
ESOSPC No space left on device
ESPIPE Illegal seek
EROFS Read-only file system
EMLINK The number of links exceeds LINK_MAX. (POSIX – Not used in Win32 applications.)
EPIPE Broken pipe
EDOM Math argument
ERANGE Result too large
EEXIST File already exists
EDEADLOCK Locking violation
EPERM Operation not permitted
ESRCH No such process id. (POSIX – Not used in Win32 applications.)
EINTR Interrupted function call
EIO Input/output error
ENXIO No such device or address
EAGAIN Resource temporarily unavailable
ENOTBLK Not used in Win32 applications
EBUSY Resource busy
ENOTDIR A pathname component is not a directory. (POSIX – Not used in Win32 applications.)
EISDIR An attempt was made to open a directory for writing, or to rename a file with the same name as an
existing directory. (POSIX – Not used in Win32 applications.)
EUCLEAN Not used in Win32 console applications
3.1.4.10.5 perror,_wperror
Header File
errno.h, stdio.h
Category
Prototype 3
void perror(const char *s);
void _wperror(const wchar_t *s);
Description
perror prints to the stderr stream (normally the console) the system error message for the last library routine that set the global
835
C Runtime Library Reference RAD Studio 3.1 C++ Reference
variable errno.
It prints the argument s followed by a colon (:) and the message corresponding to the current value of the global variable errno
and finally a new line. The convention is to pass the file name of the program as the argument string.
The array of error message strings is accessed through the global variable _sys_errlist. The global variable errno can be used as
an index into the array to find the string corresponding to the error number. None of the strings include a newline character.
The global variable _sys_nerr contains the number of entries in the array.
Bad address
Broken pipe
Cross-device link
Error 0
Illegal seek
Input/output error
Invalid environment
Invalid format
Is a directory
Math argument
836
3.1 C++ Reference RAD Studio C Runtime Library Reference
No child processes
No more files
No such device
No such process
Not a directory
Permission denied
Possible deadlock
Resource busy
Example
#include <stdio.h>
int main(void)
{
FILE *fp;
fp = fopen("perror.dat", "r");
if (!fp)
perror("Unable to open file for reading");
return 0;
}
Portability
3.1.4.10.6 _sys_errlist
Header File
errno.h
837
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Syntax
extern char * _sys_errlist[ ];
Description
_sys_errlist is used by perror to print error messages when certain library routines fail to accomplish their appointed tasks.
To provide more control over message formatting, the array of message strings is provided in _sys_errlist. You can use errno as
an index into the array to find the string corresponding to the error number. The string does not include any newline character.
Example
printf("%s\n", _sys_errlist[ENOPATH]);
This code statement that uses the Mnemonic ENOPATH will output the string "Path not found".
The following table gives mnemonics and their meanings for the values stored in _sys_errlist. The list is alphabetically ordered
for ease your reading convenience. For the numerical ordering, see the header file errno.h.
3.1.4.10.7 _sys_nerr
Header File
errno.h
Syntax
extern int _sys_nerr;
Description
_sys_nerr is used by perror to print error messages when certain library routines fail to accomplish their appointed tasks.
3.1.4.11 except.h
The following functions, macros, and classes are provided in except.h:
Topics
Name Description
__throwExceptionName ( see page 840) Header File
except.h
Syntax
extern char * _RTLENTRY __ThrowExceptionName();
#define __throwExceptionName __ThrowExceptionName()
Description
Use this global variable to get the name of a thrown exception. The output for this
variable is a printable character string.
__throwFileName ( see page 840) Header File
3 except.h
Syntax
extern char * _RTLENTRY __ThrowFileName();
#define __throwFileName __ThrowFileName()
Description
Use this global variable to get the name of a thrown exception. The output for this
variable is a printable character string.
To get the file name for a thrown exception with __throwFileName, you must
compile the module with the -xp compiler option.
838
3.1 C++ Reference RAD Studio C Runtime Library Reference
839
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.11.1 __throwExceptionName
Header File
except.h
Syntax
extern char * _RTLENTRY __ThrowExceptionName();
#define __throwExceptionName __ThrowExceptionName()
Description
Use this global variable to get the name of a thrown exception. The output for this variable is a printable character string.
3.1.4.11.2 __throwFileName
Header File
except.h
Syntax
extern char * _RTLENTRY __ThrowFileName();
#define __throwFileName __ThrowFileName()
Description
Use this global variable to get the name of a thrown exception. The output for this variable is a printable character string.
To get the file name for a thrown exception with __throwFileName, you must compile the module with the -xp compiler option.
3.1.4.11.3 __throwLineNumber
Header File
except.h
Syntax
extern unsigned _RTLENTRY __ThrowLineNumber();
#define __throwLineNumber __ThrowLineNumber()
Description
Use this global variable to get the name of a thrown exception. The output for this variable is a printable character string.
To get the line number for a thrown exception with __throwLineNumber, you must compile the module with the -xp compiler
option.
3
3.1.4.11.4 set_terminate
Header File
except.h
Syntax
840
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
set_terminate lets you install a function that defines the program's termination behavior when a handler for the exception cannot
be found. The actions are defined in t_func, which is declared to be a function of type terminate_handler. A terminate_handler
type, defined in except.h, is a function that takes no arguments, and returns void.
By default, an exception for which no handler can be found results in the program calling the terminate function. This will
normally result in a call to abort. The program then ends with the message Abnormal program termination. If you want some
function other than abort to be called by the terminate function, you should define your own t_func function. Your t_func function
is installed by set_terminate as the termination function. The installation of t_func lets you implement any actions that are not
taken by abort.
Return Value
The definition of t_func must terminate the program. Such a user-defined function must not return to its caller, the terminate
function. An attempt to return to the caller results in undefined program behavior. It is also an error for t_func to throw an
exception.
3.1.4.11.5 set_unexpected
Header File
except.h
Syntax
typedef void ( * unexpected_handler )();
unexpected_handler set_unexpected(unexpected_handler unexpected_func);
Description
set_unexpected lets you install a function that defines the program's behavior when a function throws an exception not listed in
its exception specification. The actions are defined in unexpected_func, which is declared to be a function of type
unexpected_handler. An unexpected_handler type, defined in except.h, is a function that takes no arguments, and returns void.
By default, an unexpected exception causes unexpected to be called. If is defined, it is subsequently called by unexpected.
Program control is then turned over to the user-defined unexpected_func. Otherwise, terminate is called.
Return Value
The definition of unexpected_func must not return to its caller, the unexpected function. An attempt to return to the caller results
in undefined program behavior.
3.1.4.11.6 terminate
Header File
except.h
Syntax
841
C Runtime Library Reference RAD Studio 3.1 C++ Reference
void terminate();
Description
The function terminate can be called by unexpected or by the program when a handler for an exception cannot be found. The
default action by terminate is to call abort. Such a default action causes immediate program termination.
You can modify the way that your program will terminate when an exception is generated that is not listed in the exception
specification. If you do not want the program to terminate with a call to abort, you can instead define a function to be called. Such
a function (called a terminate_handler) will be called by terminate if it is registered with set_terminate.
Return Value
None.
3.1.4.11.7 unexpected
Header File
except.h
Syntax
void unexpected();
Description
The unexpected function is called when a function throws an exception not listed in its exception specification. The program calls
unexpected, which by default calls any user-defined function registered by set_unexpected. If no function is registered with
set_unexpected, the unexpected function then calls terminate.
Return Value
3.1.4.12 fastmath.h
The following functions, macros, and classes are provided in fastmath.h:
Topics
Name Description
Using fastmath math routines ( see page 842) Header File
fastmath.h
Category
Math Routines
Description
The FastMath routines are high performance math routines that don't check for
most error conditions and never call matherr. They are coded for maximum
speed. These functions are never exported from the RTLDLL, which means that
they always get linked directly into the PE file that is being created.
3 When you include fastmath.h, the following math functions are remapped to
these fastmath functions.
fastmath.h
842
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Math Routines
Description
The FastMath routines are high performance math routines that don't check for most error conditions and never call matherr.
They are coded for maximum speed. These functions are never exported from the RTLDLL, which means that they always get
linked directly into the PE file that is being created.
When you include fastmath.h, the following math functions are remapped to these fastmath functions.
If you don't want the standard C function names remapped to the FastMath versions, then define _FM_NO_REMAP. The 3
FastMath routines can still be called with their _fm_xxx names.
The following additional functions are available in FastMath; they are not directly supported in the regular RTL:
void _FMAPI _fm_sincos(double __a, double *__x, double *__y);
void _FMAPI _fm_sincosl(long double __a, long double *__x, long double *__y);
long double _FMAPI _fm_atanhl (long double __x);
843
C Runtime Library Reference RAD Studio 3.1 C++ Reference
_Fm_init is a function that can be called to mask all fpu exceptions prior to using the FastMath routines.
3.1.4.13 fcntl.h
The following functions, macros, and classes are provided in fcntl.h:
Topics
Name Description
O_xxxx #defines ( see page 845) Header File
fcntl.h
Description
These #defines are bit definitions for a file-access argument.
These RTL file-open functions use some (not all) of these definitions:
• fdopen
• fopen
• freopen
• _fsopen
• open
• _rtl_open
• sopen
sopen also uses file-sharing symbolic constants in the
file-access argument.
_fmode ( see page 847) Header File
fcntl.h
Syntax
extern int _fmode;
Description
_fmode determines in which mode (text or binary) files will be opened and
translated. The value of _fmode is O_TEXT by default, which specifies that files
will be read in text mode. If _fmode is set to O_BINARY, the files are opened and
read in binary mode. (O_TEXT and O_BINARY are defined in fcntl.h.)
In text mode, carriage-return/linefeed (CR/LF) combinations are translated to a
single linefeed character (LF) on input. On output, the reverse is true: LF
characters are translated to CR/LF combinations.
In binary mode, no such translation occurs.
You can... more ( see page 847)
844
3.1 C++ Reference RAD Studio C Runtime Library Reference
fcntl.h 3
Description
These RTL file-open functions use some (not all) of these definitions:
• fdopen
• fopen
845
C Runtime Library Reference RAD Studio 3.1 C++ Reference
• freopen
• _fsopen
• open
• _rtl_open
• sopen
sopen also uses file-sharing symbolic constants in the file-access argument.
Constant Description
Read/Write flag
Note: Only one of the O_DENYxxx options can be included in a single open. These file-sharing attributes are in addition to any
locking performed on the files.
846
3.1 C++ Reference RAD Studio C Runtime Library Reference
Do not modify
O_CHANGED Special DOS read-only bit
O_DEVICE Special DOS read-only bit
3.1.4.13.2 _fmode
Header File
fcntl.h
Syntax
extern int _fmode;
Description
_fmode determines in which mode (text or binary) files will be opened and translated. The value of _fmode is O_TEXT by
default, which specifies that files will be read in text mode. If _fmode is set to O_BINARY, the files are opened and read in binary
mode. (O_TEXT and O_BINARY are defined in fcntl.h.)
In text mode, carriage-return/linefeed (CR/LF) combinations are translated to a single linefeed character (LF) on input. On
output, the reverse is true: LF characters are translated to CR/LF combinations.
You can override the default mode as set by _fmode by specifying a t (for text mode) or b (for binary mode) in the argument type
in the library functions fopen, fdopen, and freopen. Also, in the function open, the argument access can include either
O_BINARY or O_TEXT, which will explicitly define the file being opened (given by the path argument to the open function) to be
in either binary or text mode.
3.1.4.13.3 _pipe
Header File
io.h, fcntl.h
Category
Input/output Routines
Syntax
int _pipe(int *handles, unsigned int size, int mode);
Description
The _pipe function creates an anonymous pipe that can be used to pass information between processes. The pipe is opened for
3
both reading and writing. Like a disk file, a pipe can be read from and written to, but it does not have a name or permanent
storage associated with it; data written to and from the pipe exist only in a memory buffer managed by the operating system.
The read handle is returned to handles[0], and the write handle is returned to handles[1]. The program can use these handles in
subsequent calls to read, write, dup, dup2, or close. When all pipe handles are closed, the pipe is destroyed.
The size of the internal pipe buffer is size. A recommended minimum value is 512 bytes.
847
C Runtime Library Reference RAD Studio 3.1 C++ Reference
If mode is zero, the translation mode is determined by the external variable _fmode.
Return Value
On success, _pipe returns 0 and returns the pipe handles to handles[0] and handles[1].
Example
/*
There are two short programs here. SEND spawns a child
process, RECEIVE. Each process holds one end of a
pipe. The parent transmits its command-line argument
to the child, which prints the string and exits.
IMPORTANT: The parent process must be linked with
the \32bit\fileinfo.obj file. The code in fileinfo
enables a parent to share handles with a child.
Without this extra information, the child cannot use
the handle it receives.
*/
/* SEND */
#include <fcntl.h> // _pipe()
#include <io.h> // write()
#include <process.h> // spawnl() cwait()
#include <stdio.h> // puts() perror()
#include <stdlib.h> // itoa()
#include <string.h> // strlen()
#define DECIMAL_RADIX 10 // for atoi()
enum PIPE_HANDLES { IN, OUT }; // to index the array of handles
int main(int argc, char *argv[])
{
int handles[2]; // in- and
//outbound pipe handles
char handleStr[10]; // a handle
//stored as a string
int pid;
// system's ID for child process
if (argc <= 1)
{
puts("No message to send.");
return(1);
}
if (_pipe(handles, 256, O_TEXT) != 0)
{
perror("Cannot create the pipe");
3 return(1);
}
// store handle as a string for passing on the command line
itoa(handles[IN], handleStr, DECIMAL_RADIX);
// create the child process, passing it the inbound pipe handle
spawnl(P_NOWAIT, "receive.exe", "receive.exe", handleStr, NULL);
// transmit the message
write(handles[OUT], argv[1], strlen(argv[1])+1);
// when done with the pipe, close both handles
close(handles[IN]);
close(handles[OUT]);
848
3.1 C++ Reference RAD Studio C Runtime Library Reference
io.h, fcntl.h
Category
Input/output Routines
Prototype
int open(const char *path, int access [, unsigned mode]);
int _wopen(const wchar_t *path, int access [, unsigned mode]);
Description
open opens the file specified by path, then prepares it for reading and/or writing as determined by the value of access.
To create a file in a particular mode, you can either assign to the global variable _fmode or call open with the O_CREAT and
O_TRUNC options ORed with the translation mode desired.
open("XMP",O_CREAT|O_TRUNC|O_BINARY,S_IREAD)
creates a binary-mode, read-only file named XMP, truncating its length to 0 bytes if it already existed.
For open, access is constructed by bitwise ORing flags from the following lists. Only one flag from the first list can be used (and
one must be used); the remaining flags can be used in any logical combination.
849
C Runtime Library Reference RAD Studio 3.1 C++ Reference
O_EXCL Used only with O_CREAT. If the file already exists, an error is returned.
O_BINARY Can be given to explicitly open the file in binary mode.
O_TEXT Can be given to explicitly open the file in text mode.
If neither O_BINARY nor O_TEXT is given, the file is opened in the translation mode set by the global variable _fmode.
If the O_CREAT flag is used in constructing access, you need to supply the mode argument to open from the following symbolic
constants defined in sys\stat.h.
Return Value
On success, open returns a nonnegative integer (the file handle). The file pointer, which marks the current position in the file, is
set to the beginning of the file.
On error, open returns -1 and the global variable errno is set to one of the following values:
Example
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char msg[] = "Hello world";
if ((handle = open("TEST.$$$", O_CREAT | O_TEXT)) == -1)
{
perror("Error:");
return 1;
}
write(handle, msg, strlen(msg));
close(handle);
return 0;
}
Portability
850
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Input/output Routines
Prototype
int _sopen(char *path, int access, int shflag[, int mode]);
int _wsopen(wchar_t *path, int access, int shflag[, int mode]);
Description
_sopen opens the file given by path and prepares it for shared reading or writing, as determined by access, shflag, and mode.
_wsopen is the Unicode version of _sopen. The Unicode version accepts a filename that is a wchar_t character string.
Otherwise, the functions perform identically.
For _sopen, access is constructed by ORing flags bitwise from the following lists:
Read/write flags
If neither O_BINARY nor O_TEXT is given, the file is opened in the translation mode set by the global variable _fmode.
If the O_CREAT flag is used in constructing access, you need to supply the mode argument to _sopen from the following 3
symbolic constants defined in sys\stat.h.
shflag specifies the type of file-sharing allowed on the file path. Symbolic constants for shflag are defined in share.h.
851
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
On success, _sopen returns a nonnegative integer (the file handle), and the file pointer (that marks the current position in the file)
is set to the beginning of the file.
Example
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int handle,
handle1;
handle = sopen("c:\\autoexec.bat", O_RDONLY, SH_DENYWR, S_IREAD);
if (handle == -1)
{
perror (sys_errlist[errno]);
exit (1);
}
if (!handle)
{
printf("sopen failed\n");
exit(1);
}
/* Attempt sopen for write.
*/
handle1 = sopen("c:\\autoexec.bat", O_RDONLY, SH_DENYWR, S_IREAD);
if (handle1 == -1)
{
3 perror (sys_errlist[errno]);
exit (1);
}
if (!handle1)
{
printf("sopen failed\n");
exit(1);
}
close (handle);
close (handle1);
852
3.1 C++ Reference RAD Studio C Runtime Library Reference
return 0;
}
Portability
3.1.4.14 float.h
The following functions, macros, and classes are provided in float.h:
Topics
Name Description
CW_DEFAULT #define ( see page 856) Header File
float.h
Description
Default control word for 80x87 math coprocessor.
_chgsign, _chgsignl ( see page 856) Header File
float.h
Category
Math Routintes
Prototype
double _chgsign(double d);
long double _chgsignl(long double ld);
Description
Reverses the sign of a double-precision floating-point argument, d.
_chgsignl is the long double version; it takes a long double argument and
returns a long double result.
Return Value
Returns a value of the same magnitude and exponent as the argument, but with
the opposite sign. There is no error return value.
Portability
_clear87, _clearfp ( see page 857) Header File
float.h
Category
Math Routines
Prototype
unsigned int _clear87 (void);
unsigned int _clearfp (void);
Description
Clears the floating-point status word.
_clear87 clears the floating-point status word, which is a combination of the
80x87 status word and other conditions detected by the 80x87 exception handler.
_clearfp is identical to _clear87 and is for Microsoft compatibility.
Return Value
The bits in the value returned indicate the floating-point status before it was
cleared. For information on the status word, refer to the constants defined in
float.h.
Example
3
853
C Runtime Library Reference RAD Studio 3.1 C++ Reference
854
3.1 C++ Reference RAD Studio C Runtime Library Reference
855
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3 float.h
Description
856
3.1 C++ Reference RAD Studio C Runtime Library Reference
float.h
Category
Math Routintes
Prototype
double _chgsign(double d);
long double _chgsignl(long double ld);
Description
_chgsignl is the long double version; it takes a long double argument and returns a long double result.
Return Value
Returns a value of the same magnitude and exponent as the argument, but with the opposite sign. There is no error return value.
Portability
float.h
Category
Math Routines
Prototype
unsigned int _clear87 (void);
unsigned int _clearfp (void);
Description
_clear87 clears the floating-point status word, which is a combination of the 80x87 status word and other conditions detected by
the 80x87 exception handler.
Return Value 3
The bits in the value returned indicate the floating-point status before it was cleared. For information on the status word, refer to
the constants defined in float.h.
Example
#include <stdio.h>
#include <float.h>
int main(void)
{
857
C Runtime Library Reference RAD Studio 3.1 C++ Reference
float x;
double y = 1.5e-100;
printf("\nStatus 87 before error: %X\n", _status87());
x = y; /* create underflow and precision loss */
printf("Status 87 after error: %X\n", _status87());
_clear87();
printf("Status 87 after clear: %X\n", _status87());
y = x;
return 0;
}
Portability
float.h
Category
Math Routines
Prototype
unsigned int _control87(unsigned int newcw, unsigned int mask);
unsigned int _controlfp(unsigned int newcw, unsigned int mask);
Description
The floating-point control word is an unsigned int that, bit by bit, specifies certain modes in the floating-point package; namely,
the precision, infinity, and rounding modes. Changing these modes lets you mask or unmask floating-point exceptions.
_control87 matches the bits in mask to the bits in newcw. If a mask bit equals 1, the corresponding bit in newcw contains the
new value for the same bit in the floating-point control word, and _control87 sets that bit in the control word to the new value.
_controlfp is for Microsoft compatibility. _controlfp is identical to _control87 except that it always removes (turns off) the
EM_DEMORMAL bit from the mask parameter.
Return Value
The bits in the value returned reflect the new floating-point control word. For a complete definition of the bits returned by
_control87, see the header file float.h.
858
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
float.h
Category
Math Routines
Prototype
double _copysign(double da, double db);
long double _copysignl(long double lda, long double ldb);
Description
Returns the double-precision floating point argument da, with the same sign as the double-precision floating-point argument db.
_copysignl is the long double version; it takes a long double argument and returns a long double result.
Return Value
Returns the first value with the same magnitude and exponent, but with the sign of the second value. There is no error value
returned.
Portability
float.h
Category
Math Routines
3
Prototype
int _finite(double d);
int _finitel(long double ld);
Description
859
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
Portability
float.h
Category
Math Routines
Prototype
int _fpclass(double d);
int _fpclassl(long double ld);
Description
Returns an integer value representing the type (class) of an IEEE real for doubles. This value contains information on the
floating-point class of the argument.
_fpclassl is the long double version; it takes a long double argument and returns the type (class) of an IEEE real for long
doubles.
Return Value
Returns an integer value that indicates the floating-point class of its argument. The possible values, which are listed in the table
below, are defined in FLOAT.H.
Portability
3.1.4.14.8 _fpreset
Header File
3
float.h
Category
Math Routines
Prototype
void _fpreset(void);
860
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
_fpreset reinitializes the floating-point math package. This function is usually used in conjunction with system or the exec... or
spawn... functions. It is also used to recover from floating-point errors before calling longjmp.
Note: If an 80x87 coprocessor is used in a program a child process (executed by the system, or by an exec... or spawn...
function) might alter the parent process' floating-point state.
float.h
Category
Prototype
int _isnan(double d);
int _isnanl(long double ld);
Description
Return Value
Returns a nonzero value (TRUE) if the value passed in is a NaN; otherwise it returns 0 (FALSE). The non-zero return value
corresponds to either _FPCLASS_SNAN, if the NaN is of the signaling type, or _FPCLASS_QNAN, if the NaN is of the quiet
type. The values for _FPCLASS_SNAN and _FPCLASS_QNAN are in float.h.
Portability 3
POSIX Win32 ANSI C ANSI C++
_isnan +
_isnanl +
861
C Runtime Library Reference RAD Studio 3.1 C++ Reference
float.h
Category
Math Routines
Prototype
double _logb(double d);
long double _logbl(long double ld);
Description
Extracts the exponential value of a double-precision floating-point argument. If the argument is denormalized, it is treated as if it
were normalized.
_logbl is the long double version; it takes a long double argument and returns a long double result.
Return Value
Portability
float.h
Category
Math Routines
Prototype
double _nextafter(double da, double db);
long double _nextafterl(long double lda, long double ldb);
Description
3 Takes two doubles (da and db) and returns the closest representable neighbor of da in the direction toward db.
If da == db, _nextafter returns da, with no exception triggered. If either da or db is a quiet NaN, then the return value is one or the
other of the input NaNs.
_nextafterl is the long double version; it takes a long double argument and returns a long double result.
Return Value
Returns the closest representable neighbor of the first argument in the direction toward the second argument.
862
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
float.h
Category
Math Routines
Prototype
double _scalb(double d, long exp);
long double _scalbl(long double ld, long exp);
Description
_scalbl is the long double version; it takes a long double argument and returns a long double result.
Return Value
Returns an exponential value if successful. On overflow (depending on the sign of the argument), the function returns +/–
HUGE_VAL; the ERRNO variable is set to ERANGE.
Portability
float.h
Category
Math Routines
3
Prototype
unsigned int _status87(void);
unsigned int _statusfp(void);
Description
_status87 gets the floating-point status word, which is a combination of the 80x87 status word and other conditions detected by
863
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
The bits in the return value give the floating-point status. See float.h for a complete definition of the bits returned by _status87
and _status87.
Portability
3.1.4.15 io.h
The following functions, macros, and classes are provided in io.h:
Topics
Name Description
_findclose ( see page 873) Header File
io.h
Category
Directory Control Routines
Prototype
int _findclose(long handle);
Description
Closes the specified search handle and releases associated resources
associated with previous calls to findfirst/findnext. The handle parameter is the
search handle returned by the previous call to _findfirst.
This function is provided for Microsoft compatibility.
Return Value
On success, returns 0.
Otherwise, returns –1 and sets errno to:
ENOENTFile specification that could not be matched
Portability
_findfirst, __wfindfirst ( see page 874) Header File
io.h, wchar.h
Category
Directory Control Routines
Prototype
long _findfirst(char *filter, struct _finddata_t *fileinfo);
long __wfindfirst(wchar_t *filter, struct _wfinddata_t
*fileinfo);
Description
Begins a search of a disk directory to find information about the first instance of a
filename that matches a specified filter. The filter parameter is a string that
specifies which files to return. Wildcards may be used in the filter. The fileinfo
parameter is the file information buffer. If a matching file is found, the fileinfo
3 structure is filled with the file-directory information.
These functions are provided for Microsoft compatibility.
Return Value
On success, returns a unique... more ( see page 874)
864
3.1 C++ Reference RAD Studio C Runtime Library Reference
865
C Runtime Library Reference RAD Studio 3.1 C++ Reference
866
3.1 C++ Reference RAD Studio C Runtime Library Reference
867
C Runtime Library Reference RAD Studio 3.1 C++ Reference
868
3.1 C++ Reference RAD Studio C Runtime Library Reference
869
C Runtime Library Reference RAD Studio 3.1 C++ Reference
870
3.1 C++ Reference RAD Studio C Runtime Library Reference
• a terminal
• a console
• a printer
• a serial port
Return Value
If the device is one of the four character devices listed
above, isatty returns a nonzero integer. If it is not such a
device, isatty returns 0.
Example
lock ( see page 902) Header File
io.h
Category
Input/output Routines
Prototype
int lock(int handle, long offset, long length);
Description
Sets file-sharing locks.
lock provides an interface to the operating system file-sharing mechanism.
A lock can be placed on arbitrary, nonoverlapping regions of any file. A program
attempting to read or write into a locked region will retry the operation three
times. If all three retries fail, the call fails with an error.
Return Value
lock returns 0 on success. On error, lock returns -1 and sets the global variable
errno to
locking ( see page 903) Header File
io.h, sys\locking.h
Category
Input/output Routines
Prototype
int locking(int handle, int cmd, long length);
Description
Sets or resets file-sharing locks.
locking provides an interface to the operating system file-sharing mechanism.
The file to be locked or unlocked is the open file specified by handle. The region
to be locked or unlocked starts at the current file position, and is length bytes
long.
Locks can be placed on arbitrary, nonoverlapping regions of any file. A program
attempting to read or write into a locked region will retry the operation three
times. If all three retries fail, the call fails with... more ( see page 903)
lseek ( see page 904) Header File
io.h
3
Category
Input/output Routines
Prototype
long lseek(int handle, long offset, int fromwhere);
Description
Moves file pointer.
lseek sets the file pointer associated with handle to a new position offset bytes
beyond the file location given by fromwhere. fromwhere must be one of the
following symbolic constants (defined in io.h):
871
C Runtime Library Reference RAD Studio 3.1 C++ Reference
872
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.15.1 _findclose
Header File
io.h
Category
3
Directory Control Routines
Prototype
int _findclose(long handle);
Description
Closes the specified search handle and releases associated resources associated with previous calls to findfirst/findnext. The
handle parameter is the search handle returned by the previous call to _findfirst.
873
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
On success, returns 0.
Portability
See Also
_findfirst ( see page 874)
io.h, wchar.h
Category
Prototype
long _findfirst(char *filter, struct _finddata_t *fileinfo);
long __wfindfirst(wchar_t *filter, struct _wfinddata_t *fileinfo);
Description
Begins a search of a disk directory to find information about the first instance of a filename that matches a specified filter. The
filter parameter is a string that specifies which files to return. Wildcards may be used in the filter. The fileinfo parameter is the file
information buffer. If a matching file is found, the fileinfo structure is filled with the file-directory information.
Return Value
On success, returns a unique search handle to a file or group of files matching the filter specification.
874
3.1 C++ Reference RAD Studio C Runtime Library Reference
See Also
_findclose ( see page 873)
io.h, wchar.h
Category
Prototype
long _findfirsti64(char *filter, struct _finddatai64_t *fileinfo);
long _wfindfirsti64(wchar_t *filter, struct _wfinddatai64_t *fileinfo);
Description
Begins a search of a disk directory to find information about the first instance of a filename that matches a specified filter. The
filter parameter is a string that specifies which files to return. Wildcards may be used in the filter. The fileinfo parameter is the file
information buffer. If a matching file is found, the fileinfo structure is filled with the file-directory information.
These i64 versions are for 64 bit filesize use and are provided for Microsoft compatibility.
Return Value
On success, returns a unique search handle identifying the file or group of files matching the filter specification.
Portability
io.h, wchar.h 3
Category
Prototype
long _findnext(long handle, struct _finddata_t *fileinfo);
long __wfindnext(long handle, struct _wfinddata_t *fileinfo);
875
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
Finds subsequent files, if any, that match the filter argument in a previous call to _findfirst/__wfindfirst. Then,
_findnext/__wfindnext updates the fileinfo structure with the necessary information for continuing the search. One file name for
each call to _tfindnext is returned until no more files are found in the directory matching the pathname (filter).
The handle parameter is the search handle returned by a previous call to _findfirst. The fileinfo parameter is the file information
buffer.
Return Value
On success, returns 0.
Portability
See Also
_findclose ( see page 873)
io.h, wchar.h
Category
Prototype
long _findnexti64(long handle, struct _finddatai64_t *fileinfo);
__int64 _wfindnexti64(long handle, struct _wfinddata_t *fileinfo);
Description
Finds subsequent files, if any, that match the filter argument in a previous call to _findfirsti64/_wfindfirsti64. Then,
_findnexti64/_wfindnexti64 updates the fileinfo structure with the necessary information for continuing the search. One file name
for each call to _tfindnext is returned until no more files are found in the directory matching the pathname (filter).
3
The handle parameter is the search handle returned by a previous call to _findfirst. The fileinfo parameter is the file information
buffer.
These i64 versions are for 64 bit filesize use and are provided for Microsoft compatibility.
Return Value
On success, returns 0.
876
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
3.1.4.15.6 _get_osfhandle
Header File
io.h
Category
Input/output Routines
Prototype
long _get_osfhandle(int filehandle);
Description
The _get_osfhandle function associates an operating system file handle with an existing runtime file handle. The variable
filehandle is the file handle of your program.
Return value
On success, _get_osfhandle returns an operating system file handle corresponding to the variable filehandle.
On error, the function returns -1 and sets the global variable errno to
Example
#include <windows.h>
#include <fcntl.h>
#include <stdio.h>
#include <io.h>
//Example for _get_osfhandle() and _open_osfhandle()
BOOL InitApplication(HINSTANCE hInstance);
HWND InitInstance(HINSTANCE hInstance, int nCmdShow);
LRESULT FAR PASCAL _export MainWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
Example_get_osfhandle(HWND hWnd);
#pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 3
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; // message
if (!InitApplication(hInstance)) // Initialize shared things
return (FALSE); // Exits if unable to initialize
/* Perform initializations that apply to a specific instance */
if (!(InitInstance(hInstance, nCmdShow)))
return (FALSE);
/* Acquire and dispatch messages until a WM_QUIT message is received. */
877
C Runtime Library Reference RAD Studio 3.1 C++ Reference
878
3.1 C++ Reference RAD Studio C Runtime Library Reference
case WM_QUIT:
case WM_DESTROY: // message: window being destroyed
PostQuitMessage(0);
break;
default: // Passes it on if unprocessed
return (DefWindowProc(hWnd, message, wParam, lParam));
}
}
Example_get_osfhandle(HWND hWnd)
{
long osfHandle;
char str[128];
int fHandle = open("file1.c", O_CREAT|O_TEXT);
if(fHandle != -1)
{
osfHandle = _get_osfhandle(fHandle);
sprintf(str, "file handle = %lx OS file handle = %lx", fHandle, osfHandle);
MessageBox(hWnd,str,"_get_osfhandle",MB_OK|MB_ICONINFORMATION);
close(fHandle);
fHandle = _open_osfhandle(osfHandle, O_TEXT );
sprintf(str, "file handle = %lx OS file handle = %lx", fHandle, osfHandle);
MessageBox(hWnd,str,"_open_osfhandle",MB_OK|MB_ICONINFORMATION);
close(fHandle);
}
else
MessageBox(hWnd,"File Open Error","WARNING",MB_OK|MB_ICONSTOP);
return 0;
}
Portability
3.1.4.15.7 _open_osfhandle
Header File
io.h
Category
Input/output Routines
Prototype
int _open_osfhandle(long osfhandle, int flags);
Description
The _open_osfhandle function allocates a runtime file handle and sets it to point to the operating system file handle specified by
osfhandle. 3
The value flags is a bitwise OR combination of one or more of the following manifest constants (defined in fcntl.h):
O_APPEND Repositions the file pointer to the end of the file before every write operation.
O_RDONLY Opens the file for reading only.
O_TEXT Opens the file in text (translated) mode.
879
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
Portability
io.h
Category
Input/output Routines
Prototype
int _rtl_chmod(const char *path, int func [, int attrib]);
int _wrtl_chmod(const wchar_t *path, int func, ... );
Description
which is obsolete_rtl_chmod can either fetch or set file attributes. If func is 0, _rtl_chmod returns the current attributes for the file.
If func is 1, the attribute is set to attrib.
Return Value
On error, it returns a value of -1 and sets the global variable errno to one of the following values:
3 ENOENT Path or filename not found
EACCES Permission denied
Example
#include <errno.h>
#include <stdio.h>
#include <dir.h>
#include <io.h>
880
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.15.9 _rtl_close
Header File
io.h
Category
3
Input/output Routines
Prototype
int _rtl_close(int handle);
Description
Closes a file.
881
C Runtime Library Reference RAD Studio 3.1 C++ Reference
The _rtl_close function closes the file associated with handle, a file handle obtained from a call to creat, creatnew, creattemp,
dup, dup2, open, _rtl_creat, or _rtl_open.
It does not write a Ctrl-Z character at the end of the file. If you want to terminate the file with a Ctrl-Z, you must explicitly output
one.
Return Value
On error (if it fails because handle is not the handle of a valid, open file), _rtl_close returns a value of -1 and the global variable
errno is set to
Example
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char msg[] = "Hello world";
if ((handle = _rtl_open("TEST.$$$", O_RDWR)) == -1)
{
perror("Error:");
return 1;
}
_rtl_write(handle, msg, strlen(msg));
_rtl_close(handle);
return 0;
}
Portability
io.h
Category
Input/output Routines
3 Prototype
int _rtl_creat(const char *path, int attrib);
int _wrtl_creat(const wchar_t *path, int attrib);
Description
882
3.1 C++ Reference RAD Studio C Runtime Library Reference
which is obsolete_rtl_creat opens the file specified by path. The file is always opened in binary mode. Upon successful file
creation, the file pointer is set to the beginning of the file. The file is opened for both reading and writing.
If the file already exists its size is reset to 0. (This is essentially the same as deleting the file and creating a new file with the
same name.)
The attrib argument is an OR’ed combination of one or more of the following constants (defined in dos.h):
Return Value
On error, it returns -1 and sets the global variable errno to one of the following values:
EACCESPermission denied
Example
#include <string.h>
#include <stdio.h>
#include <io.h>
int main() {
unsigned count;
int handle;
char buf[11] = "0123456789";
/* Create a 10-byte file using _rtl_creat. */
if ((handle = _rtl_creat("DUMMY2.FIL", 0)) < 0) {
perror("Unable to _rtl_create DUMMY2.FIL");
return 1;
}
if (_rtl_write(handle, buf, strlen(buf)) < 0) {
perror("Unable to _rtl_write to DUMMY2.FIL");
return 1;
}
_rtl_close(handle);
return 0;
}
Portability
3
3.1.4.15.11 _rtl_open, _wrtl_open
Header File
io.h
Category
Input/output Routines
883
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
int _rtl_open(const char *filename, int oflags);
int _wrtl_open(const wchar_t *path, int oflags);
Description
_rtl_open opens the file specified by filename, then prepares it for reading or writing, as determined by the value of oflags. The
file is always opened in binary mode.
oflags uses the flags from the following two lists. Only one flag from List 1 can be used (and one must be used) and the flags in
List 2 can be used in any logical combination.
Only one of the SH_DENYxx values can be included in a single _rtl_open routine. These file-sharing attributes are in addition to
any locking performed on the files.
Return Value
On success:_rtl_open returns a non-negative integer (the file handle). The file pointer, which marks the current position in the
file, is set to the beginning of the file.
On error, it returns -1 and sets the global variable errno to one of the following values:
Example
#include <string.h>
#include <stdio.h>
884
3.1 C++ Reference RAD Studio C Runtime Library Reference
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char msg[] = "Hello world";
if ((handle = _rtl_open("TEST.$$$", O_RDWR)) == -1)
{
perror("Error:");
return 1;
}
_rtl_write(handle, msg, strlen(msg));
_rtl_close(handle);
return 0;
}
Portability
3.1.4.15.12 _rtl_read
Header File
io.h
Category
Input/output Routines
Prototype
int _rtl_read(int handle, void *buf, unsigned len);
Description
This function reads len bytes from the file associated with handle into the buffer pointed to by buf. When a file is opened in text
mode, _rtl_read does not remove carriage returns.
The argument handle is a file handle obtained from a creat, open, dup, or dup2 call.
On disk files, _rtl_read begins reading at the current file pointer. When the reading is complete, it increments the file pointer by
the number of bytes read. On devices, the bytes are read directly from the device.
The maximum number of bytes it can read is UINT_MAX -1 (because UINT_MAX is the same as -1, the error return indicator).
UINT_MAX is defined in limits.h.
3
Return Value
885
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <stdio.h>
#include <io.h>
#include <alloc.h>
#include <fcntl.h>
#include <process.h>
#include <sys\stat.h>
int main(void)
{
void *buf;
int handle, bytes;
buf = malloc(10);
/*
Looks for a file in the current directory named TEST.$$$ and attempts to read 10 bytes from
it. To use this example you should create the file TEST.$$$
*/
if ((handle =
open("TEST.$$$", O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1)
{
printf("Error Opening File\n");
exit(1);
}
if ((bytes = _rtl_read(handle, buf, 10)) == -1) {
printf("Read Failed.\n");
exit(1);
}
else {
printf("_rtl_read: %d bytes read.\n", bytes);
}
return 0;
}
Portability
3.1.4.15.13 _rtl_write
Header File
io.h
Category
Input/output Routines
3 Prototype
int _rtl_write(int handle, void *buf, unsigned len);
Description
Writes to a file.
_rtl_write attempts to write len bytes from the buffer pointed to by buf to the file associated with handle.
886
3.1 C++ Reference RAD Studio C Runtime Library Reference
The maximum number of bytes that _rtl_write can write is UINT_MAX -1 (because UINT_MAX is the same as -1), which is the
error return indicator for _rtl_write. UINT_MAX is defined in limits.h. _rtl_write does not translate a linefeed character (LF) to a
CR/LF pair because all its files are binary files.
If the number of bytes actually written is less than that requested the condition should be considered an error and probably
indicates a full disk.
For disk files, writing always proceeds from the current file pointer. On devices, bytes are directly sent to the device.
For files opened with the O_APPEND option, the file pointer is not positioned to EOF before writing the data.
Return Value
On error, it returns -1 and sets the global variable errno to one of the following values:
Example
#include <stdio.h>
#include <io.h>
#include <alloc.h>
#include <fcntl.h>
#include <process.h>
#include <sys\stat.h>
int main(void)
{
void *buf;
int handle, bytes;
buf = malloc(200);
/*
Create a file name TEST.$$$ in the current directory and writes 200 bytes to it. If TEST.$$$
already exists, it's overwritten.
*/
if ((handle = open("TEST.$$$", O_CREAT | O_WRONLY | O_BINARY,
S_IWRITE | S_IREAD)) == -1)
{
printf("Error Opening File\n");
exit(1);
}
if ((bytes = _rtl_write(handle, buf, 200)) == -1) {
printf("Write Failed.\n");
exit(1);
}
printf("_rtl_write: %d bytes written.\n",bytes);
return 0;
}
Portability
io.h
887
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Input/output Routines
Prototype
int access(const char *filename, int amode);
int _waccess(const wchar_t *filename, int amode);
Description
access checks the file named by filename to determine if it exists, and whether it can be read, written to, or executed.
All existing files have read access (amode equals 04), so 00 and 04 give the same result. Similarly, amode values of 06 and 02
are equivalent because under Win32 write access implies read access.
If filename refers to a directory, access simply determines whether the directory exists.
Return Value
If the requested access is allowed, access returns 0; otherwise, it returns a value of -1, and the global variable errno is set to one
of the following values:
Example
#include <stdio.h>
#include <io.h>
int file_exists(char *filename);
int main(void)
{
printf("Does NOTEXIST.FIL exist: %s\n",
file_exists("NOTEXISTS.FIL") ? "YES" : "NO");
return 0;
}
int file_exists(char *filename)
{
return (access(filename, 0) == 0);
3 }
Portability
888
3.1 C++ Reference RAD Studio C Runtime Library Reference
io.h
Category
Input/output Routines
Prototype
int chmod(const char *path, int amode);
int _wchmod(const wchar_t *path, int amode);
Description
chmod sets the file-access permissions of the file given by path according to the mask given by amode. path points to a string.
amode can contain one or both of the symbolic constants S_IWRITE and S_IREAD (defined in sys\stat.h).
Return Value
Upon successfully changing the file access mode, chmod returns 0. Otherwise, chmod returns a value of -1.
In the event of an error, the global variable errno is set to one of the following values:
Example
#include <errno.h>
#include <stdio.h>
#include <io.h>
#include <process.h>
#include <sys\stat.h>
void main(void)
{
char filename[64];
struct stat stbuf;
int amode;
printf("Enter name of file: ");
scanf("%s", filename);
if (stat(filename, &stbuf) != 0) 3
{
perror("Unable to get file information");
exit(1);
}
if (stbuf.st_mode & S_IWRITE)
{
printf("Changing to read-only\n");
amode = S_IREAD;
}
else
889
C Runtime Library Reference RAD Studio 3.1 C++ Reference
{
printf("Changing to read-write\n");
amode = S_IREAD|S_IWRITE;
}
if (chmod(filename, amode) != 0)
{
perror("Unable to change file mode");
exit(1);
}
exit(0);
}
Portability
3.1.4.15.16 chsize
Header File
io.h
Category
Input/output Routines
Prototype
int chsize(int handle, long size);
Description
chsize changes the size of the file associated with handle. It can truncate or extend the file, depending on the value of size
compared to the file's original size.
The mode in which you open the file must allow writing.
If chsize extends the file, it will append null characters (\0). If it truncates the file, all data beyond the new end-of-file indicator is
lost.
Return Value
On success, chsize returns 0. On failure, it returns -1 and the global variable errno is set to one of the following values:
890
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.15.17 close
Header File
io.h
Category
Input/output Routines
Prototype
int close(int handle);
Description
Closes a file.
The close function closes the file associated with handle, a file handle obtained from a call to creat, creatnew, creattemp, dup,
dup2, open, _rtl_creat, or _rtl_open.
It does not write a Ctrl-Z character at the end of the file. If you want to terminate the file with a Ctrl-Z, you must explicitly output
one.
Return Value
On error (if it fails because handle is not the handle of a valid, open file), close returns a value of -1 and the global variable errno
is set to
Example
#include <string.h>
#include <stdio.h>
#include <fcntl.h> 3
#include <io.h>
main()
{
int handle;
char buf[11] = "0123456789";
/* create a file containing 10 bytes */
handle = open("NEW.FIL", O_CREAT);
if (handle > -1)
{
write(handle, buf, strlen(buf));
891
C Runtime Library Reference RAD Studio 3.1 C++ Reference
io.h
Category
Input/output Routines
Prototype
int creat(const char *path, int amode);
int _wcreat(const wchar_t *path, int amode);
Description
creat creates a new file or prepares to rewrite an existing file given by path. amode applies only to newly created files.
A file created with creat is always created in the translation mode specified by the global variable _fmode (O_TEXT or
O_BINARY).
If the file exists and the write attribute is set, creat truncates the file to a length of 0 bytes, leaving the file attributes unchanged. If
the existing file has the read-only attribute set, the creat call fails and the file remains unchanged.
The creat call examines only the S_IWRITE bit of the access-mode word amode. If that bit is 1, the file can be written to. If the bit
is 0, the file is marked as read-only. All other operating system attributes are set to 0.
3 S_IREAD / S_IWRITE Permission to read and write (write permission implies read permission)
Return Value
Upon successful completion, _creat returns the new file handle, a nonnegative integer; otherwise, it returns -1.
In the event of error, the global variable errno is set to one of the following:
892
3.1 C++ Reference RAD Studio C Runtime Library Reference
Example
#include <sys\stat.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char buf[11] = "0123456789";
/* change the default file mode from text to binary */
_fmode = O_BINARY;
/* create a binary file for reading and writing */
handle = creat("DUMMY.FIL", S_IREAD |S_IWRITE);
/* write 10 bytes to the file */
write(handle, buf, strlen(buf));
/* close the file */
close(handle);
return 0;
}
Portability
3.1.4.15.19 creatnew
Header File
io.h
Category
Input/output Routines
Prototype
int creatnew(const char *path, int mode);
Description
creatnew is identical to _rtl_creat with one exception: If the file exists, creatnew returns an error and leaves the file untouched.
3
The mode argument to creatnew can be zero or an OR-combination of any one of the following constants (defined in dos.h):
Return Value
893
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Upon successful completion, creatnew returns the new file handle, a nonnegative integer; otherwise, it returns -1.
In the event of error, the global variable errno is set to one of the following values:
Example
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <io.h>
int main(void)
{
int handle;
char buf[11] = "0123456789";
/* attempt to create a file that doesn't already exist */
handle = creatnew("DUMMY.FIL", 0);
if (handle == -1)
printf("DUMMY.FIL already exists.\n");
else
{
printf("DUMMY.FIL successfully created.\n");
write(handle, buf, strlen(buf));
close(handle);
}
return 0;
}
Portability
3.1.4.15.20 creattemp
Header File
io.h
Category
Input/output Routines
Prototype
int creattemp(char *path, int attrib);
3
Description
Creates a unique file in the directory associated with the path name.
A file created with creattemp is always created in the translation mode specified by the global variable _fmode (O_TEXT or
O_BINARY).
path is a path name ending with a backslash (\). A unique file name is selected in the directory given by path. The newly created
file name is stored in the path string supplied. path should be long enough to hold the resulting file name. The file is not
894
3.1 C++ Reference RAD Studio C Runtime Library Reference
The attrib argument to creattemp can be zero or an OR-combination of any one of the following constants (defined in dos.h):
Upon successful file creation, the file pointer is set to the beginning of the file. The file is opened for both reading and writing.
Return Value
Upon successful completion, the new file handle, a nonnegative integer, is returned; otherwise, -1 is returned.
In the event of error, the global variable errno is set to one of the following values:
Example
#include <string.h>
#include <stdio.h>
#include <io.h>
int main(void)
{
int handle;
char pathname[128];
strcpy(pathname, "\\");
/* create a unique file in the root directory */
handle = creattemp(pathname, 0);
printf("%s was the unique file created.\n", pathname);
close(handle);
return 0;
}
Portability
3.1.4.15.21 dup
Header File
io.h
Category
3
Input/output Routines
Prototype
int dup(int handle);
Description
895
C Runtime Library Reference RAD Studio 3.1 C++ Reference
• dup creates a new file handle that has the following in common with the original file handle:
• Same open file or device
• Same file pointer (that is, changing the file pointer of one changes the other)
• Same access mode (read, write, read/write)
handle is a file handle obtained from a call to creat, open, dup, dup2, _rtl_creat, or _rtl_open.
Return Value
Upon successful completion, dup returns the new file handle, a nonnegative integer; otherwise, dup returns -1.
In the event of error, the global variable errno is set to one of the following values:
Example
#include <string.h>
#include <stdio.h>
#include <io.h>
void flush(FILE *stream);
int main(void)
{
FILE *fp;
char msg[] = "This is a test";
/* create a file */
fp = fopen("DUMMY.FIL", "w");
/* write some data to the file */
fwrite(msg, strlen(msg), 1, fp);
printf("Press ENTER to flush DUMMY.FIL:");
getchar();
/* flush the data to DUMMY.FIL without closing it */
flush(fp);
printf("\nFile was flushed, Press ENTER to quit:");
getchar();
return 0;
}
void flush(FILE *stream)
{
int duphandle;
/* flush TC's internal buffer */
fflush(stream);
/* make a duplicate file handle */
duphandle = dup(fileno(stream));
/* close the duplicate handle to flush the DOS buffer */
close(duphandle);
}
Portability
3.1.4.15.22 dup2
Header File
io.h
Category
896
3.1 C++ Reference RAD Studio C Runtime Library Reference
Input/output Routines
Prototype
int dup2(int oldhandle, int newhandle);
Description
• dup2 creates a new file handle that has the following in common with the original file handle:
• Same open file or device
• Same file pointer (that is, changing the file pointer of one changes the other)
• Same access mode (read, write, read/write)
dup2 creates a new handle with the value of newhandle. If the file associated with newhandle is open when dup2 is called, the
file is closed.
newhandle and oldhandle are file handles obtained from a creat, open, dup, or dup2 call.
Return Value
dup2 returns 0 on successful completion, -1 otherwise.
In the event of error, the global variable errno is set to one of the following values:
EBADF Bad file number
EMFILE Too many open files
Example
#include <sys\stat.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#define STDOUT 1
int main(void)
{
int nul, oldstdout;
char msg[] = "This is a test";
/* create a file */
nul = open("DUMMY.FIL", O_CREAT | O_RDWR,
S_IREAD | S_IWRITE);
/* create a duplicate handle for standard output */
oldstdout = dup(STDOUT);
/*
redirect standard output to DUMMY.FIL
by duplicating the file handle onto
the file handle for standard output.
*/
dup2(nul, STDOUT);
/* close the handle for DUMMY.FIL */
close(nul);
/* will be redirected into DUMMY.FIL */
write(STDOUT, msg, strlen(msg));
/* restore original standard output handle */
dup2(oldstdout, STDOUT); 3
/* close duplicate handle for STDOUT */
close(oldstdout);
return 0;
}
Portability
897
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.15.23 eof
Header File
io.h
Category
Input/output Routines
Prototype
int eof(int handle);
Description
eof determines whether the file associated with handle has reached end-of-file.
Return Value
If the current position is end-of-file, eof returns the value 1; otherwise, it returns 0. A return value of -1 indicates an error; the
global variable errno is set to
Example
#include <sys\stat.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char msg[] = "This is a test";
char ch;
/* create a file */
handle = open("DUMMY.FIL",
O_CREAT | O_RDWR,
S_IREAD | S_IWRITE);
/* write some data to the file */
write(handle, msg, strlen(msg));
/* seek to the beginning of the file */
lseek(handle, 0L, SEEK_SET);
/* reads chars from the file until it reaches EOF */
3 do
{
read(handle, &ch, 1);
printf("%c", ch);
} while (!eof(handle));
close(handle);
return 0;
}
Portability
898
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.15.24 filelength
Header File
io.h
Category
Input/output Routines
Prototype
long filelength(int handle);
Description
filelength returns the length (in bytes) of the file associated with handle.
Return Value
On success filelength returns a long value the file length in bytes. On error it returns -1 and the global variable errno is set to
Example
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char buf[11] = "0123456789";
/* create a file containing 10 bytes */
handle = open("DUMMY.FIL", O_CREAT);
write(handle, buf, strlen(buf));
/* display the size of the file */
printf("file length in bytes: %ld\n", filelength(handle));
/* close the file */
close(handle);
return 0;
}
Portability
io.h
899
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Input/output Routines
Prototype
int getftime(int handle, struct ftime *ftimep);
int setftime(int handle, struct ftime *ftimep);
Description
getftime retrieves the file time and date for the disk file associated with the open handle. The ftime structure pointed to by ftimep
is filled in with the file's time and date.
setftime sets the file date and time of the disk file associated with the open handle to the date and time in the ftime structure
pointed to by ftimep. The file must not be written to after the setftime call or the changed information will be lost. The file must be
open for writing; an EACCES error will occur if the file is open for read-only access.
setftime requires the file to be open for writing; an EACCES error will occur if the file is open for read-only access.
Return Value
In the event of an error return -1 is returned and the global variable errno is set to one of the following values:
Example
#include <stdio.h>
#include <io.h>
3 int main(void)
{
FILE *stream;
std::ftime ft;
if ((stream = fopen("TEST.$$$",
"wt")) == NULL)
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
getftime(fileno(stream), &ft);
900
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.15.26 isatty
Header File
io.h
Category
Input/output Routines
Prototype
int isatty(int handle);
Description
isatty determines whether handle is associated with any one of the following character devices:
• a terminal
• a console
• a printer
• a serial port
Return Value
If the device is one of the four character devices listed above, isatty returns a nonzero integer. If it is not such a device, isatty
returns 0.
Example
#include <stdio.h>
#include <io.h>
int main(void)
{
int handle;
handle = fileno(stdout);
if (isatty(handle))
printf("Handle %d is a device type\n", handle);
else
printf("Handle %d isn't a device type\n", handle);
return 0;
}
Portability 3
POSIX Win32 ANSI C ANSI C++
+ +
901
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.15.27 lock
Header File
io.h
Category
Input/output Routines
Prototype
int lock(int handle, long offset, long length);
Description
A lock can be placed on arbitrary, nonoverlapping regions of any file. A program attempting to read or write into a locked region
will retry the operation three times. If all three retries fail, the call fails with an error.
Return Value
lock returns 0 on success. On error, lock returns -1 and sets the global variable errno to
Example
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
int main(void)
{
int handle, status;
long length;
handle = _sopen("c:\\autoexec.bat",
O_RDONLY,SH_DENYNO,S_IREAD);
if (handle < 0)
{
printf("_sopen failed\n");
exit(1);
}
length = filelength(handle);
status = lock(handle,0L,length/2);
if (status == 0)
printf("lock succeeded\n");
else
printf("lock failed\n");
3 status = unlock(handle,0L,length/2);
if (status == 0)
printf("unlock succeeded\n");
else
printf("unlock failed\n");
close(handle);
return 0;
}
Portability
902
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.15.28 locking
Header File
io.h, sys\locking.h
Category
Input/output Routines
Prototype
int locking(int handle, int cmd, long length);
Description
locking provides an interface to the operating system file-sharing mechanism. The file to be locked or unlocked is the open file
specified by handle. The region to be locked or unlocked starts at the current file position, and is length bytes long.
Locks can be placed on arbitrary, nonoverlapping regions of any file. A program attempting to read or write into a locked region
will retry the operation three times. If all three retries fail, the call fails with an error.
The cmd specifies the action to be taken (the values are defined in sys\locking.h):
LK_LOCK Lock the region. If the lock is unsuccessful, try once a second for 10 seconds before giving up.
LK_RLCK Same as LK_LOCK.
LK_NBLCK Lock the region. If the lock if unsuccessful, give up immediately.
LK_NBRLCK Same as LK_NBLCK.
LK_UNLCK Unlock the region, which must have been previously locked.
Return Value
On successful operations, locking returns 0. Otherwise, it returns -1, and the global variable errno is set to one of the following
values:
Example 3
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
#include <sys\locking.h>
int main(void)
{
int handle, status;
903
C Runtime Library Reference RAD Studio 3.1 C++ Reference
long length;
handle = sopen("c:\\autoexec.bat", O_RDONLY,SH_DENYNO);
if (handle < 0) {
printf("sopen failed\n");
exit(1);
}
length = filelength(handle);
status = locking(handle,LK_LOCK,length/2);
if (status == 0)
printf("lock succeeded\n");
else
perror("lock failed");
status = locking(handle,LK_UNLCK,length/2);
if (status == 0)
printf("unlock succeeded\n");
else
perror("unlock failed");
close(handle);
return 0;
}
Portability
3.1.4.15.29 lseek
Header File
io.h
Category
Input/output Routines
Prototype
long lseek(int handle, long offset, int fromwhere);
Description
lseek sets the file pointer associated with handle to a new position offset bytes beyond the file location given by fromwhere.
fromwhere must be one of the following symbolic constants (defined in io.h):
3 Return Value
lseek returns the offset of the pointer’s new position measured in bytes from the file beginning. lseek returns -1L on error, and
the global variable errno is set to one of the following values:
904
3.1 C++ Reference RAD Studio C Runtime Library Reference
On devices incapable of seeking (such as terminals and printers), the return value is undefined.
Example
#include <sys\stat.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char msg[] = "This is a test";
char ch;
/* create a file */
handle = open("TEST.$$$", O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
/* write some data to the file */
write(handle, msg, strlen(msg));
/* seek to the beginning of the file */
lseek(handle, 0L, SEEK_SET);
/* reads chars from the file until we hit EOF */
do
{
read(handle, &ch, 1);
printf("%c", ch);
} while (!eof(handle));
close(handle);
return 0;
}
Portability
3.1.4.15.30 read
Header File
io.h
Category
Input/output Routines
Prototype
int read(int handle, void *buf, unsigned len);
Description
read attempts to read len bytes from the file associated with handle into the buffer pointed to by buf. 3
For a file opened in text mode, read removes carriage returns and reports end-of-file when it reaches a Ctrl-Z.
The file handle handle is obtained from a creat, open, dup, or dup2 call.
On disk files, read begins reading at the current file pointer. When the reading is complete, it increments the file pointer by the
number of bytes read. On devices, the bytes are read directly from the device.
The maximum number of bytes that read can read is UINT_MAX -1, because UINT_MAX is the same as -1, the error return
indicator. UINT_MAX is defined in limits.h.
905
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
On successful completion, read returns an integer indicating the number of bytes placed in the buffer. If the file was opened in
text mode, read does not count carriage returns or Ctrl-Z characters in the number of bytes read.
On end-of-file, read returns 0. On error, read returns -1 and sets the global variable errno to one of the following values:
Example
#include <stdio.h>
#include <io.h>
#include <alloc.h>
#include <fcntl.h>
#include <process.h>
#include <sys\stat.h>
int main(void)
{
void *buf;
int handle, bytes;
buf = malloc(10);
/*
Looks for a file in the current directory named TEST.$$$ and attempts to read 10 bytes from
it. To use this example you should create the file TEST.$$$.
*/
if ((handle =
open("TEST.$$$", O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1)
{
printf("Error Opening File\n");
exit(1);
}
if ((bytes = read(handle, buf, 10)) == -1) {
printf("Read Failed.\n");
exit(1);
}
else {
printf("Read: %d bytes read.\n", bytes);
}
return 0;
}
Portability
3.1.4.15.31 setmode
Header File
3
io.h
Category
Input/output Routines
Prototype
int setmode(int handle, int amode);
906
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
setmode sets the mode of the open file associated with handle to either binary or text. The argument amode must have a value
of either O_BINARY or O_TEXT, never both. (These symbolic constants are defined in fcntl.h.)
Return Value
setmode returns the previous translation mode if successful. On error it returns -1 and sets the global variable errno to
Example
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
int main (int argc, char ** argv )
(
FILE *fp;
int newmode;
long where;
char buf[256];
fp = fopen( argv[1], "r+" );
if ( !fp )
{
printf( "Couldn't open %s\n", argv[1] );
return -1;
}
newmode = setmode( fileno( fp ), O_BINARY );
if ( newmode == -1 )
{
printf( "Couldn't set mode of %s\n", argv[1] );
return -2
}
fp->flags |= _F_BIN;
where = ftell( fp );
printf ("file position: %d\n", where );
fread( buf, 1, 1, fp );
where = ftell ( fp );
printf( "read %c, file position: %ld\n", *buf, where );
fclose ( fp );
return 0;
}
Portability
3.1.4.15.32 tell
3
Header File
io.h
Category
Input/output Routines
Prototype
907
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
tell gets the current position of the file pointer associated with handle and expresses it as the number of bytes from the beginning
of the file.
Return Value
tell returns the current file pointer position. A return of -1 (long) indicates an error, and the global variable errno is set to
Example
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char msg[] = "Hello world";
if ((handle = open("TEST.$$$", O_CREAT | O_TEXT | O_APPEND)) == -1)
{
perror("Error:");
return 1;
}
write(handle, msg, strlen(msg));
printf("The file pointer is at byte %ld\n", tell(handle));
close(handle);
return 0;
}
Portability
3.1.4.15.33 umask
Header File
io.h, sys\stat.h
Category
Input/output Routines
Prototype
3
unsigned umask(unsigned mode);
Description
The umask function sets the access permission mask used by open and creat. Bits that are set in mode will be cleared in the
access permission of files subsequently created by open and creat.
The mode can have one of the following values, defined in sys\stat.h:
908
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
Example
#include <io.h>
#include <stdio.h>
#include <sys\stat.h>
#define FILENAME "TEST.$$$"
int main(void)
{
unsigned oldmask;
FILE *f;
struct stat statbuf;
/* Cause subsequent files to be created as read-only */
oldmask = umask(S_IWRITE);
printf("Old mask = 0x%x\n",oldmask);
/* Create a zero-length file */
if ((f = fopen(FILENAME,"w+")) == NULL)
{
perror("Unable to create output file");
return (1);
}
fclose(f);
/* Verify that the file is read-only */
if (stat(FILENAME,&statbuf) != 0)
{
perror("Unable to get information about output file");
return (1);
}
if (statbuf.st_mode & S_IWRITE)
printf("Error! %s is writable!\n",FILENAME);
else
printf("Success! %s is not writable.\n",FILENAME);
return (0);
}
Portability
3.1.4.15.34 unlock
Header File
3
io.h
Category
Input/output Routines
Prototype
int unlock(int handle, long offset, long length);
909
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
unlock provides an interface to the operating system file-sharing mechanism. unlock removes a lock previously placed with a call
to lock. To avoid error, all locks must be removed before a file is closed. A program must release all locks before completing.
Return Value
Example
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
int main(void)
{
int handle, status;
long length;
handle = _sopen("c:\\autoexec.bat",O_RDONLY,SH_DENYNO,S_IREAD);
if (handle < 0)
{
printf("_sopen failed\n");
exit(1);
}
length = filelength(handle);
status = lock(handle,0L,length/2);
if (status == 0)
printf("lock succeeded\n");
else
printf("lock failed\n");
status = unlock(handle,0L,length/2);
if (status == 0)
printf("unlock succeeded\n");
else
printf("unlock failed\n");
close(handle);
return 0;
}
Portability
3.1.4.15.35 vsscanf
3 Header File
io.h
Category
Prototype
int vsscanf(const char *buffer, const char *format, va_list arglist);
910
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
The v...scanf functions are known as alternate entry points for the ...scanf functions. They behave exactly like their ...scanf
counterparts, but they accept a pointer to a list of arguments instead of an argument list.
vsscanf scans a series of input fields, one character at a time, reading from a stream. Then each field is formatted according to a
format specifier passed to vsscanf in the format string pointed to by format. Finally, vsscanf stores the formatted input at an
address passed to it as an argument following format. There must be the same number of format specifiers and addresses as
there are input fields.
vsscanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace) character, or it might
terminate entirely, for a number of reasons. See scanf for a discussion of possible causes.
Return Value
vsscanf returns the number of input fields successfully scanned, converted, and stored; the return value does not include
scanned fields that were not stored. If no fields were stored, the return value is 0.
Example
#include <stdio.h>
#include <stdarg.h>
char buffer[80] = "30 90.0 abc";
int vssf(char *fmt, ...)
{
va_list argptr;
int cnt;
fflush(stdin);
va_start(argptr, fmt);
cnt = vsscanf(buffer, fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
int inumber;
float fnumber;
char string[80];
vssf("%d %f %s", &inumber, &fnumber, string);
printf("%d %f %s\n", inumber, fnumber, string);
return 0;
}
Portability
3.1.4.15.36 write
Header File
io.h
Category
911
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Input/output Routines
Prototype
int write(int handle, void *buf, unsigned len);
Description
Writes to a file.
write writes a buffer of data to the file or device named by the given handle. handle is a file handle obtained from a creat, open,
dup, or dup2 call.
This function attempts to write len bytes from the buffer pointed to by buf to the file associated with handle. Except when write is
used to write to a text file, the number of bytes written to the file will be no more than the number requested. The maximum
number of bytes that write can write is UINT_MAX -1, because UINT_MAX is the same as -1, which is the error return indicator
for write. On text files, when write sees a linefeed (LF) character, it outputs a CR/LF pair. UINT_MAX is defined in limits.h.
If the number of bytes actually written is less than that requested, the condition should be considered an error and probably
indicates a full disk. For disks or disk files, writing always proceeds from the current file pointer. For devices, bytes are sent
directly to the device. For files opened with the O_APPEND option, the file pointer is positioned to EOF by write before writing
the data.
Return Value
write returns the number of bytes written. A write to a text file does not count generated carriage returns. In case of error, write
returns -1 and sets the global variable errno to one of the following values:
Example
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#include <string.h>
int main(void)
{
int handle;
char string[40];
int length, res;
/*
Create a file named "TEST.$$$" in the current directory and write a string to it. If
"TEST.$$$" already exists, it will be overwritten.
*/
if ((handle = open("TEST.$$$", O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE)) == -1)
{
printf("Error opening file.\n");
exit(1);
3 }
strcpy(string, "Hello, world!\n");
length = strlen(string);
if ((res = write(handle, string, length)) != length)
{
printf("Error writing to the file.\n");
exit(1);
}
printf("Wrote %d bytes to the file.\n", res);
close(handle);
912
3.1 C++ Reference RAD Studio C Runtime Library Reference
return 0;
}
Portability
3.1.4.16 limits.h
The following functions, macros, and classes are provided in limits.h:
Topics
Name Description
CHAR_xxx #defines ( see page 913) Header File
limits.h
Description
INT_xxx #defines ( see page 913) Header File
limits.h
Description
Maximum and minimum value for type int.
LONG_xxx #defines ( see page 914) Header File
limits.h
Description
Maximum and minimum value for type long.
SCHAR_xxx #defines ( see page 914) Header File
limits.h
Description
SHRT_xxx #defines ( see page 914) Header File
limits.h
Description
Uxxxx_MAX #defines ( see page 915) Header File
limits.h
Description
limits.h
Description
Name Meaning
CHAR_BIT Type char, number of bits
CHAR_MAX Type char, minimum value
CHAR_MIN Type char, maximum value
3
These values are independent of whether type char is defined as signed or unsigned by default.
913
C Runtime Library Reference RAD Studio 3.1 C++ Reference
limits.h
Description
Name Meaning
INT_MAX Type int, maximum value
INT_MIN Type int, minimum value
limits.h
Description
Name Meaning
LONG_MAX Type long, maximum value
LONG_MIN Type long, minimum value
limits.h
Description
Name Meaning
SCHAR_MAX Type char, maximum value
SCHAR_MIN Type char, minimum value
limits.h
Description
3 Name Meaning
SHRT_MAX Type short, maximum value
SHRT_MIN Type short, minimum value
914
3.1 C++ Reference RAD Studio C Runtime Library Reference
limits.h
Description
3.1.4.17 locale.h
The following functions, macros, and classes are provided in locale.h:
Topics
Name Description
localeconv ( see page 915) Header File
locale.h
Category
Miscellaneous Routines
Prototype
struct lconv *localeconv(void);
Description
Queries the locale for numeric format.
This function provides information about the monetary and other numeric formats
for the current locale. The information is stored in a struct lconv type. The
structure can only be modified by the setlocale. Subsequent calls to localeconv
will update the lconv structure.
The lconv structure is defined in locale.h. It contains the following fields:
setlocale, _wsetlocale ( see page 917) Header File
locale.h
Category
Miscellaneous Routines
Prototype
char *setlocale(int category, const char *locale);
wchar_t * _wsetlocale( int category, const wchar_t *locale);
Description
Use the setlocale to select or query a locale.
C++ Builder supports all locales supported in Win95/98/2000 operating systems.
See your system documentation for details.
The possible values for the category argument are as follows:
3
3.1.4.17.1 localeconv
Header File
locale.h
Category
Miscellaneous Routines
915
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
struct lconv *localeconv(void);
Description
This function provides information about the monetary and other numeric formats for the current locale. The information is stored
in a struct lconv type. The structure can only be modified by the setlocale. Subsequent calls to localeconv will update the lconv
structure.
char Decimal point used in nonmonetary formats. This can never be an empty string.
char Separator used to group digits to the left of the decimal point. Not used with monetary quantities.
char Size of each group of digits. Not used with monetary quantities. See the value listing table below.
char International monetary symbol in the current locale. The symbol format is specified in the ISO 4217
Codes for the Representation of Currency and Funds.
char Local monetary symbol for the current locale.
char Decimal point used to format monetary quantities.
char Separator used to group digits to the left of the decimal point for monetary quantities.
char Size of each group of digits used in monetary quantities. See the value listing table below.
char String indicating nonnegative monetary quantities.
char String indicating negative monetary quantities.
char Number of digits after the decimal point that are to be displayed in an internationally formatted
monetary quantity.
char Number of digits after the decimal point that are to be displayed in a formatted monetary quantity.
char Set to 1 if currency_symbol precedes a nonnegative formatted monetary quantity. If currency_symbol
is after the quantity, it is set to 0.
char Set to 1 if currency_symbol is to be separated from the nonnegative formatted monetary quantity by a
space. Set to 0 if there is no space separation.
char Set to 1 if currency_symbol precedes a negative formatted monetary quantity. If currency_symbol is
after the quantity, set to 0.
char Set to 1 if currency_symbol is to be separated from the negative formatted monetary quantity by a
space. Set to 0 if there is no space separation.
char Indicate where to position the positive sign in a nonnegative formatted monetary quantity.
char Indicate where to position the positive sign in a negative formatted monetary quantity.
Any of the above strings (except decimal_point) that is empty “ “ is not supported in the current locale. The nonstring char
elements are nonnegative numbers. Any nonstring char element that is set to CHAR_MAX indicates that the element is not
3 supported in the current locale.
The grouping and mon_grouping elements are set and interpreted as follows:
916
3.1 C++ Reference RAD Studio C Runtime Library Reference
The p_sign_posn and n_sign_posn elements are set and interpreted as follows:
Return Value
Returns a pointer to the the filled-in structure of type struct lconv. The values in the structure will change whenever setlocale
modifies the LC_MONETARY or LC_NUMERIC categories.
Example
#include <locale.h>
#include <stdio.h>
int main(void)
{
struct lconv ll;
struct lconv *conv = ≪
/* read the locality conversion structure */
conv = localeconv();
/* display the structure */
printf("Decimal Point : %s\n", conv-> decimal_point);
printf("Thousands Separator : %s\n", conv-> thousands_sep);
printf("Grouping : %s\n", conv-> grouping);
printf("International Currency symbol : %s\n", conv-> int_curr_symbol);
printf("$ thousands separator : %s\n", conv-> mon_thousands_sep);
printf("$ grouping : %s\n", conv-> mon_grouping);
printf("Positive sign : %s\n", conv-> positive_sign);
printf("Negative sign : %s\n", conv-> negative_sign);
printf("International fraction digits : %d\n", conv-> int_frac_digits);
printf("Fraction digits : %d\n", conv-> frac_digits);
printf("Positive $ symbol precedes : %d\n", conv-> p_cs_precedes);
printf("Positive sign space separation: %d\n", conv-> p_sep_by_space);
printf("Negative $ symbol precedes : %d\n", conv-> n_cs_precedes);
printf("Negative sign space separation: %d\n", conv-> n_sep_by_space);
printf("Positive sign position : %d\n", conv-> p_sign_posn);
printf("Negative sign position : %d\n", conv-> n_sign_posn);
return 0;
}
Portability
locale.h
Category
Miscellaneous Routines
Prototype
917
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
C++ Builder supports all locales supported in Win95/98/2000 operating systems. See your system documentation for details.
The locale argument is a pointer to the name of the locale or named locale category. Passing a NULL pointer returns the current
locale in effect. Passing a pointer that points to a null string requests setlocale to look for environment variables to determine
which locale to set. The locale names are not case sensitive.
When setlocale is unable to honor a locale request, the preexisting locale in effect is unchanged and a null pointer is returned.
If the locale argument is a NULL pointer, the locale string for the category is returned. If category is LC_ALL, a complete locale
string is returned. The structure of the complete locale string consists of the names of all the categories in the current locale
concatenated and separated by semicolons. This string can be used as the locale parameter when calling setlocale with any of
the LC_xxx values. This will reinstate all the locale categories that are named in the complete locale string, and allows saving
and restoring of locale states. If the complete locale string is used with a single category, for example, LC_TIME, only that
category will be restored from the locale string.
If an empty string "" is used as the locale parameter an implementation-defined locale is used. This is the ANSI C specified
behavior.
To take advantage of dynamically loadable locales in your application, define _ _USELOCALES_ _ for each module. If _
_USELOCALES_ _ is not defined, all locale-sensitive functions and macros will work only with the default C locale.
If a NULL pointer is used as the argument for the locale parameter, setlocale returns a string that specifies the current locale in
effect. If the category parameter specifies a single category, such as LC_COLLATE, the string pointed to will be the name of that
category. If LC_ALL is used as the category parameter then the string pointed to will be a full locale string that will indicate the
name of each category in effect.
.
.
3 .
localenameptr = setlocale( LC_COLLATE, NULL );
if (localenameptr)
printf( "%s\n", localenameptr );
.
.
918
3.1 C++ Reference RAD Studio C Runtime Library Reference
The output here will be one of the module names together with the specified code page. For example, the output could be
LC_COLLATE = English_United States.437.
.
.
.
localenameptr = setlocale( LC_ALL, NULL );
if (localenameptr)
printf( "%s\n", localenameptr );
.
.
.
Each category in this full string is delimited by a semicolon. This string can be copied and saved by an application and then used
again to restore the same locale categories at another time. Each delimited name corresponds to the locale category constants
defined in locale.h. Therefore, the first name is the name of the LC_COLLATE category, the second is the LC_CTYPE category,
and so on. Any other categories named in the locale.h header file are reserved for future implementation.
Return value
If selection is successful, setlocale returns a pointer to a string that is associated with the selected category (or possibly all
categories) for the new locale.
On failure, a NULL pointer is returned and the locale is unchanged. All other possible returns are discussed in the Remarks
section above.
Example
#include <locale.h>
#include <stdio.h>
int main(void) 3
{
char *old_locale;
/* The only locale supported in CodeGear C++ is "C" */
old_locale = setlocale(LC_ALL,"C");
printf("Old locale was %s\n",old_locale);
return 0;
}
Portability
919
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.18 malloc.h
The following functions, macros, and classes are provided in malloc.h:
Topics
Name Description
alloca ( see page 920) Header File
malloc.h
Category
Memory Routines
Prototype
void *alloca(size_t size);
Description
Allocates temporary stack space.
alloca allocates size bytes on the stack; the allocated space is automatically
freed up when the calling function exits.
The use of alloca is not encouraged. In the try-block of a C++ program the alloca
function should never be used. If an exception is thrown, any values placed on
the stack by alloca will be corrupted.
Return Value
If enough stack space is available, alloca returns a pointer to the allocated stack
area. Otherwise, it returns NULL.
Example
3.1.4.18.1 alloca
Header File
malloc.h
Category
Memory Routines
Prototype
void *alloca(size_t size);
Description
alloca allocates size bytes on the stack; the allocated space is automatically freed up when the calling function exits.
The use of alloca is not encouraged. In the try-block of a C++ program the alloca function should never be used. If an exception
3
is thrown, any values placed on the stack by alloca will be corrupted.
Return Value
If enough stack space is available, alloca returns a pointer to the allocated stack area. Otherwise, it returns NULL.
Example
#include <malloc.h>
#include <stdio.h>
920
3.1 C++ Reference RAD Studio C Runtime Library Reference
#include <stdlib.h>
void test(int a)
{
char *newstack;
int len = a;
char dummy[1];
dummy[0] = 0; /* force good stack frame */
printf("SP before calling alloca(0x%X) = 0x%X\n",len,_SP);
newstack = (char *) alloca(len);
printf("SP after calling alloca = 0x%X\n",_SP);
if (newstack)
printf("Alloca(0x%X) returned %p\n",len,newstack);
else
printf("Alloca(0x%X) failed\n",len);
}
void main()
{
test(256);
test(16384);
}
Portability
3.1.4.19 math.h
The following functions, macros, and classes are provided in math.h:
Topics
Name Description
HUGE_VAL #defines ( see page 931) Header File
math.h
Description
Overflow value for math functions.
M_E, M_LOGxxx, M_LNxx #defines ( see page 932) Header File
math.h
Description
The constant values for logarithm functions.
M_SQRTxx #defines ( see page 932) Header File
math.h
Description
Constant values for square roots of 2.
PI constants ( see page 932) Header File
math.h
Description
Common constants of pi
921
C Runtime Library Reference RAD Studio 3.1 C++ Reference
922
3.1 C++ Reference RAD Studio C Runtime Library Reference
923
C Runtime Library Reference RAD Studio 3.1 C++ Reference
924
3.1 C++ Reference RAD Studio C Runtime Library Reference
925
C Runtime Library Reference RAD Studio 3.1 C++ Reference
926
3.1 C++ Reference RAD Studio C Runtime Library Reference
927
C Runtime Library Reference RAD Studio 3.1 C++ Reference
928
3.1 C++ Reference RAD Studio C Runtime Library Reference
929
C Runtime Library Reference RAD Studio 3.1 C++ Reference
930
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
931
C Runtime Library Reference RAD Studio 3.1 C++ Reference
math.h
Description
Name Meaning
M_E The value of e
M_LOG2E The value of log(e)
M_LOG10E The value of log10(e)
M_LN2 The value of ln(2)
M_LN10 The value of ln(10)
math.h
Description
Name Meaning
M_SQRT2 Square root of 2
M_SQRT_2 1/2 the square root of 2
3.1.4.19.4 PI constants
Header File
math.h
Description
Common constants of pi
Name Meaning
M_PI pi
3 M_PI_2 One-half pi
M_PI_4 One-fourth pi
M_1_PI One divided by pi
M_2_PI Two divided by pi
M_1_SQRTPI One divided by the square root of pi
M_2_SQRTPI Two divided by the square root of pi
932
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdlib.h, math.h
Category
Prototype
double atof(const char *s);
double _wtof(const wchar_t *s);
Description
• atof converts a string pointed to by s to double; this function recognizes the character representation of a floating-point
number, made up of the following:
• An optional string of tabs and spaces
• An optional sign
• A string of digits and an optional decimal point (the digits can be on both sides of the decimal point)
• An optional e or E followed by an optional signed integer
The characters must match this generic format:
[whitespace] [sign] [ddd] [.] [ddd] [e|E[sign]ddd]
atof also recognizes +INF and -INF for plus and minus infinity, and +NAN and -NAN for not-a-number.
In this function, the first unrecognized character ends the conversion.
The functions strtod and _strtold are similar to atof and provide better error detection, and hence are preferred in some
applications.
Return Value
Returns the converted value of the input string.
If there is an overflow, atof returns plus or minus HUGE_VAL (or _LHUGE_VAL), errno is set to ERANGE (Result out of range),
and _matherr (or _matherrl) is not called.
math.h
Category
Description
933
C Runtime Library Reference RAD Studio 3.1 C++ Reference
An optional sign
The first unrecognized character ends the conversion. There are no provisions for overflow.
The functions strtod and _strtold are similar to atof and _atold; they provide better error detection, and hence are preferred in
some applications.
Return Value
If there is an overflow, _atold returns plus or minus HUGE_VAL (or _LHUGE_VAL), errno is set to ERANGE (Result out of
range), and _matherr (or _matherrl) is not called.
Portability
math.h, stdlib.h
Category
Prototype
char *_i64toa(__int64 value, char *string, int radix);
wchar_t *_i64tow(__int64 value, wchar_t *string, int radix);
Description
_i64toa converts an __int64 to a string. _i64tow is the unicode version. It converts a __int64 to a wide-character string.
These functions convert value to a null-terminated string and store the result in string. value is an __int64.
3
radix specifies the base to be used in converting value; it must be between 2 and 36, inclusive. If value is negative and radix is
10, the first character of string is the minus sign (-).
Note: The space allocated for string must be large enough to hold the returned string, including the terminating null character
(\0). These functions can return up to 33 bytes.
Return Value
934
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
math.h
Category
Prototype
int _matherr(struct _exception *e);
int _matherrl(struct _exceptionl *e);
Description
_matherrl is the long double version; it is called when an error is generated by the long double math functions.
_matherr and _matherrl each serve as a user hook (a function that can be customized by the user) that you can replace by
writing your own math error-handling routine.
_matherr and _matherrl are useful for information on trapping domain and range errors caused by the math functions. They do
not trap floating-point exceptions, such as division by zero. See signal for information on trapping such errors.
You can define your own _matherr or _matherrl routine to be a custom error handler (such as one that catches and resolves
certain types of errors); this customized function overrides the default version in the C library. The customized _matherr or
_matherrl should return 0 if it fails to resolve the error, or nonzero if the error is resolved. When _matherr or _matherrl return
nonzero, no error message is printed and the global variable errno is not changed.
The members of the _exception and _exceptionl structures are shown in the following table:
935
C Runtime Library Reference RAD Studio 3.1 C++ Reference
type The type of mathematical error that occurred; an enum type defined in the typedef _mexcep (see
definition after this list).
name A pointer to a null-terminated string holding the name of the math library function that resulted in an
error.
arg1, arg2 The arguments (passed to the function that name points to) caused the error; if only one argument
was passed to the function, it is stored in arg1.
retval The default return value for _matherr (or _matherrl); you can modify this value.
The typedef _mexcep, also defined in math.h, enumerates the following symbolic constants representing possible mathematical
errors:
The macros DBL_MAX, DBL_MIN, LDBL_MAX, and LDBL_MIN are defined in float.h
The source code to the default _matherr and _matherrl is on the C++Builder distribution disks.
The UNIX-style _matherr and _matherrl default behavior (printing a message and terminating) is not ANSI compatible. If you
want a UNIX-style version of these routines, use MATHERR.C and MATHERRL.C provided on the C++Builder distribution disks.
Example
#include <math.h>
#include <string.h>
#include <stdio.h>
int _matherr (struct _exception *a)
{
if (a->type == DOMAIN)
if (!strcmp(a->name,"sqrt")) {
a->retval = sqrt (-(a->arg1));
return 1;
}
return 0;
}
int main(void)
{
double x = -2.0, y;
y = sqrt(x);
printf("_Matherr corrected value: %lf\n",y);
return 0;
}
3 3.1.4.19.9 abs
Header File
stdlib.h, math.h
Category
Prototype
936
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
abs returns the absolute value of the integer argument x. If abs is called when stdlib.h has been included, it's treated as a macro
that expands to inline code.
If you want to use the abs function instead of the macro, include
#undef abs
Return Value
The abs function returns an integer in the range of 0 to INT_MAX, with the exception that an argument with the value INT_MIN is
returned as INT_MIN. The values for INT_MAX and INT_MIN are defined in header file limit.h.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
int number = -1234;
printf("number: %d absolute value: %d\n", number, abs(number));
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double acos(double x);
long double acosl(long double x);
Description
acosl is the long double version; it takes a long double argument and returns a long double result.
Arguments to acos and acosl must be in the range -1 to 1, or else acos and acosl return NAN and set the global variable errno to:
Return Value
937
C Runtime Library Reference RAD Studio 3.1 C++ Reference
acos and acosl of an argument between -1 and +1 return a value in the range 0 to pi. Error handling for these routines can be
modified through the functions _matherr_matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 0.5;
result = acos(x);
printf("The arc cosine of %lf is %lf\n", x, result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double asin(double x);
long double asinl(long double x);
Description
asin of a real argument returns the arc sine of the input value.
asinl is the long double version; it takes a long double argument and returns a long double result.
Real arguments to asin and asinl must be in the range -1 to 1, or else asin and asinl return NAN and set the global variable errno
to
Return Value
3 asin and asinl of a real argument return a value in the range -pi/2 to pi/2. Error handling for these functions may be modified
through the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
938
3.1 C++ Reference RAD Studio C Runtime Library Reference
double x = 0.5;
result = asin(x);
printf("The arc sin of %lf is %lf\n", x, result);
return(0);
}
Portability
math.h
Category
Math Routines
Prototype
double atan(double x);
long double atanl(long double x);
Description
atanl is the long double version; it takes a long double argument and returns a long double result.
Return Value
atan and atanl of a real argument return a value in the range -pi/2 to pi/2. Error handling for these functions can be modified
through the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 0.5;
result = atan(x);
printf("The arc tangent of %lf is %lf\n", x, result);
return(0);
}
3
Portability
939
C Runtime Library Reference RAD Studio 3.1 C++ Reference
math.h
Category
Math Routines
Prototype
double atan2(double y, double x);
long double atan2l(long double y, long double x);
Description
atan2 returns the arc tangent of y/x; it produces correct results even when the resulting angle is near pi/2 or -pi/2 (x near 0). If
both x and y are set to 0, the function sets the global variable errno to EDOM, indicating a domain error.
atan2l is the long double version; it takes long double arguments and returns a long double result.
Return Value
atan2 and atan2l return a value in the range -pi to pi. Error handling for these functions can be modified through the functions
_matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 90.0, y = 45.0;
result = atan2(y, x);
printf("The arc tangent ratio of %lf is %lf\n", (y / x), result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double cabs(struct complex z);
940
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
cabs calculates the absolute value of a complex number. cabs is a macro that calculates the absolute value of z, a complex
number. z is a structure with type complex; the structure is defined in math.h as
struct complex {
double x, y;
};
Calling cabs is equivalent to calling sqrt with the real and imaginary components of z, as shown here:
sqrt(z.x * z.x + z.y * z.y)
cabsl is the long double version; it takes a structure with type _complexl as an argument, and returns a long double result. The
structure is defined in math.h as
struct _complexl {
long double x, y;
};
Return Value
cabs (or cabsl) returns the absolute value of z, a double. On overflow, cabs (or cabsl) returns HUGE_VAL (or _LHUGE_VAL)
and sets the global variable errno to
Error handling for these functions can be modified through the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
#ifdef __cplusplus
#include <complex.h>
#endif
#ifdef __cplusplus /* if C++, use class complex */
void print_abs(void)
{
complex<float> z(1.0, 2.0);
double absval;
absval = abs(z);
printf("The absolute value of %.2lfi %.2lfj is %.2lf",
real(z), imag(z), absval);
}
#else /* below function is for C (and not C++) */
void print_abs(void)
{
struct complex z; 3
double absval;
z.x = 2.0;
z.y = 1.0;
absval = cabs(z);
printf("The absolute value of %.2lfi %.2lfj is %.2lf",
z.x, z.y, absval);
}
#endif
int main(void)
{
941
C Runtime Library Reference RAD Studio 3.1 C++ Reference
print_abs();
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double ceil(double x);
long double ceill(long double x);
Description
Rounds up.
ceill is the long double version; it takes a long double argument and returns a long double result.
Return Value
These functions return the integer found as a double (ceil) or a long double (ceill).
Example
#include <math.h>
#include <stdio.h>
int main(void)
{
double number = 123.54;
double down, up;
down = floor(number);
up = ceil(number);
printf("original number %5.2lf\n", number);
printf("number rounded down %5.2lf\n", down);
printf("number rounded up %5.2lf\n", up);
return 0;
}
3
Portability
942
3.1 C++ Reference RAD Studio C Runtime Library Reference
math.h
Category
Prototype
double cos(double x);
long double cosl(long double x);
Description
cos computes the cosine of the input value. The angle is specified in radians.
cosl is the long double version; it takes a long double argument and returns a long double result.
Return Value
cos of a real argument returns a value in the range -1 to 1. Error handling for these functions can be modified through _matherr
(or _matherrl).
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 0.5;
result = cos(x);
printf("The cosine of %lf is %lf\n", x, result);
return 0;
}
Portability
Category
Math Routines
Prototype
double cosh(double x);
943
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
coshl is the long double version; it takes a long double argument and returns a long double result.
Return Value
When the correct value would create an overflow, these functions return the value HUGE_VAL (cosh) or _LHUGE_VAL (coshl)
with the appropriate sign, and the global variable errno is set to ERANGE. Error handling for these functions can be modified
through the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 0.5;
result = cosh(x);
printf("The hyperbolic cosine of %lf is %lf\n", x, result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double exp(double x);
long double expl(long double x);
3 Description
expl is the long double version; it takes a long double argument and returns a long double result.
Return Value
Sometimes the arguments passed to these functions produce results that overflow or are incalculable. When the correct value
944
3.1 C++ Reference RAD Studio C Runtime Library Reference
overflows, exp returns the value HUGE_VAL and expl returns _LHUGE_VAL. Results of excessively large magnitude cause the
global variable errno to be set to
On underflow, these functions return 0.0, and the global variable errno is not changed. Error handling for these functions can be
modified through the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 4.0;
result = exp(x);
printf("'e' raised to the power \
of %lf (e ^ %lf) = %lf\n",
x, x, result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double fabs(double x);
long double fabsl(long double x);
Description
fabs calculates the absolute value of x, a double. fabsl is the long double version; it takes a long double argument and returns
a long double result.
3
Return Value
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
945
C Runtime Library Reference RAD Studio 3.1 C++ Reference
math.h
Category
Math Routines
Prototype
double floor(double x);
long double floorl(long double x);
Description
Rounds down.
floorl is the long double version; it takes a long double argument and returns a long double result.
Return Value
floor returns the integer found as a double. floorl returns the integer found as a long double.
Portability
Category
Math Routines
Prototype
double fmod(double x, double y);
946
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
fmod calculates x modulo y (the remainder f, where x = ay + f for some integer a, and 0 < f < y).
fmodl is the long double version; it takes long double arguments and returns a long double result.
Return Value
fmod and fmodl return the remainder f where x = ay + f (as described above). When y = 0, fmod and fmodl return 0.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double x = 5.0, y = 2.0;
double result;
result = fmod(x,y);
printf("The remainder of (%lf / %lf) is %lf\n", x, y, result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double frexp(double x, int *exponent);
long double frexpl(long double x, int *exponent);
Description
frexp calculates the mantissa m (a double greater than or equal to 0.5 and less than 1) and the integer value n such that x (the 3
original double value) equals m * 2n. frexp stores n in the integer that exponent points to.
frexpl is the long double version; it takes a long double argument for x and returns a long double result.
Return Value
frexp and frexpl return the mantissa m. Error handling for these routines can be modified through the functions _matherr and
_matherrl.
Example
947
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <math.h>
#include <stdio.h>
int main(void)
{
double mantissa, number;
int exponent;
number = 8.0;
mantissa = frexp(number, &exponent);
printf("The number %lf is ", number);
printf("%lf times two to the ", mantissa);
printf("power of %d\n", exponent);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double hypot(double x, double y);
long double hypotl(long double x, long double y);
Description
z2 = x2 + y2 and z >= 0
This is equivalent to the length of the hypotenuse of a right triangle, if the lengths of the two sides are x and y.
hypotl is the long double version; it takes long double arguments and returns a long double result.
Return Value
On success, these functions return z, a double (hypot) or a long double) (hypotl). On error (such as an overflow), they set the
global variable errno to
3 ERANGE Result out of range
and return the value HUGE_VAL (hypot) or _LHUGE_VAL) (hypotl). Error handling for these routines can be modified through
the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
948
3.1 C++ Reference RAD Studio C Runtime Library Reference
int main(void)
{
double result;
double x = 3.0;
double y = 4.0;
result = hypot(x, y);
printf("The hypotenuse is: %lf\n", result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double ldexp(double x, int exp);
long double ldexpl(long double x, int exp);
Description
Calculates x * 2^exp.
lexpl is the long double version; it takes a long double argument for x and returns a long double result.
Return Value
On success, ldexp (or ldexpl) returns the value it calculated, x * 2^exp. Error handling for these routines can be modified through
the functions _matherr and _matherrl.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double value;
double x = 2;
/* ldexp raises 2 by a power of 3
then multiplies the result by 2 */
value = ldexp(x,3); 3
printf("The ldexp value is: %lf\n", value);
return 0;
}
Portability
949
C Runtime Library Reference RAD Studio 3.1 C++ Reference
ldexpl + + +
3.1.4.19.25 ldiv
Header File
math.h
Category
Math Routines
Prototype
ldiv_t ldiv(long int numer, long int denom);
Description
ldiv divides two longs and returns both the quotient and the remainder as an ldiv_t type. numer and denom are the numerator
and denominator, respectively.
Return Value
ldiv returns a structure whose elements are quot (the quotient) and rem (the remainder).
Example
/* ldiv example */
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
ldiv_t lx;
lx = ldiv(100000L, 30000L);
printf("100000 div 30000 = %ld remainder %ld\n", lx.quot, lx.rem);
return 0;
}
Portability
math.h
950
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Math Routines
Prototype
double log(double x);
long double logl(long double x);
Description
logl is the long double version; it takes a long double argument and returns a long double result.
Return Value
errno
If x is 0, the functions return the value negative HUGE_VAL (log) or negative _LHUGE_VAL (logl), and set errno to ERANGE.
Error handling for these routines can be modified through the functions _matherr and _matherrl.
Example
#include <math.h>
#include <stdio.h>
int main(void)
{
double result;
double x = 8.6872;
result = log(x);
printf("The natural log of %lf is %lf\n", x, result);
return 0;
}
Portability
math.h 3
Category
Math Routines
Prototype
double log10(double x);
long double log10l(long double x);
951
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
log10l is the long double version; it takes a long double argument and returns a long double result.
Return Value
On success, log10 (or log10l) returns the calculated value log base ten of x.
If the argument x passed to these functions is real and less than 0, the global variable errno is set to
If x is 0, these functions return the value negative HUGE_VAL (log10) or _LHUGE_VAL (log10l). Error handling for these
routines can be modified through the functions _matherr and _matherrl.
Example
#include <math.h>
#include <stdio.h>
int main(void)
{
double result;
double x = 800.6872;
result = log10(x);
printf("The common log of %lf is %lf\n", x, result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double modf(double x, double *ipart);
long double modfl(long double x, long double *ipart);
3 Description
modf breaks the double x into two parts: the integer and the fraction. modf stores the integer in ipart and returns the fraction.
modfl is the long double version; it takes long double arguments and returns a long double result.
Return Value
952
3.1 C++ Reference RAD Studio C Runtime Library Reference
Example
#include <math.h>
#include <stdio.h>
int main(void)
{
double fraction, integer;
double number = 100000.567;
fraction = modf(number, &integer);
printf("The whole and fractional parts of %lf are %lf and %lf\n",
number, integer, fraction);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double poly(double x, int degree, double coeffs[]);
long double polyl(long double x, int degree, long double coeffs[]);
Description
poly generates a polynomial in x, of degree degree, with coefficients coeffs[0], coeffs[1], ..., coeffs[degree]. For example, if n = 4,
the generated polynomial is:
polyl is the long double version; it takes long double arguments and returns a long double result.
Return Value
poly and polyl return the value of the polynomial as evaluated for the given x.
Example
#include <stdio.h>
#include <math.h>
/* polynomial: x**3 - 2x**2 + 5x - 1 */ 3
int main(void)
{
double array[] = { -1.0, 5.0, -2.0, 1.0
};
double result;
result = poly(2.0, 3, array);
printf("The polynomial: x**3 - 2.0x**2 + 5x - 1 at 2.0 is %lf\n", result);
return 0;
}
953
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Portability
math.h
Category
Math Routines
Prototype
double pow(double x, double y);
long double powl(long double x, long double y);
Description
powl is the long double version; it takes long double arguments and returns a long double result.
Return Value
On success, pow and powl return the value calculated of x to the power of y.
Sometimes the arguments passed to these functions produce results that overflow or are incalculable. When the correct value
would overflow, the functions return the value HUGE_VAL (pow) or _LHUGE_VAL (powl). Results of excessively large
magnitude can cause the global variable errno to be set to
If the argument x passed to pow or powl is real and less than 0, and y is not a whole number, or if x is 0 and y is less than 0, or
you call pow(0,0), the global variable errno is set to
Error handling for these functions can be modified through the functions _matherr and _matherrl.
Example
#include <math.h>
#include <stdio.h>
int main(void)
3 {
double x = 2.0, y = 3.0;
printf("%lf raised to %lf is %lf\n", x, y, pow(x, y));
return 0;
}
Portability
954
3.1 C++ Reference RAD Studio C Runtime Library Reference
powl + + +
math.h
Category
Math Routines
Prototype
double pow10(int p);
long double pow10l(int p);
Description
pow10l is the long double version; it takes long double arguments and returns a long double result.
Return Value
On success, pow10 returns the value calculated, 10 to the power of p and pow10l returns a long double result.
The result is actually calculated to long double accuracy. All arguments are valid, although some can cause an underflow or
overflow.
Example
#include <math.h>
#include <stdio.h>
int main(void)
{
double p = 3.0;
printf("Ten raised to %lf is %lf\n", p, pow10(p));
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
955
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
Calculates sine.
sin computes the sine of the input value. Angles are specified in radians.
sinl is the long double version; it takes a long double argument and returns a long double result. Error handling for these
functions can be modified through the functions _matherr and _matherrl.
Return Value
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result, x = 0.5;
result = sin(x);
printf("The sin of %lf is %lf\n", x, result);
return 0;
}
Portability
math.h
Category
Prototype
double sinh(double x);
long double sinhl(long double x);
Description
sinl is the long double version; it takes a long double argument and returns a long double result. Error handling for sinh and
sinhl can be modified through the functions _matherr and _matherrl.
Return Value
956
3.1 C++ Reference RAD Studio C Runtime Library Reference
When the correct value overflows, these functions return the value HUGE_VAL (sinh) or _LHUGE_VAL (sinhl) of appropriate
sign. Also, the global variable errno is set to ERANGE.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result, x = 0.5;
result = sinh(x);
printf("The hyperbolic sin of %lf is %lf\n", x, result);
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double sqrt(double x);
long double sqrtl(long double x);
Description
sqrtl is the long double version; it takes a long double argument and returns a long double result. Error handling for these
functions can be modified through the functions _matherr and _matherrl.
Return Value
On success, sqrt and sqrtl return the value calculated, the square root of x. If x is real and positive, the result is positive. If x is
real and negative, the global variable errno is set to
957
C Runtime Library Reference RAD Studio 3.1 C++ Reference
return 0;
}
Portability
math.h
Category
Math Routines
Prototype
double tan(double x);
long double tanl(long double x);
Description
tanl is the long double version; it takes a long double argument and returns a long double result. Error handling for these
routines can be modified through the functions _matherr and _matherrl..
Return Value
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result, x;
x = 0.5;
result = tan(x);
printf("The tan of %lf is %lf\n", x, result);
return 0;
}
Portability
958
3.1 C++ Reference RAD Studio C Runtime Library Reference
math.h
Category
Math Routines
Prototype
double tanh(double x);
long double tanhl(long double x);
Description
tanhl is the long double version; it takes a long double argument and returns a long double result. Error handling for these
functions can be modified through the functions _matherr and _matherrl.
Return Value
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
double result, x;
x = 0.5;
result = tanh(x);
printf("The hyperbolic tangent of %lf is %lf\n", x, result);
return 0;
}
Portability
3.1.4.20 mem.h
The following functions, macros, and classes are provided in mem.h:
959
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Topics
Name Description
memccpy ( see page 962) Header File
mem.h, string.h
Category
Memory and String Manipulation Routines
Prototype
void *memccpy(void *dest, const void *src, int c, size_t n);
Description
Copies a block of n bytes.
memccpy is available on UNIX System V systems.
memccpy copies a block of n bytes from src to dest. The copying stops as soon
as either of the following occurs:
960
3.1 C++ Reference RAD Studio C Runtime Library Reference
961
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.20.1 memccpy
Header File
mem.h, string.h
Category
Prototype
void *memccpy(void *dest, const void *src, int c, size_t n);
Description
memccpy copies a block of n bytes from src to dest. The copying stops as soon as either of the following occurs:
962
3.1 C++ Reference RAD Studio C Runtime Library Reference
mem.h, string.h
Category
Memory and String Manipulation Routines, Inline Routines, C++ Prototyped Routines
Prototype
void *memchr(const void s, int c, size_t n);/ C only */
const void *memchr(const void *s, int c, size_t n);// C++ only
void *memchr(void *s, int c, size_t n);// C++ only
void *memchr(const void s, int c, size_t n);/ C and C++ */
void * _wmemchr(void s, int c, size_t n);/ unicode version */
Description
memchr searches the first n bytes of the block pointed to by s for character c.
Return Value
On success, memchr returns a pointer to the first occurrence of c in s; otherwise, it returns NULL.
Note: If you are using the intrinsic version of these functions, the case of n = 0 will return NULL.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char str[17];
char *ptr;
strcpy(str, "This is a string");
ptr = (char *) memchr(str, 'r', strlen(str));
if (ptr)
printf("The character 'r' is at position: %d\n", ptr - str);
else
printf("The character was not found\n");
return 0; 3
}
Portability
963
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.20.3 memcmp
Header File
mem.h, string.h
Category
Prototype
int memcmp(const void *s1, const void *s2, size_t n);
Description
memcmp compares the first n bytes of the blocks s1 and s2 as unsigned chars.
Return Value
964
3.1 C++ Reference RAD Studio C Runtime Library Reference
mem.h, string.h
Category
Prototype
void *memcpy(void *dest, const void *src, size_t n);
void *_wmemcpy(void *dest, const void *src, size_t n);
Description
memcpy copies a block of n bytes from src to dest. If src and dest overlap, the behavior of memcpy is undefined.
Return Value
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char src[] = "******************************";
char dest[] = "abcdefghijlkmnopqrstuvwxyz0123456709";
char *ptr;
printf("destination before memcpy: %s\n", dest);
ptr = (char *) memcpy(dest, src, strlen(src));
if (ptr)
printf("destination after memcpy: %s\n", dest);
else
printf("memcpy failed\n");
return 0;
}
Portability
3
3.1.4.20.5 memicmp
Header File
mem.h, string.h
Category
965
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
int memicmp(const void *s1, const void *s2, size_t n);
Description
memicmp compares the first n bytes of the blocks s1 and s2, ignoring character case (upper or lower).
Return Value
3.1.4.20.6 memmove
Header File
mem.h, string.h
Category
Prototype
3
void *memmove(void *dest, const void *src, size_t n);
Description
memmove copies a block of n bytes from src to dest. Even when the source and destination blocks overlap, bytes in the
overlapping locations are copied correctly.
966
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char *dest = "abcdefghijklmnopqrstuvwxyz0123456789";
char *src = "******************************";
printf("destination prior to memmove: %s\n", dest);
memmove(dest, src, 26);
printf("destination after memmove: %s\n", dest);
return 0;
}
Portability
mem.h, string.h
Category
Prototype
void *memset(void *s, int c, size_t n);
void *_wmemset(void *s, int c, size_t n);
Description
Return Value
memset returns s.
Example
#include <string.h>
#include <stdio.h> 3
#include <mem.h>
int main(void)
{
char buffer[] = "Hello world\n";
printf("Buffer before memset: %s\n", buffer);
memset(buffer, '*', strlen(buffer) - 1);
printf("Buffer after memset: %s\n", buffer);
return 0;
}
967
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Portability
3.1.4.20.8 setmem
Header File
mem.h
Category
Prototype
void setmem(void *dest, unsigned length, char value);
Description
setmem sets a block of length bytes, pointed to by dest, to the byte value.
Return Value
None.
Example
#include <stdio.h>
#include <alloc.h>
#include <mem.h>
int main(void)
{
char *dest;
dest = (char *) calloc(21, sizeof(char));
setmem(dest, 20, 'c');
printf("%s\n", dest);
return 0;
}
Portability
3 3.1.4.21 new.h
The following functions, macros, and classes are provided in new.h:
968
3.1 C++ Reference RAD Studio C Runtime Library Reference
Topics
Name Description
_new_handler ( see page 969) Header File
new.h
Syntax
typedef void (*pvf)();
pvf _new_handler;
Description
_new_handler contains a pointer to a function that takes no arguments and
returns void. If operator new() is unable to allocate the space required, it will call
the function pointed to by _new_handler; if that function returns it will try the
allocation again. By default, the function pointed to by _new_handler simply
terminates the application. The application can replace this handler, however,
with a function that can try to free up some space. This is done by assigning
directly to _new_handler or by calling the function set_new_handler, which
returns... more ( see page 969)
set_new_handler function ( see page 970) Header File
new.h
Category
Memory Routines
Syntax
typedef void (new * new_handler)();
new_handler set_new_handler(new_handler my_handler);
Description
set_new_handler installs the function to be called when the global operator new
or operator new[]() cannot allocate the requested memory. By default the new
operators throw an bad_alloc exception if memory cannot be allocated. You can
change this default behavior by calling set_new_handler to set a new handler. To
retain the traditional version of new, which does not throw exceptions, you can
use set_new_handler(0).
If new cannot allocate the requested memory, it calls the handler that was set by
a previous call to set_new_handler.... more ( see page 970)
3.1.4.21.1 _new_handler
Header File
new.h
Syntax
typedef void (*pvf)();
pvf _new_handler;
Description
_new_handler contains a pointer to a function that takes no arguments and returns void. If operator new() is unable to allocate
the space required, it will call the function pointed to by _new_handler; if that function returns it will try the allocation again. By
default, the function pointed to by _new_handler simply terminates the application. The application can replace this handler,
however, with a function that can try to free up some space. This is done by assigning directly to _new_handler or by calling the
function set_new_handler, which returns a pointer to the former handler.
As an alternative, you can set using the function set_new_handler, like this: 3
pvf set_new_handler(pvf p);
_new_handler is provided primarily for compatibility with C++ version 1.2. In most cases this functionality can be better provided
by overloading operator new().
Example
969
C Runtime Library Reference RAD Studio 3.1 C++ Reference
new.h
Category
Memory Routines
Syntax
typedef void (new * new_handler)();
new_handler set_new_handler(new_handler my_handler);
Description
set_new_handler installs the function to be called when the global operator new or operator new[]() cannot allocate the
requested memory. By default the new operators throw an bad_alloc exception if memory cannot be allocated. You can change
this default behavior by calling set_new_handler to set a new handler. To retain the traditional version of new, which does not
throw exceptions, you can use set_new_handler(0).
If new cannot allocate the requested memory, it calls the handler that was set by a previous call to set_new_handler. If there is
no handler installed by set_new_handler, new returns 0. my_handler should specify the actions to be taken when new cannot
satisfy a request for memory allocation. The new_handler type, defined in new.h, is a function that takes no arguments and
returns void. A new_handler can throw a bad_alloc exception.
void main(void) {
std::set_new_handler(mem_warn);
char *ptr = new char[100];
cout << "\nFirst allocation: ptr = " << hex << long(ptr);
ptr = new char[64000U];
970
3.1 C++ Reference RAD Studio C Runtime Library Reference
cout << "\nFinal allocation: ptr = " << hex << long(ptr);
std::set_new_handler(0); // Reset to default.
}
3.1.4.22 process.h
The following functions, macros, and classes are provided in process.h:
Topics
Name Description
P_xxxx #defines ( see page 975) Header File
process.h
Description
Modes used by the spawn... functions.
_adopt_thread ( see page 975) Header File
process.h
Category
Process Control Routines
Prototype
_PTHREAD_ADOPTION_DATA _adopt_thread(void (_USERENTRY
*__start_address)(void *), void * __arglist, int free_flag
);
Description
“Adopts” a thread, created with the Windows API CreateThread function, to the
C++Builder RTL by hooking up the necessary internal data (exceptions, stack
info, and so forth). _adopt_thread thereby allows the RTL to handle exception
issues in that thread. The execution path of this thread is then transferred to
another function (the adoptive thread function). From the RTL's perspective,
during the execution of this adoptive thread function, the thread appears as if it
had been created by a call to... more ( see page 975)
_beginthread ( see page 976) Header File
process.h
Category
Process Control Routines
Prototype
unsigned long _beginthread(void (_USERENTRY *__start)(void
*), unsigned __stksize, void *__arg);
Description
Starts execution of a new thread.
Note: The start_address must be declared to be _USERENTRY.
The _beginthread function creates and starts a new thread. The thread starts
execution at start_address.
The size of its stack in bytes is stack_size; the stack is allocated by the operating
system after the stack size is rounded up to the next multiple of 4096. The thread
is passed arglist as its only parameter; it can be NULL, but must be present. The
thread function should... more ( see page 976)
_beginthreadNT ( see page 978) Header File
process.h
Category
Process Control Routines
Prototype
unsigned long _beginthreadNT(void (_USERENTRY
*start_address)(void *), unsigned stack_size, void
*arglist, void *security_attrib, unsigned long
create_flags, unsigned long *thread_id); 3
Description
Starts execution of a new thread under Windows NT.
Note: The start_address must be declared to be _USERENTRY.
All multithread Windows NT programs must use _beginthreadNT or the
_beginthread function instead of the operating system thread-creation API
function because these functions perform initialization required for correct
operation of the runtime library functions. The _beginthreadNT function provides
support for the operating system security. These functions are available only in
the multithread libraries.
The _beginthreadNT... more ( see page 978)
971
C Runtime Library Reference RAD Studio 3.1 C++ Reference
972
3.1 C++ Reference RAD Studio C Runtime Library Reference
973
C Runtime Library Reference RAD Studio 3.1 C++ Reference
execl, execle, execlp, execlpe, execv, execve, execvp, execvpe, _wexecl, Header File
_wexecle, _wexeclp, _wexeclpe, _wexecv, _wexecve, _wexecvp, _wexecvpe ( process.h
see page 987)
Category
Process Control Routines
Prototype
int execl(char *path, char *arg0 *arg1, ..., *argn, NULL);
int _wexecl(wchar_t *path, wchar_t *arg0 *arg1, ..., *argn,
NULL);
int execle(char *path, char *arg0, *arg1, ..., *argn, NULL,
char **env);
int _wexecle(wchar_t *path, wchar_t *arg0, *arg1, ...,
*argn, NULL, wchar_t **env);
int execlp(char *path, char *arg0,*arg1, ..., *argn, NULL);
int _wexeclp(wchar_t *path, wchar_t *arg0,*arg1, ...,
*argn, NULL);
int execlpe(char *path, char *arg0, *arg1, ..., *argn,
NULL, char **env);
int _wexeclpe(wchar_t *path, wchar_t *arg0, *arg1, ...,
*argn, NULL, wchar_t **env);
int execv(char *path, char *argv[]);
int _wexecv(wchar_t *path, wchar_t *argv[]);
int execve(char *path, char... more ( see page 987)
getpid ( see page 989) Header File
process.h
Category
Process Control Routines
Prototype
unsigned getpid(void)
Description
Gets the process ID of a program.
This function returns the current process ID--an integer that uniquely identifies
the process.
Return Value
getpid returns the current process' ID.
Example
spawnl, spawnle, spawnlp, spawnlpe, spawnv, spawnve, spawnvp, spawnvpe, Header File
_wspawnl, _wspawnle, _wspawnlp, _wspawnlpe, _wspawnv, _wspawnve, process.h
_wspawnvp, _wspawnvpe ( see page 989)
Category
Process Control Routines
Prototype
int spawnl(int mode, char *path, char *arg0, arg1, ...,
argn, NULL);
int _wspawnl(int mode, wchar_t *path, wchar_t *arg0, arg1,
..., argn, NULL);
int spawnle(int mode, char *path, char *arg0, arg1, ...,
argn, NULL, char *envp[]);
int _wspawnle(int mode, wchar_t *path, wchar_t *arg0, arg1,
..., argn, NULL, wchar_t *envp[]);
int spawnlp(int mode, char *path, char *arg0, arg1, ...,
argn, NULL);
int _wspawnlp(int mode, wchar_t *path, wchar_t *arg0, arg1,
..., argn, NULL);
int spawnlpe(int mode, char *path, char *arg0, arg1, ...,
argn, NULL, char *envp[]);
int _wspawnlpe(int mode, wchar_t *path, wchar_t *arg0,
arg1, ...,... more ( see page 989)
974
3.1 C++ Reference RAD Studio C Runtime Library Reference
process.h
Description
Constant Meaning
P_WAIT Child runs separately, parent waits until exit
P_DETACH Child and parent run concurrently with child process in background mode
P_NOWAIT Child and parent run concurrently (Not implemented)
P_NOWAITO Child and parent run concurrently, but the child process is not saved
P_OVERLAY Child replaces parent so that parent no longer exists
3.1.4.22.2 _adopt_thread
Header File
process.h
Category
Prototype
_PTHREAD_ADOPTION_DATA _adopt_thread(void (_USERENTRY *__start_address)(void *), void *
__arglist, int free_flag );
Description
“Adopts” a thread, created with the Windows API CreateThread function, to the C++Builder RTL by hooking up the necessary
3
internal data (exceptions, stack info, and so forth). _adopt_thread thereby allows the RTL to handle exception issues in that
thread. The execution path of this thread is then transferred to another function (the adoptive thread function). From the RTL's
perspective, during the execution of this adoptive thread function, the thread appears as if it had been created by a call to
_beginthreadex and is allowed all the benefits, such as calling other RTL functions and throwing/catching exceptions.
To create a thread, a user normally calls _beginthread. This hooks up the internal data automatically. _adopt_thread is primarily
used in cases in which this internal data is not present. For example, this happens when a user is called from a thread that came
975
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Using _adopt_thread thereby allows C++Builder compiled DLLs to be used from non-C++Builder EXEs. _adopt_thread works by:
3.1.4.22.3 _beginthread
Header File
process.h
Category
Prototype
unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void
*__arg);
Description
3 Starts execution of a new thread.
The _beginthread function creates and starts a new thread. The thread starts execution at start_address.
The size of its stack in bytes is stack_size; the stack is allocated by the operating system after the stack size is rounded up to the
next multiple of 4096. The thread is passed arglist as its only parameter; it can be NULL, but must be present. The thread
function should terminate by simply returning; the _endthread. function will be called automatically. The _endthread function will
automatically close the handle, and set the return value of the thread to zero.
976
3.1 C++ Reference RAD Studio C Runtime Library Reference
Either this function or _beginthreadNT must be used instead of the operating system thread-creation API function because
_beginthread and _beginthreadNT perform initialization required for correct operation of the runtime library functions.
Return Value
_beginthread returns the handle of the new thread. The return value is a standard Windows handle that can be used in operating
system API's such as SuspendThread and ResumeThread.
On error, the function returns -1, and the global variable errno is set to one of the following values:
Also see the description of the Win32 API GetLastError, in the MSDN Library.
Example
/* Use the -tWM (32-bit multi-threaded target) command-line switch for this example */
#include <stdio.h>
#include <errno.h>
#include <stddef.h> /* _threadid variable */
#include <process.h> /* _beginthread, _endthread */
#include <time.h> /* time, _ctime */
void thread_code(void *threadno)
{
time_t t;
time(&t);
printf("Executing thread number %d, ID = %d, time = %s\n",
(int)threadno, _threadid, ctime(&t));
void start_thread(int i)
{
int thread_id;
#if defined(__WIN32__)
if ((thread_id = _beginthread(thread_code,4096,(void *)i)) == (unsigned long)-1)
#else
if ((thread_id = _beginthread(thread_code,4096,(void *)i)) == -1)
#endif
{
printf("Unable to create thread %d, errno = %d\n",i,errno);
return;
}
printf("Created thread %d, ID = %ld\n",i,thread_id);
}
int main(void)
{
int i;
for (i = 1; i < 20; i++)
start_thread(i); 3
printf("Hit ENTER to exit main thread.\n");
getchar();
return 0;
}
Portability
977
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.22.4 _beginthreadNT
Header File
process.h
Category
Prototype
unsigned long _beginthreadNT(void (_USERENTRY *start_address)(void *), unsigned stack_size,
void *arglist, void *security_attrib, unsigned long create_flags, unsigned long *thread_id);
Description
All multithread Windows NT programs must use _beginthreadNT or the _beginthread function instead of the operating system
thread-creation API function because these functions perform initialization required for correct operation of the runtime library
functions. The _beginthreadNT function provides support for the operating system security. These functions are available only in
the multithread libraries.
The _beginthreadNT function creates and starts a new thread. The thread starts execution at start_address. When your thread
terminates, the _endthread function will be called automatically. _endthread will close the thread handle, and call the ExitThread
API.
The size of its stack in bytes is stack_size; the stack is allocated by the operating system after the stack size is rounded up to the
next multiple of 4096. The thread arglist can be NULL, but must be present.
The _beginthreadNT function uses the security_attr pointer to access the SECURITY_ATTRIBUTES structure. The structure
contains the security attributes for the thread. If security_attr is NULL, the thread is created with default security attributes. The
thread handle is not inherited if security_attr is NULL.
_beginthreadNT reads the create_flags variable for flags that provide additional information about the thread creation. This
variable can be zero, specifying that the thread will run immediately upon creation. The variable can also be
CREATE_SUSPENDED; in which case, the thread will not run until the ResumeThread function is called. ResumeThread is
provided by the Win32 API.
Return Value
On success, _beginthreadNT returns the handle of the new thread. The return value is a standard Windows handle that can be
used in operating system API's such as SuspendThread and ResumeThread.
On error, it returns -1, and the global variable errno is set to one of the following values:
Also see the description of the Win32 API GetLastError, in the MSDN Library.
Example
/* Use the -tWM (32-bit multi-threaded target) command-line switch for this example */
978
3.1 C++ Reference RAD Studio C Runtime Library Reference
979
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.22.5 _beginthreadex
Header File
process.h
Category
Prototype
unsigned long _beginthreadex(void *__security_attr, unsigned __stksize, unsigned (__stdcall
*__start)(void *), void *__arg, unsigned __create_flags, unsigned *__thread_id);
Description
Creates a thread and allows specifying the other parameters of the OS API CreateThread (such as security and thread creation
flags). The _endthreadex function will be called automatically when the thread function terminates. The value returned from your
thread function will be passed along to _endthreadex, which in turn will pass it along to the ExitThread API. The return value can
then be retrieved using the GetExitCodeThread API.
Unlike _endthread, the _endthreadex function does not close the thread handle, thereby allowing other threads to block on this
one without fear that the handle will be freed out from under the system.
Other than the order of parameters and the closing of the thread handle, _beginthreadex performs same operation as
_beginthreadNT.
Note: Note: The start address needs to be defined to return an unsigned, which is the thread exit code.
Return Value
_beginthreadex returns the handle of the new thread. The return value is a standard Windows handle that can be used in
operating system API's such as SuspendThread and ResumeThread.
Also see the description of the Win32 API GetLastError, in the MSDN Library.
Example
//* Use the -tWM (32-bit multi-threaded target) command-line switch for this example */
#pragma checkoption -tWM
#include <windows.h>
#include <process.h>
#include <stdio.h>
#define NTHREADS 25
3 /* This function acts as the 'main' function for each new thread */
static unsigned __stdcall threadMain(void *arg)
{
printf("Thread %2d has an ID of %u\n", (int)arg, GetCurrentThreadId());
return 0;
}
int main(void)
{
HANDLE hThreads[NTHREADS];
int i;
980
3.1 C++ Reference RAD Studio C Runtime Library Reference
unsigned threadId;
SECURITY_ATTRIBUTES sa = {
sizeof(SECURITY_ATTRIBUTES), /* structure size */
0, /* No security descriptor */
TRUE /* Thread handle is inheritable */
};
/* Create NTHREADS inheritable threads that are initially suspended and that will run
starting at threadMain()*/
for(i = 0; i < NTHREADS; i++) {
hThreads[i] = (HANDLE)_beginthreadex(
&sa, /* Thread security */
4096, /* Thread stack size */
threadMain, /* Thread starting address */
(void *)i, /* Thread start argument */
CREATE_SUSPENDED, /* Create in suspended state */
&threadId); /* Thread ID */
if(hThreads[i] == INVALID_HANDLE_VALUE) {
MessageBox(0, "Thread Creation Failed", "Error", MB_OK);
return 1;
}
printf("Created thread %2d with an ID of %u\n", i, threadId);
}
printf("\nPress ENTER to thaw all threads\n\n");
getchar();
3.1.4.22.6 _c_exit
Header File
process.h
Category
Prototype
3
void _c_exit(void);
Description
_c_exit performs the same cleanup as _exit, except that it does not terminate the calling process.
Return Value
981
C Runtime Library Reference RAD Studio 3.1 C++ Reference
None.
Example
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
main()
{
int fd;
char c;
3.1.4.22.7 _cexit
Header File
process.h
Category
Prototype
void _cexit(void);
Description
3 _cexit performs the same cleanup as exit, closing all files but without terminating the calling process. The _cexit function calls
any registered "exit functions" (posted with atexit). Before _cexit returns, it flushes all input/output buffers and closes all streams
that were open.
Return Value
None.
Example
#include <windows.h>
982
3.1 C++ Reference RAD Studio C Runtime Library Reference
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
void exit_func(void)
{
printf("Exit function called\n\n");
printf("Close Window to return to program... It will beep if able to read from file");
}
int main(void)
{
int fd;
char c;
if ((fd = open("_cexit.c",O_RDONLY)) < 0)
{
printf("Unable to open _cexit.c for reading\n");
return 1;
}
atexit(exit_func);
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d before _cexit\n",fd);
else
printf("Successfully read from open file handle %d before _cexit\n",fd);
_cexit();
if (read(fd,&c,1) == 1)
MessageBeep(0);
return 0;
}
Portability
3.1.4.22.8 _endthread
Header File
process.h
Category
Prototype
void _endthread(void);
Description
The _endthread function terminates the currently executing thread by closing the thread handle and calling the ExitThread API. 3
The thread must have been started by an earlier call to _beginthread or _beginthreadNT.. _endthread is called automatically by
the runtime library when your thread function terminates.
This function is available in the multithread libraries; it is not in the single-threaded libraries.
Return Value
983
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.22.9 _endthreadex
Header File
process.h
Category
Prototype
void _endthreadex(unsigned thread_retval);
Description
Terminates execution of the current thread by calling the ExitThread API, but without closing the handle. The thread must have
been created by an earlier call to _beginthreadex. The runtime library will call _endthreadex autotmatically, when your thread
function terminates. _endthreadex receives the return value of your thread function in thread_retval, and will pass it along to the
Win32 ExitThread API.
Note: Note: Performs the same operation as _endthread(), but does not close the thread handle.
Return Value
None.
3.1.4.22.10 _expand
Header File
process.h
Category
Memory Routines
Prototype
void *_expand(void *block, size_t size);
Description
This function attempts to change the size of an allocated memory block without moving the block's location in the heap. The data
in the block are not changed, up to the smaller of the old and new sizes of the block. The block must have been allocated earlier
with malloc, calloc, or realloc, and must not have been freed.
Return Value
If _expand is able to resize the block without moving it, _expand returns a pointer to the block, whose address is unchanged. If
3 _expand is unsuccessful, it returns a NULL pointer and does not modify or resize the block.
Example
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
void main(void)
{
char *bufchar, *newbuf;
984
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.22.11 _unadopt_thread
Header File
process.h
Category
Prototype
void _unadopt_thread(_PTHREAD_ADOPTION_DATA thd);
Description
Frees the RTL thread-specific data associated with a previous call to _adopt_thread.
Return Value
None.
Portability
3.1.4.22.12 cwait
Header File 3
process.h
Category
Prototype
int cwait(int *statloc, int pid, int action);
985
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
The cwait function waits for a child process to terminate. The process ID of the child to wait for is pid. If statloc is not NULL, it
points to the location where cwait will store the termination status. The action specifies whether to wait for the process alone, or
for the process and all of its children.
If the child process terminated normally (by calling exit, or returning from main), the termination status word is defined as follows:
If the child process terminated abnormally, the termination status word is defined as follows:
If pid is 0, cwait waits for any child process to terminate. Otherwise, pid specifies the process ID of the process to wait for; this
value must have been obtained by an earlier call to an asynchronous spawn function.
The acceptable values for action are WAIT_CHILD, which waits for the specified child only, and WAIT_GRANDCHILD, which
waits for the specified child and all of its children. These two values are defined in process.h.
Return Value
When cwait returns after a normal child process termination, it returns the process ID of the child.
When cwait returns after an abnormal child termination, it returns -1 to the parent and sets errno to EINTR (the child process
terminated abnormally).
If cwait returns without a child process completion, it returns a -1 value and sets errno to one of the following values:
Portability
3 POSIX Win32 ANSI C ANSI C++
+
986
3.1 C++ Reference RAD Studio C Runtime Library Reference
process.h
Category
Prototype
int execl(char *path, char *arg0 *arg1, ..., *argn, NULL);
int _wexecl(wchar_t *path, wchar_t *arg0 *arg1, ..., *argn, NULL);
int execle(char *path, char *arg0, *arg1, ..., *argn, NULL, char **env);
int _wexecle(wchar_t *path, wchar_t *arg0, *arg1, ..., *argn, NULL, wchar_t **env);
int execlp(char *path, char *arg0,*arg1, ..., *argn, NULL);
int _wexeclp(wchar_t *path, wchar_t *arg0,*arg1, ..., *argn, NULL);
int execlpe(char *path, char *arg0, *arg1, ..., *argn, NULL, char **env);
int _wexeclpe(wchar_t *path, wchar_t *arg0, *arg1, ..., *argn, NULL, wchar_t **env);
int execv(char *path, char *argv[]);
int _wexecv(wchar_t *path, wchar_t *argv[]);
int execve(char *path, char *argv[], char **env);
int _wexecve(wchar_t *path, wchar_t *argv[], wchar_t **env);
int execvp(char *path, char *argv[]);
int _wexecvp(wchar_t *path, wchar_t *argv[]);
int execvpe(char *path, char *argv[], char **env);
int _wexecvpe(wchar_t *path, wchar_t *argv[], wchar_t **env);
Description
The functions in the exec... family load and run (execute) other programs, known as child processes. When an exec... call
succeeds, the child process overlays the parent process. There must be sufficient memory available for loading and executing
the child process.
path is the file name of the called child process. The exec... functions search for path using the standard search algorithm:
• If no explicit extension is given, the functions search for the file as given. If the file is not found, they add .EXE and search
3
again. If not found, they add .COM and search again. If found, the command processor, COMSPEC (Windows) or
COMMAND.COM (DOS), is used to run the batch file.
• If an explicit extension or a period is given, the functions search for the file exactly as given.
The suffixes l, v, p, and e added to the exec... "family name" specify that the named function operates with certain capabilities.
987
C Runtime Library Reference RAD Studio 3.1 C++ Reference
l specifies that the argument pointers (arg0, arg1, ..., argn) are passed as separate arguments.
Typically, the l suffix is used when you know in advance the number of arguments to be passed.
v specifies that the argument pointers (argv[0] ..., arg[n]) are passed as an array of pointers. Typically,
the v suffix is used when a variable number of arguments is to be passed.
p specifies that the function searches for the file in those directories specified by the PATH environment
variable (without the p suffix, the function searches only the current working directory). If the path
parameter does not contain an explicit directory, the function searches first the current directory, then
the directories set with the PATH environment variable.
e specifies that the argument env can be passed to the child process, letting you alter the environment
for the child process. Without the e suffix, child processes inherit the environment of the parent
process.
Each function in the exec... family must have one of the two argument-specifying suffixes (either l or v). The path search and
environment inheritance suffixes (p and e) are optional; for example:
• execl is an exec... function that takes separate arguments, searches only the root or current directory for the child, and passes
on the parent's environment to the child.
• execvpe is an exec... function that takes an array of argument pointers, incorporates PATH in its search for the child process,
and accepts the env argument for altering the child's environment.
The exec... functions must pass at least one argument to the child process (arg0 or argv[0]); this argument is, by convention, a
copy of path. (Using a different value for this 0th argument won't produce an error.)
path is available for the child process.
When the l suffix is used, arg0 usually points to path, and arg1, ..., argn point to character strings that form the new list of
arguments. A mandatory null following argn marks the end of the list.
When the e suffix is used, you pass a list of new environment settings through the argument env. This environment argument is
an array of character pointers. Each element points to a null-terminated character string of the form
envvar = value
where envvar is the name of an environment variable, and value is the string value to which envvar is set. The last element in
env is null. When env is null, the child inherits the parents' environment settings.
The combined length of arg0 + arg1 + ... + argn (or of argv[0] + argv[1] + ... + argn[n]), including space characters that separate
the arguments, must be less than 260 bytes. Null terminators are not counted.
When an exec... function call is made, any open files remain open in the child process.
Return Value
If successful, the exec... functions do not return. On error, the exec... functions return -1, and the global variable errno is set to
one of the following values:
Example
/* execl() example */
#include <stdio.h>
#include <process.h>
988
3.1 C++ Reference RAD Studio C Runtime Library Reference
int loop;
printf("%s running...\n\n", argv[0]);
3.1.4.22.14 getpid
Header File
process.h
Category
Prototype
unsigned getpid(void)
Description
This function returns the current process ID--an integer that uniquely identifies the process.
Return Value
Example
#include <stdio.h>
#include <process.h>
int main()
{
printf("This program's process identification number (PID) "
"number is %X\n", getpid());
printf("Note: under DOS it is the PSP segment\n");
return 0;
}
Portability
989
C Runtime Library Reference RAD Studio 3.1 C++ Reference
process.h
Category
Prototype
int spawnl(int mode, char *path, char *arg0, arg1, ..., argn, NULL);
int _wspawnl(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL);
int spawnle(int mode, char *path, char *arg0, arg1, ..., argn, NULL, char *envp[]);
int _wspawnle(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL, wchar_t *envp[]);
int spawnlp(int mode, char *path, char *arg0, arg1, ..., argn, NULL);
int _wspawnlp(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL);
int spawnlpe(int mode, char *path, char *arg0, arg1, ..., argn, NULL, char *envp[]);
int _wspawnlpe(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL, wchar_t *envp[]);
int spawnv(int mode, char *path, char *argv[]);
int _wspawnv(int mode, wchar_t *path, wchar_t *argv[]);
int spawnve(int mode, char *path, char *argv[], char *envp[]);
int _wspawnve(int mode, wchar_t *path, wchar_t *argv[], wchar_t *envp[]);
int spawnvp(int mode, char *path, char *argv[]);
int _wspawnvp(int mode, wchar_t *path, wchar_t *argv[]);
int spawnvpe(int mode, char *path, char *argv[], char *envp[]);
int _wspawnvpe(int mode, wchar_t *path, wchar_t *argv[], wchar_t *envp[]);
Note: In spawnle, spawnlpe, spawnv, spawnve, spawnvp, and spawnvpe, the last string must be NULL.
Description
The functions in the spawn... family create and run (execute) other files, known as child processes. There must be sufficient
memory available for loading and executing a child process.
The value of mode determines what action the calling function (the parent process) takes after the spawn... call. The possible
values of mode are
P_WAIT Puts parent process on hold until child process completes execution.
P_NOWAIT Continues to run parent process while child process runs. The child process ID is returned, so that
the parent can wait for completion using cwait or wait.
P_NOWAITO Identical to P_NOWAIT except that the child process ID isn't saved by the operating system, so the
parent process can't wait for it using cwait or wait.
P_DETACH Identical to P_NOWAITO, except that the child process is executed in the background with no access
3 to the keyboard or the display.
P_OVERLAY Overlays child process in memory location formerly occupied by parent. Same as an exec... call.
path is the file name of the called child process. The spawn... function calls search for path using the standard operating system
search algorithm:
• If there is no extension or no period, they search for an exact file name. If the file is not found, they search for files first with
the extension EXE, then COM, and finally BAT.
990
3.1 C++ Reference RAD Studio C Runtime Library Reference
• If an extension is given, they search only for the exact file name.
• If only a period is given, they search only for the file name with no extension.
• If path does not contain an explicit directory, spawn... functions that have the p suffix search the current directory, then the
directories set with the operating system PATH environment variable.
The suffixes p, l, and v, and e added to the spawn... "family name" specify that the named function operates with certain
capabilities.
p The function searches for the file in those directories specified by the PATH environment
variable. Without the p suffix, the function searches only the current working directory.
l The argument pointers arg0, arg1, ..., argn are passed as separate arguments. Typically, the l suffix
is used when you know in advance the number of arguments to be passed.
v The argument pointers argv[0], ..., arg[n] are passed as an array of pointers. Typically, the v suffix is
used when a variable number of arguments is to be passed.
e The argument envp can be passed to the child process, letting you alter the environment for the child
process. Without the e suffix, child processes inherit the environment of the parent process.
Each function in the spawn... family must have one of the two argument-specifying suffixes (either l or v). The path search and
environment inheritance suffixes (p and e) are optional.
For example:
• spawnl takes separate arguments, searches only the current directory for the child, and passes on the parent's environment to
the child.
• spawnvpe takes an array of argument pointers, incorporates PATH in its search for the child process, and accepts the envp
argument for altering the child's environment.
The spawn... functions must pass at least one argument to the child process (arg0 or argv[0]). This argument is, by convention, a
copy of path. (Using a different value for this 0 argument won't produce an error.) If you want to pass an empty argument list
to the child process, then arg0 or argv[0] must be NULL.
When the l suffix is used, arg0 usually points to path, and arg1, ...., argn point to character strings that form the new list of
arguments. A mandatory null following argn marks the end of the list.
When the e suffix is used, you pass a list of new environment settings through the argument envp. This environment argument is
an array of character pointers. Each element points to a null-terminated character string of the form
envvar = value
where envvar is the name of an environment variable, and value is the string value to which envvar is set. The last element in
envp[] is null. When envp is null, the child inherits the parents' environment settings.
The combined length of arg0 + arg1 + ... + argn (or of argv[0] + argv[1] + ... + argv[n]), including space characters that separate
the arguments, must be less than 260 bytes for Windows (128 for DOS). Null-terminators are not counted.
When a spawn... function call is made, any open files remain open in the child process.
Return Value
When successful, the spawn... functions, where mode is P_WAIT, return the child process' exit status (0 for a normal
termination). If the child specifically calls exit with a nonzero argument, its exit status can be set to a nonzero value.
If mode is P_NOWAIT or P_NOWAITO, the spawn functions return the process ID of the child process. The ID obtained when
using P_NOWAIT can be passed to cwait.
3
On error, the spawn... functions return -1, and the global variable errno is set to one of the following values:
991
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <process.h>
#include <stdio.h>
void spawnl_example(void)
{
int result;
result = spawnl(P_WAIT, "bcc32.exe", "bcc32.exe", NULL);
if (result == -1)
{
perror("Error from spawnl");
exit(1);
}
}
int main(void)
{
spawnl_example();
return 0;
}
3.1.4.22.16 wait
Header File
process.h
Category
Prototype
int wait(int *statloc);
Description
The wait function waits for one or more child processes to terminate. The child processes must be those created by the calling
program; wait cannot wait for grandchildren (processes spawned by child processes). If statloc is not NULL, it points to location
where wait will store the termination status.
If the child process terminated normally (by calling exit, or returning from main), the termination status word is defined as follows:
Return Value
When wait returns after a normal child process termination it returns the process ID of the child.
992
3.1 C++ Reference RAD Studio C Runtime Library Reference
When wait returns after an abnormal child termination it returns -1 to the parent and sets errno to EINTR.
If wait returns without a child process completion it returns a -1 value and sets errno to:
Portability
3.1.4.23 setjmp.h
The following functions, macros, and classes are provided in setjmp.h:
Topics
Name Description
longjmp ( see page 994) Header File
setjmp.h
Category
Miscellaneous Routines
Prototype
void longjmp(jmp_buf jmpb, int retval);
Description
Performs nonlocal goto.
A call to longjmp restores the task state captured by the last call to setjmp with
the argument jmpb. It then returns in such a way that setjmp appears to have
returned with the value retval.
A Win32 task state includes:
• Register variables
• EBX, EDI, ESI
• Stack pointer (ESP)
• Frame pointer (EBP)
• No segment registers are saved
• Flags are not saved
A task state is complete enough that setjmp and longjmp can
be used to implement co-routines.
setjmp must be called before longjmp. The... more ( see
page 994)
993
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.23.1 longjmp
Header File
setjmp.h
Category
Miscellaneous Routines
Prototype
void longjmp(jmp_buf jmpb, int retval);
Description
A call to longjmp restores the task state captured by the last call to setjmp with the argument jmpb. It then returns in such a way
that setjmp appears to have returned with the value retval.
• Register variables
• EBX, EDI, ESI
3 • Stack pointer (ESP)
• Frame pointer (EBP)
• No segment registers are saved
• Flags are not saved
A task state is complete enough that setjmp and longjmp can be used to implement co-routines.
setjmp must be called before longjmp. The routine that called setjmp and set up jmpb must still be active and cannot have
returned before the longjmp is called. If this happens, the results are unpredictable.
994
3.1 C++ Reference RAD Studio C Runtime Library Reference
longjmp cannot pass the value 0; if 0 is passed in retval, longjmp will substitute 1.
Return Value
None.
Example
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
void subroutine(jmp_buf);
int main(void)
{
int value;
jmp_buf jumper;
value = setjmp(jumper);
if (value != 0)
{
printf("Longjmp with value %d\n", value);
exit(value);
}
printf("About to call subroutine ... \n");
subroutine(jumper);
return 0;
}
void subroutine(jmp_buf jumper)
{
longjmp(jumper,1);
}
Portability
3.1.4.23.2 setjmp
Header File
setjmp.h
Category
Miscellaneous Routines
Prototype
int setjmp(jmp_buf jmpb);
Description
A later call to longjmp with jmpb restores the captured task state and returns in such a way that setjmp appears to have returned
with the value val.
995
C Runtime Library Reference RAD Studio 3.1 C++ Reference
int value;
jmp_buf jumper;
value = setjmp(jumper);
if (value != 0)
{
printf("Longjmp with value %d\n", value);
exit(value);
}
printf("About to call subroutine ... \n");
subroutine(jumper);
return 0;
}
void subroutine(jmp_buf jumper)
{
longjmp(jumper,1);
}
Portability
3.1.4.24 share.h
The following functions, macros, and classes are provided in share.h:
3 Topics
Name Description
SH_xxxx #defines ( see page 997) Header File
share.h
Description
File-sharing mode for use with sopen.
996
3.1 C++ Reference RAD Studio C Runtime Library Reference
share.h
Description
These file-sharing attributes are in addition to any locking performed on the files.
3.1.4.25 signal.h
The following functions, macros, and classes are provided in signal.h:
Topics
Name Description
SIGxxxx #defines ( see page 998) Header File
signal.h
Description
Signal types used by raise and signal.
SIG_xxx #defines ( see page 998) Header File
signal.h
Description
Predefined functions for handling signals generated by raise or by external
events.
raise ( see page 999) Header File
signal.h
Category
Process Control Routines
Prototype
int raise(int sig); 3
Description
Sends a software signal to the executing program.
raise sends a signal of type sig to the program. If the program has installed a
signal handler for the signal type specified by sig, that handler will be executed. If
no handler has been installed, the default action for that signal type will be taken.
The signal types currently defined in signal.h are noted here:
997
C Runtime Library Reference RAD Studio 3.1 C++ Reference
signal.h
Description
(*) Signal types marked with a (*) aren't generated by Borland C++ during normal operation. However, they can be generated
with raise.
signal.h
3 Description
Name Meaning
SIG_DFL Terminate the program
SIG_IGN No action, ignore signal
SIG_ERR Return error code
998
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.25.3 raise
Header File
signal.h
Category
Prototype
int raise(int sig);
Description
raise sends a signal of type sig to the program. If the program has installed a signal handler for the signal type specified by sig,
that handler will be executed. If no handler has been installed, the default action for that signal type will be taken.
Note: SIGABRT isn’t generated by C++Builder during normal operation. It can, however, be generated by abort, raise, or
unhandled exceptions.
Return Value
Example
#include <signal.h>
int main(void)
{ 3
int a, b;
a = 10;
b = 0;
if (b == 0)
/* preempt divide by zero error */
raise(SIGFPE);
a = a / b;
return 0;
}
999
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Portability
signal.h
Category
Prototype
void (_USERENTRY *signal(int sig, void (_USERENTRY *func)(int sig[, int subcode])))(int);
Description
signal determines how receipt of signal number sig will subsequently be treated. You can install a user-specified handler routine
(specified by the argument func) or use one of the two predefined handlers, SIG_DFL and SIG_IGN, in signal.h. The function
func must be declared with the _USERENTRY calling convention.
A routine that catches a signal (such as a floating point) also clears the signal. To continue to receive signals, a signal handler
must be reinstalled by calling signal again.
3
User-defined signals can be generated only by calling raise. Default action is to ignore the signal.
signal.h defines a type called sig_atomic_t, the largest integer type the processor can load or store atomically in the presence of
asynchronous interrupts (this is a 32-bit integer -- a Borland C++ integer).
When a signal is generated by the raise function or by an external event, the following two things happen:
• If a user-specified handler has been installed for the signal, the action for that signal type is set to SIG_DFL.
1000
3.1 C++ Reference RAD Studio C Runtime Library Reference
• The user-specified function is called with the signal type as the parameter.
User-specified handler functions can terminate by a return or by a call to abort, _exit, exit, or longjmp. If your handler function is
expected to continue to receive and handle more signals, you must have the handler function call signal again.
Borland C++ implements an extension to ANSI C when the signal type is SIGFPE, SIGSEGV, or SIGILL. The user-specified
handler function is called with one or two extra parameters. If SIGFPE, SIGSEGV, or SIGILL has been raised as the result of
an explicit call to the raise function, the user-specified handler is called with one extra parameter, an integer specifying that
the handler is being explicitly invoked. The explicit activation values for SIGFPE, SIGSEGV and SIGILL are as follows
Note: Declarations of these types are defined in float.h.
SIGFPE FPE_EXPLICITGEN
SIGSEGV SEGV_EXPLICITGEN
SIGILL ILL_EXPLICITGEN
If SIGFPE is raised because of a floating-point exception, the user handler is called with one extra parameter that specifies the
FPE_xxx type of the signal. If SIGSEGV, SIGILL, or the integer-related variants of SIGFPE signals (FPE_INTOVFLOW or
FPE_INTDIV0) are raised as the result of a processor exception, the user handler is called with two extra parameters:
1.The SIGFPE, SIGSEGV, or SIGILL exception type (see float.h for all these types). This first parameter is the usual ANSI signal
type.
2.An integer pointer into the stack of the interrupt handler that called the user-specified handler. This pointer points to a list of the
processor registers saved when the exception occurred. The registers are in the same order as the parameters to an interrupt
function; that is, EBP, EDI, ESI, EDS, ES, EDX, ECX, EBX, EAX, EIP, CS, EFL. To have a register value changed when the
handler returns, change one of the locations in this list.
In this way, the handler can examine and make any adjustments to the registers that you want.
The following SIGFPE-type signals can occur (or be generated). They correspond to the exceptions that the 80x87 family is
capable of detecting, as well as the "INTEGER DIVIDE BY ZERO" and the "INTERRUPT ON OVERFLOW" on the main CPU.
(The declarations for these are in float.h.)
The FPE_INTOVFLOW and FPE_INTDIV0 signals are generated by integer operations, and the others are generated by
floating-point operations. Whether the floating-point exceptions are generated depends on the coprocessor control word, which
can be modified with _control87. Denormal exceptions are handled by Borland C++ and not passed to a signal handler.
1001
C Runtime Library Reference RAD Studio 3.1 C++ Reference
When the signal type is SIGFPE, SIGSEGV, or SIGILL, a return from a signal handler is generally not advisable if the state of the
floating point processor is corrupt, the results of an integer division are wrong, an operation that shouldn't have overflowed did, a
bound instruction failed, or an illegal operation was attempted. The only time a return is reasonable is when the handler alters
the registers so that a reasonable return context exists or the signal type indicates that the signal was generated explicitly (for
example, FPE_EXPLICITGEN, SEGV_EXPLICITGEN, or ILL_EXPLICITGEN). Generally in this case you would print an error
message and terminate the program using _exit, exit, or abort. If a return is executed under any other conditions, the program's
action will probably be unpredictable.
Note: Take special care when using the signal function in a multithread program. The SIGINT, SIGTERM, and SIGBREAK
signals can be used only by the main thread (thread one) in a non-Win32 application. When one of these signals occurs, the
currently executing thread is suspended, and control transfers to the signal handler (if any) set up by thread one. Other signals
can be handled by any thread.
Note: A signal handler should not use C++ runtime library functions, because a semaphore deadlock might occur. Instead, the
handler should simply set a flag or post a semaphore, and return immediately.
Return Value
On success, signal returns a pointer to the previous handler routine for the specified signal type.
On error, signal returns SIG_ERR, and the external variable errno is set to EINVAL.
Example
/* signal example */
/*
This example installs a signal handler routine for SIGFPE,
catches an integer overflow condition, makes an adjustment to AX
register, and returns. This example program MAY cause your computer
to crash, and will produce runtime errors depending on which memory
model is used.
*/
#pragma inline
#include <stdio.h>
#include <signal.h>
#ifdef __cplusplus
typedef void (*fptr)(int);
#else
typedef void (*fptr)();
#endif
void Catcher(int *reglist)
3 {
signal(SIGFPE, (fptr)Catcher); // ******reinstall signal handler
printf("Caught it!\n"); *(reglist + 8) = 3; /* make return AX = 3 */
}
int main(void)
{
signal(SIGFPE, (fptr)Catcher); /* cast Catcher to appropriate type */
asm mov ax,07FFFH /* AX = 32767 */
asm inc ax /* cause overflow */
asm into /* activate handler */
/* The handler set AX to 3 on return. If that had not happened,
1002
3.1 C++ Reference RAD Studio C Runtime Library Reference
there would have been another exception when the next 'into'
executed after the 'dec' instruction. */
asm dec ax /* no overflow now */
asm into /* doesn't activate */
return 0;
}
Portability
3.1.4.26 stdarg.h
The following functions, macros, and classes are provided in stdarg.h:
Topics
Name Description
va_arg, va_end, va_start ( see page 1003) Header File
stdarg.h
Category
Variable Argument List Routines
Prototype
void va_start(va_list ap, lastfix);
type va_arg(va_list ap, type);
void va_end(va_list ap);
Description
Implement a variable argument list.
Some C functions, such as vfprintf and vprintf, take variable argument lists in
addition to taking a number of fixed (known) parameters. The va_arg, va_end,
and va_start macros provide a portable way to access these argument lists. They
are used for stepping through a list of arguments when the called function does
not know the number and types of the arguments being passed.
The header file stdarg.h declares one type (va_list) and... more ( see page
1003)
stdarg.h
Category
Prototype
void va_start(va_list ap, lastfix);
type va_arg(va_list ap, type);
3
void va_end(va_list ap);
Description
Some C functions, such as vfprintf and vprintf, take variable argument lists in addition to taking a number of fixed (known)
parameters. The va_arg, va_end, and va_start macros provide a portable way to access these argument lists. They are used for
stepping through a list of arguments when the called function does not know the number and types of the arguments being
1003
C Runtime Library Reference RAD Studio 3.1 C++ Reference
passed.
The header file stdarg.h declares one type (va_list) and three macros (va_start, va_arg, and va_end).
• va_list: This array holds information needed by va_arg and va_end. When a called function takes a variable argument list, it
declares a variable ap of type va_list.
• va_start: This routine (implemented as a macro) sets ap to point to the first of the variable arguments being passed to the
function. va_start must be used before the first call to va_arg or va_end.
• va_start takes two parameters: ap and lastfix. (ap is explained under va_list in the preceding paragraph; lastfix is the name of
the last fixed parameter being passed to the called function.)
• va_arg: This routine (also implemented as a macro) expands to an expression that has the same type and value as the next
argument being passed (one of the variable arguments). The variable ap to va_arg should be the same ap that va_start
initialized.
Note: Because of default promotions, you cannot use char, unsigned char
, or float types with va_arg.
Note: The first time va_arg is used, it returns the first argument in the list. Each successive time va_arg is used, it returns the
next argument in the list. It does this by first dereferencing ap, and then incrementing ap to point to the following item. va_arg
uses the type to both perform the dereference and to locate the following item. Each successive time va_arg is invoked, it
modifies ap to point to the next argument in the list.
• va_end: This macro helps the called function perform a normal return. va_end might modify ap in such a way that it cannot be
used unless va_start is recalled. va_end should be called after va_arg has read all the arguments; failure to do so might
cause strange, undefined behavior in your program.
Return Value
va_start and va_end return no values; va_arg returns the current argument in the list (the one that ap is pointing to).
Example
#include <stdio.h>
#include <stdarg.h>
/* calculate sum of a 0 terminated list */
void sum(char *msg, ...)
{
int total = 0;
va_list ap;
int arg;
va_start(ap, msg);
while ((arg = va_arg(ap,int)) != 0) {
total += arg;
}
printf(msg, total);
va_end(ap);
}
int main(void) {
sum("The total of 1+2+3+4 is %d\n", 1,2,3,4,0);
return 0;
}
Portability
3.1.4.27 stddef.h
The following functions, macros, and classes are provided in stddef.h:
1004
3.1 C++ Reference RAD Studio C Runtime Library Reference
Topics
Name Description
NULL #define ( see page 1005) Header File
stddef.h
Description
Null pointer constant that is compatible with any data object pointer. It is not
compatible with function pointers. When a pointer is equivalent to NULL it is
guaranteed not to point to any data object defined within the program.
_threadid ( see page 1005) Header File
stddef.h
Syntax
extern long _threadid;
Description
_threadid is a long integer that contains the ID of the currently executing thread.
It is implemented as a macro, and should be declared only by including stddef.h.
offsetof ( see page 1006) Header File
stddef.h
Category
Memory Routines
Prototype
size_t offsetof(struct_type, struct_member);
Description
Gets the byte offset to a structure member.
offsetof is available only as a macro. The argument struct_type is a struct type.
struct_member is any element of the struct that can be accessed through the
member selection operators or pointers.
If struct_member is a bit field, the result is undefined.
See also sizeof for more information on memory allocation and alignment of
structures.
Return Value
offsetof returns the number of bytes from the start of the structure to the start of
the named structure member.
Portability
stddef.h
Description
Null pointer constant that is compatible with any data object pointer. It is not compatible with function pointers. When a pointer is
equivalent to NULL it is guaranteed not to point to any data object defined within the program.
3.1.4.27.2 _threadid
Header File
stddef.h
Syntax 3
extern long _threadid;
Description
_threadid is a long integer that contains the ID of the currently executing thread. It is implemented as a macro, and should be
declared only by including stddef.h.
1005
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.27.3 offsetof
Header File
stddef.h
Category
Memory Routines
Prototype
size_t offsetof(struct_type, struct_member);
Description
offsetof is available only as a macro. The argument struct_type is a struct type. struct_member is any element of the struct that
can be accessed through the member selection operators or pointers.
See also sizeof for more information on memory allocation and alignment of structures.
Return Value
offsetof returns the number of bytes from the start of the structure to the start of the named structure member.
Portability
3.1.4.28 stdio.h
The following functions, macros, and classes are provided in stdio.h:
Topics
Name Description
BUFSIZ #define ( see page 1023) Header File
stdio.h
Description
Default buffer size used by setbuf function.
_F_xxxx #defines ( see page 1023) Header File
stdio.h
Description
File status flags of streams
OPEN_MAX #define ( see page 1024) Header File
3 stdio.h
Description
Number of files that can be open simultaneously.
L_ctermid #define ( see page 1024) Header File
stdio.h
Description
The length of a device id string.
1006
3.1 C++ Reference RAD Studio C Runtime Library Reference
1007
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1008
3.1 C++ Reference RAD Studio C Runtime Library Reference
1009
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1010
3.1 C++ Reference RAD Studio C Runtime Library Reference
1011
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1012
3.1 C++ Reference RAD Studio C Runtime Library Reference
1013
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1014
3.1 C++ Reference RAD Studio C Runtime Library Reference
1015
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1016
3.1 C++ Reference RAD Studio C Runtime Library Reference
1017
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1018
3.1 C++ Reference RAD Studio C Runtime Library Reference
1019
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1020
3.1 C++ Reference RAD Studio C Runtime Library Reference
1021
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1022
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdio.h
Description
Description
Name Meaning
_F_RDWR Read and write
1023
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdio.h
Description
Name Meaning
FOPEN_MAX Maximum files per process
SYS_OPEN Maximum files for system
stdio.h
Description
stdio.h
3 Description
stdio.h
1024
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
stdio.h
Description
Name Meaning
_IOFBF The file is fully buffered. When a buffer is empty, the next input operation will attempt to fill the entire
buffer.
On output, the buffer will be completely filled before any data is written to the file.
_IOLBF The file is line buffered. When a buffer is empty, the next input operation will still attempt to fill the
entire buffer.
On output, however, the buffer will be flushed whenever a newline character is written to the file.
_IONBF The file is unbuffered. The buf and size parameters of setbuf are ignored. Each input operation will
read directly from the file, and each output operation will immediately write the data to the file.
stdio.h, share.h
Category
Input/output Routines
Prototype
FILE *_fsopen(const char *filename, const char *mode, int shflag);
FILE *_wfsopen(const wchar_t *filename, const wchar_t *mode, int shflag);
Description
_fsopen opens the file named by filename and associates a stream with it. _fsopen returns a pointer that is used to identify the
stream in subsequent operations.
The mode string used in calls to _fsopen is one of the following values:
3
r Open for reading only.
w Create for writing. If a file by that name already exists, it will be overwritten.
a Append; open for writing at end of file. or create for writing if the file does not exist.
r+ Open an existing file for update (reading and writing).
w+ Create a new file for update (reading and writing). If a file by that name already exists, it will be
overwritten.
1025
C Runtime Library Reference RAD Studio 3.1 C++ Reference
a+ Open for append; open (or create if the file does not exist) for update at the end of the file.
To specify that a given file is being opened or created in text mode append a t to the mode string (rt w+t and so on). Similarly to
specify binary mode append a b to the mode string (wb a+b and so on). _fsopen also allows the t or b to be inserted between the
letter and the + character in the mode string; for example rt+ is equivalent to r+t. If a t or b is not given in the mode string the
mode is governed by the global variable _fmode. If _fmode is set to O_BINARY files are opened in binary mode. If _fmode is set
to O_TEXT they are opened in text mode. These O_... constants are defined in fcntl.h.
When a file is opened for update, both input and output can be done on the resulting stream, however:
Return Value
Example
#include <io.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
int main(void)
{
FILE *f;
int status;
f = _fsopen("TESTFILE.DAT", "r", SH_DENYNO);
if (f == NULL)
{
printf("_fsopen failed\n");
exit(1);
}
status = access("TESTFILE.DAT", 6);
if (status == 0)
printf("read/write access allowed\n");
else
printf("read/write access not allowed\n");
3 fclose(f);
return 0;
}
Portability
1026
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.28.9 _pclose
Header File
stdio.h
Category
Prototype
int _pclose(FILE * stream);
Description
_pclose closes a pipe stream created by a previous call to _popen, and then waits for the associated child command to complete.
Return Value
On success, _pclose returns the termination status of the child command. This is the same value as the termination status
returned by cwait, except that the high and low order bytes of the low word are swapped.
Portability
stdio.h
Category
Input/output Routines
Prototype
FILE *_popen (const char *command, const char *mode);
FILE *_wpopen (const wchar_t *command, const wchar_t *mode);
Description
The _popen function creates a pipe to the command processor. The command processor is executed asynchronously, and is 3
passed the command line in command. The mode string specifies whether the pipe is connected to the command processor’s
standard input or output, and whether the pipe is to be opened in binary or text mode.
1027
C Runtime Library Reference RAD Studio 3.1 C++ Reference
The terminating t or b is optional; if missing, the translation mode is determined by the external variable _fmode.
Use the _pclose function to close the pipe and obtain the return code of the command.
Return Value
On success, _popen returns a FILE pointer that can be used to read the standard output of the command, or to write to the
standard input of the command, depending on the mode string.
Example
/* this program initiates a child process to run the dir command
and pipes the directory listing from the child to the parent.
*/
#include <stdio.h> // popen() pclose() feof() fgets() puts()
#include <string.h> // strlen()
int main( )
{
FILE* handle; // handle to one end of pipe
char message[256]; // buffer for text passed through pipe
int status; // function return value
// open a pipe to receive text from a process running "DIR"
handle = _popen("dir /b", "rt");
if (handle == NULL)
{
perror("_popen error");
}
// read and display input received from the child process
while (fgets(message, sizeof(message), handle))
{
fprintf(stdout, message);
}
// close the pipe and check the return status
status = _pclose(handle);
if (status == -1)
{
perror("_pclose error");
}
return(0);
}
Portability
3
3.1.4.28.11 _snprintf;_snwprintf
Header File
stdio.h
Category
1028
3.1 C++ Reference RAD Studio C Runtime Library Reference
Syntax
int _snprintf(char* buffer, size_t nsize, const char* format, ...);
int _snwprintf(wchar_t* buffer, size_t nsize, const wchar_t* format, ...);
Description
Sends formatted output to a string of a maximum length specified by nsize. _snprintf and _snwprintf are Microsoft compatible
with the _snprintf and _snprintfw functions, respectively.
• < nsize, then all of the characters have been written, including the terminating ‘\0’ character.
• == nsize, then nsize characters are written with no terminating ‘\0’ character.
If nsize is 0, then the string will not be written to (and may be NULL).
If nsize is too small, then return value is -1, and only nsize characters are written, with no terminating ‘\0’ character.
Return Value
Number of bytes output or –1 if nsize is too small.
3.1.4.28.12 _vsnprintf;_vsnwprintf
Header File
stdio.h
Category
Prototype
int _vsnprintf(char* buffer, size_t nsize, const char* format, va_list param);
int _vsnwprintf(wchar_t* buffer, size_t nsize, const wchar_t* format, va_list param);
Description
Sends formatted output to a string of a maximum length specified by nsize. _vsnprintf and _vsnwprintf are Microsoft compatible
with the _vsnprintf and _vsnprintfw functions, respectively.
• < nsize, then all of the characters have been written, including the terminating ‘\0’ character.
• == nsize, then nsize characters are written with no terminating ‘\0’ character.
If nsize is 0, then the string will not be written to (and may be NULL).
If nsize is too small, then return value is -1, and only nsize characters are written, with no terminating ‘\0’ character.
Return Value
Number of bytes output or –1 if nsize is too small. 3
3.1.4.28.13 clearerr
Header File
stdio.h
Category
1029
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Input/output Routines
Prototype
void clearerr(FILE *stream);
Description
clearerr resets the named stream's error and end-of-file indicators to 0. Once the error indicator is set, stream operations
continue to return error status until a call is made to clearerr or rewind. The end-of-file indicator is reset with each input operation.
Return Value
None.
Example
#include <stdio.h>
int main(void)
{
FILE *fp;
char ch;
/* open a file for writing */
fp = fopen("DUMMY.FIL", "w");
/* force an error condition by attempting to read */
ch = fgetc(fp);
printf("%c\n",ch);
if (ferror(fp))
{
/* display an error message */
printf("Error reading from DUMMY.FIL\n");
/* reset the error and EOF indicators */
clearerr(fp);
}
fclose(fp);
return 0;
}
Portability
stdio.h
Description
3.1.4.28.15 fclose
Header File
stdio.h
Category
1030
3.1 C++ Reference RAD Studio C Runtime Library Reference
Input/output Routines
Prototype
int fclose(FILE *stream);
Description
Closes a stream.
fclose closes the named stream. All buffers associated with the stream are flushed before closing. System-allocated buffers are
freed upon closing. Buffers assigned with setbuf or setvbuf are not automatically freed. (But if setvbuf is passed null for the buffer
pointer it will free it upon close.)
Return Value
Portability
3.1.4.28.16 _fcloseall
Header File
stdio.h
Category
Input/output Routines
Prototype
int _fcloseall(void);
Description
stdauxstdstreams
When _fcloseall flushes the associated buffers before closing a stream. The buffers allocated by the system are released.
Return Value
_fcloseall returns the total number of streams it closed. The _fcloseall function returns EOF if any errors were detected.
Example 3
#include <stdio.h>
int main(void)
{
int streams_closed;
/* open two streams */
fopen("DUMMY.ONE", "w");
fopen("DUMMY.TWO", "w");
/* close the open streams */
streams_closed = fcloseall();
1031
C Runtime Library Reference RAD Studio 3.1 C++ Reference
if (streams_closed == EOF)
/* issue an error message */
perror("Error");
else
/* print result of fcloseall() function */
printf("%d streams were closed.\n", streams_closed);
return 0;
}
Portability
stdio.h
Category
Input/output Routines
Prototype
FILE *_fdopen(int handle, char *type);
FILE *_wfdopen(int handle, wchar_t *type);
Description
_fdopen associates a stream with a file handle obtained from creat, dup, dup2, or open.
The type of stream must match the mode of the open handle.
The type string used in a call to _fdopen is one of the following values:
r Open for reading only. _fdopen returns NULL if the file cannot be opened.
w Create for writing. If the file already exists, its contents are overwritten.
a Append; open for writing at end-of-file or create for writing if the file does not exist.
r+ Open an existing file for update (reading and writing). _fdopen returns NULL if the file cannot be
opened.
w+ Create a new file for update. If the file already exists, its contents are overwritten.
a+ Open for append; open (or create if the file does not exist) for update at the end of the file.
To specify that a given file is being opened or created in text mode, append t to the value of the type string (for example, rt or
3 w+t).
Similarly, to specify binary mode, append b to the type string (for example, rb or w+b).
If t or b is not given in the type string, the mode is governed by the global variable _fmode.
1032
3.1 C++ Reference RAD Studio C Runtime Library Reference
When a file is opened for update, both input and output can be done on the resulting stream; however,
3.1.4.28.18 feof
Header File
stdio.h
Category
Input/output Routines
Prototype
int feof(FILE *stream);
3
Description
feof is a macro that tests the given stream for an end-of-file indicator. Once the indicator is set read operations on the file return
the indicator until rewind is called or the file is closed. The end-of-file indicator is reset with each input operation.
Return Value
feof returns nonzero if an end-of-file indicator was detected on the last input operation on the named stream and 0 if end-of-file
1033
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <stdio.h>
int main(void)
{
FILE *stream;
/* open a file for reading */
stream = fopen("DUMMY.FIL", "r");
/* read a character from the file */
fgetc(stream);
/* check for EOF */
if (feof(stream))
printf("We have reached end-of-file\n");
/* close the file */
fclose(stream);
return 0;
}
Portability
3.1.4.28.19 ferror
Header File
stdio.h
Category
Input/output Routines
Prototype
int ferror(FILE *stream);
Description
ferror is a macro that tests the given stream for a read or write error. If the stream's error indicator has been set it remains set
until clearerr or rewind is called or until the stream is closed.
Return Value
Example
#include <stdio.h>
3 int main(void)
{
FILE *stream;
/* open a file for writing */
stream = fopen("DUMMY.FIL", "w");
/* force an error condition by attempting to read */
(void) getc(stream);
if (ferror(stream)) /* test for an error on the stream */
{
/* display an error message */
printf("Error reading from DUMMY.FIL\n");
1034
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.28.20 fflush
Header File
stdio.h
Category
Input/output Routines
Prototype
int fflush(FILE *stream);
Description
Flushes a stream.
If the given stream has buffered output fflush writes the output for stream to the associated file.
The stream remains open after fflush has executed. fflush has no effect on an unbuffered stream.
Return Value
Example
#include <string.h>
#include <stdio.h>
#include <io.h>
void flush(FILE *stream);
int main(void)
{
FILE *stream;
char msg[] = "This is a test";
/* create a file */
stream = fopen("DUMMY.FIL", "w");
/* write some data to the file */
fwrite(msg, strlen(msg), 1, stream);
printf("Press ENTER to flush DUMMY.FIL:");
getchar();
/* flush the data to DUMMY.FIL without closing it */ 3
flush(stream);
printf("\nFile was flushed, Press ENTER to quit:");
getchar();
return 0;
}
void flush(FILE *stream)
{
int duphandle;
/* flush the stream's internal buffer */
1035
C Runtime Library Reference RAD Studio 3.1 C++ Reference
fflush(stream);
/* make a duplicate file handle */
duphandle = dup(fileno(stream));
/* close the duplicate handle to flush the DOS buffer */
close(duphandle);
}
Portability
stdio.h
Category
Input/output Routines
Prototype
int fgetc(FILE *stream);
wint_t fgetwc(FILE *stream);
Description
Return Value
On success fgetc returns the character read after converting it to an int without sign extension. On end-of-file or error it returns
EOF.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *stream;
char string[] = "This is a test";
char ch;
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* write a string into the file */
fwrite(string, strlen(string), 1, stream);
/* seek to the beginning of the file */
3 fseek(stream, 0, SEEK_SET);
do
{
/* read a char from the file */
ch = fgetc(stream);
/* display the character */
putchar(ch);
} while (ch != EOF);
fclose(stream);
return 0;
}
1036
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
stdio.h
Category
Prototype
int _fgetchar(void);
wint_t _fgetwchar(void);
Description
Return Value
On success _fgetchar returns the character read after converting it to an int without sign extension. On end-of-file or error it
returns EOF.
Example
#include <stdio.h>
int main(void)
{
char ch;
/* prompt the user for input */
printf("Enter a character followed by <Enter>: ");
/* read the character from stdin */
ch = fgetchar();
/* display what was read */
printf("The character read is: '%c'\n", ch);
return 0;
}
Portability
3.1.4.28.23 fgetpos
Header File
1037
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdio.h
Category
Input/output Routines
Prototype
int fgetpos(FILE *stream, fpos_t *pos);
Description
fgetpos stores the position of the file pointer associated with the given stream in the location pointed to by pos. The exact value
is unimportant; its value is opaque except as a parameter to subsequent fsetpos calls.
Return Value
On success fgetpos returns 0. On failure it returns a nonzero value and sets the global variable errno to
Example
#include <stdlib.h>
#include <stdio.h>
void showpos(FILE *stream);
int main(void)
{
FILE *stream;
fpos_t filepos;
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* save the file pointer position */
fgetpos(stream, &filepos);
/* write some data to the file */
fprintf(stream, "This is a test");
/* show the current file position */
showpos(stream);
/* set a new file position, display it */
if (fsetpos(stream, &filepos) == 0)
showpos(stream);
else
{
fprintf(stderr, "Error setting file pointer.\n");
exit(1);
}
/* close the file */
fclose(stream);
return 0;
}
void showpos(FILE *stream)
{
3 fpos_t pos;
/* display the current file pointer
position of a stream */
fgetpos(stream, &pos);
printf("File position: %ld\n", pos);
}
Portability
1038
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdio.h
Category
Input/output Routines
Prototype
char *fgets(char *s, int n, FILE *stream);
wchar_t *fgetws(wchar_t *s, int n, FILE *stream); // Unicode version
Description
fgets reads characters from stream into the string s. The function stops reading when it reads either n - 1 characters or a newline
character whichever comes first. fgets retains the newline character at the end of s. A null byte is appended to s to mark the end
of the string.
Return Value
On success fgets returns the string pointed to by s; it returns NULL on end-of-file or error.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *stream;
char string[] = "This is a test";
char msg[20];
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* write a string into the file */
fwrite(string, strlen(string), 1, stream);
/* seek to the start of the file */
fseek(stream, 0, SEEK_SET);
/* read a string from the file */
fgets(msg, strlen(string)+1, stream);
/* display the string */
printf("%s", msg);
fclose(stream);
return 0;
}
3
Portability
1039
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.28.25 _fileno
Header File
stdio.h
Category
Input/output Routines
Prototype
int _fileno(FILE *stream);
Description
_fileno is a macro that returns the file handle for the given stream. If stream has more than one handle _fileno returns the handle
assigned to the stream when it was first opened.
Return Value
Example
#include <stdio.h>
int main(void)
{
FILE *stream;
int handle;
/* create a file */
stream = fopen("DUMMY.FIL", "w");
/* obtain the file handle associated with the stream */
handle = fileno(stream);
/* display the handle number */
printf("handle number: %d\n", handle);
/* close the file */
fclose(stream);
return 0;
}
Portability
3.1.4.28.26 _flushall
Header File
3
stdio.h
Category
Input/output Routines
Prototype
int _flushall(void);
1040
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
_flushall clears all buffers associated with open input streams and writes all buffers associated with open output streams to their
respective files. Any read operation following _flushall reads new data into the buffers from the input files. Streams stay open
after _flushall executes.
Return Value
_flushall returns an integer the number of open input and output streams.
Example
#include <stdio.h>
int main(void)
{
FILE *stream;
/* create a file */
stream = fopen("DUMMY.FIL", "w");
/* flush all open streams */
printf("%d streams were flushed.\n", flushall());
/* close the file */
fclose(stream);
return 0;
}
Portability
stdio.h
Category
Input/output Routines
Prototype
FILE *fopen(const char *filename, const char *mode);
FILE *_wfopen(const wchar_t *filename, const wchar_t *mode);
Description
Opens a stream.
fopen opens the file named by filename and associates a stream with it. fopen returns a pointer to be used to identify the stream
in subsequent operations. 3
The mode string used in calls to fopen is one of the following values:
1041
C Runtime Library Reference RAD Studio 3.1 C++ Reference
w+ Create a new file for update (reading and writing). If a file by that name already exists, it will be
overwritten.
a+ Open for append; open (or create if the file does not exist) for update at the end of the file.
To specify that a given file is being opened or created in text mode append a t to the mode string (rt w+t and so on). Similarly to
specify binary mode append a b to the mode string (wb a+b and so on). fopen also allows the t or b to be inserted between the
letter and the + character in the mode string; for example rt+ is equivalent to r+t.
If a t or b is not given in the mode string the mode is governed by the global variable _fmode. If _fmode is set to O_B/INARY files
are opened in binary mode. If _fmode is set to O_TEXT they are opened in text mode. These O_... constants are defined in
fcntl.h.
When a file is opened for update, both input and output can be done on the resulting stream; however,
stdio.h
Category
Input/output Routines
Prototype
int fprintf(FILE *stream, const char *format[, argument, ...]);
int fwprintf(FILE *stream, const wchar_t *format[, argument, ...]);
Description
fprintf accepts a series of arguments applies to each a format specifier contained in the format string pointed to by format and
outputs the formatted data to a stream. There must be the same number of format specifiers as arguments.
3
Note: For details on format specifiers, see printf Format Specifiers.
Return Value
fprintf returns the number of bytes output. In the event of error it returns EOF.
Example
#include <stdio.h>
int main(void)
1042
3.1 C++ Reference RAD Studio C Runtime Library Reference
{
FILE *stream;
int i = 100;
char c = 'C';
float f = 1.234;
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* write some data to the file */
fprintf(stream, "%d %c %f", i, c, f);
/* close the file */
fclose(stream);
return 0;
}
Portability
stdio.h
Category
Input/output Routines
Prototype
int fputc(int c, FILE *stream);
wint_t fputwc(wint_t c, FILE *stream);
Description
Return Value
Example
#include <stdio.h>
int main(void)
{
char msg[] = "Hello world"; 3
int i = 0;
while (msg[i])
{
fputc(msg[i], stdout);
i++;
}
return 0;
}
Portability
1043
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdio.h
Category
Input/output Routines
Prototype
int _fputchar(int c);
wint_t _fputwchar(wint_t c);
Description
Return Value
Example
#include <stdio.h>
int main(void)
{
char msg[] = "This is a test";
int i = 0;
while (msg[i])
{
fputchar(msg[i]);
i++;
}
return 0;
}
Portability
1044
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdio.h
Category
Input/output Routines
Prototype
int fputs(const char *s, FILE *stream);
int fputws(const wchar_t *s, FILE *stream);
Description
fputs copies the null-terminated string s to the given output stream; it does not append a newline character and the terminating
null character is not copied.
Return Value
Example
#include <stdio.h>
int main(void)
{
/* write a string to standard output */
fputs("Hello world\n", stdout);
return 0;
}
Portability
3.1.4.28.32 fread
Header File
stdio.h
Category
Input/output Routines
Prototype
size_t fread(void *ptr, size_t size, size_t n, FILE *stream); 3
Description
fread reads n items of data each of length size bytes from the given input stream into a block pointed to by ptr.
Return Value
1045
C Runtime Library Reference RAD Studio 3.1 C++ Reference
On success fread returns the number of items (not bytes) actually read.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *stream;
char msg[] = "this is a test";
char buf[20];
if ((stream = fopen("DUMMY.FIL", "w+"))
== NULL)
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
/* write some data to the file */
fwrite(msg, strlen(msg)+1, 1, stream);
/* seek to the beginning of the file */
fseek(stream, SEEK_SET, 0);
/* read the data and display it */
fread(buf, strlen(msg)+1, 1, stream);
printf("%s\n", buf);
fclose(stream);
return 0;
}
Portability
stdio.h
Category
Input/output Routines
Prototype
FILE *freopen(const char *filename, const char *mode, FILE *stream);
FILE *_wfreopen(const wchar_t *filename, const wchar_t *mode, FILE *stream);
Description
The mode string used in calls to fopen is one of the following values:
1046
3.1 C++ Reference RAD Studio C Runtime Library Reference
a Append; open for writing at end-of-file or create for writing if the file does not exist.
r+ Open an existing file for update (reading and writing).
w+ Create a new file for update (reading and writing).
a+ Open for append; open (or create if the file does not exist) for update at the end of the file.
To specify that a given file is being opened or created in text mode append a t to the mode string (rt w+t and so on); similarly to
specify binary mode append a b to the mode string (wb a+b and so on).
If a t or b is not given in the mode string the mode is governed by the global variable _fmode. If _fmode is set to O_BINARY files
are opened in binary mode. If _fmode is set to O_TEXT they are opened in text mode. These O_... constants are defined in
fcntl.h.
When a file is opened for update, both input and output can be done on the resulting stream; however,
stdio.h
3
Category
Input/output Routines
Prototype
int fscanf(FILE *stream, const char *format[, address, ...]);
int fwscanf(FILE *stream, const wchar_t *format[, address, ...]);
1047
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
fscanf scans a series of input fields one character at a time reading from a stream. Then each field is formatted according to a
format specifier passed to fscanf in the format string pointed to by format. Finally fscanf stores the formatted input at an address
passed to it as an argument following format. The number of format specifiers and addresses must be the same as the number
of input fields.
fscanf can stop scanning a particular field before it reaches the normal end-of-field character (whitespace) or it can terminate
entirely for a number of reasons. See scanf for a discussion of possible causes.
Return Value
fscanf returns the number of input fields successfully scanned, converted and stored. The return value does not include scanned
fields that were not stored.
If fscanf attempts to read at end-of-file, the return value is EOF. If no fields were stored, the return value is 0.
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int i;
printf("Input an integer: ");
/* read an integer from the
standard input stream */
if (fscanf(stdin, "%d", &i))
printf("The integer read was: %i\n", i);
else
{
fprintf(stderr, "Error reading an integer from stdin.\n");
exit(1);
}
return 0;
}
Portability
3.1.4.28.35 fseek
Header File
stdio.h
3 Category
Input/output Routines
Prototype
int fseek(FILE *stream, long offset, int whence);
Description
1048
3.1 C++ Reference RAD Studio C Runtime Library Reference
fseek sets the file pointer associated with stream to a new position that is offset bytes from the file location given by whence. For
text mode streams offset should be 0 or a value returned by ftell.
whence must be one of the values 0. 1, or 2 which represent three symbolic constants (defined in stdio.h) as follows:
fseek discards any character pushed back using ungetc. fseek is used with stream I/O; for file handle I/O use lseek.
After fseek the next operation on an update file can be either input or output.
Return Value
fseek might return a 0 indicating that the pointer has been moved successfully when in fact it has not been. This is because
DOS, which actually resets the pointer, does not verify the setting. fseek returns an error code only on an unopened file or device.
In the event of an error return the global variable errno is set to one of the following values:
Example
#include <stdio.h>
long filesize(FILE *stream);
int main(void)
{
FILE *stream;
stream = fopen("MYFILE.TXT", "w+");
fprintf(stream, "This is a test");
printf("Filesize of MYFILE.TXT is %ld bytes\n", filesize(stream));
fclose(stream);
return 0;
}
long filesize(FILE *stream)
{
long curpos, length;
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
fseek(stream, curpos, SEEK_SET);
return length;
}
Portability
3.1.4.28.36 fsetpos 3
Header File
stdio.h
Category
Input/output Routines
Prototype
1049
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
fsetpos sets the file pointer associated with stream to a new position. The new position is the value obtained by a previous call to
fgetpos on that stream. It also clears the end-of-file indicator on the file that stream points to and undoes any effects of ungetc on
that file. After a call to fsetpos the next operation on the file can be input or output.
Return Value
On failure it returns a nonzero value and also sets the global variable errno to a nonzero value.
Portability
3.1.4.28.37 ftell
Header File
stdio.h
Category
Input/output Routines
Prototype
long int ftell(FILE *stream);
Description
ftell returns the current file pointer for stream. The offset is measured in bytes from the beginning of the file (if the file is binary).
The value returned by ftell can be used in a subsequent call to fseek.
Return Value
ftell returns the current file pointer position on success. It returns -1L on error and sets the global variable errno to a positive
value.
In the event of an error return the global variable errno is set to one of the following values:
1050
3.1 C++ Reference RAD Studio C Runtime Library Reference
return 0;
}
Portability
3.1.4.28.38 fwrite
Header File
stdio.h
Category
Input/output Routines
Prototype
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
Description
Writes to a stream.
fwrite appends n items of data each of length size bytes to the given output file. The data written begins at ptr. The total number
of bytes written is (n x size). ptr in the declarations is a pointer to any object.
Return Value
On successful completion fwrite returns the number of items (not bytes) actually written.
Example
#include <stdio.h>
struct mystruct
{
int i;
char ch;
};
int main(void)
{
FILE *stream;
struct mystruct s;
if ((stream = fopen("TEST.$$$", "wb")) == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
s.i = 0;
s.ch = 'A'; 3
fwrite(&s, sizeof(s), 1, stream); /* write struct s to file */
fclose(stream); /* close file */
return 0;
}
Portability
1051
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdio.h
Category
Input/output Routines
Prototype
int getc(FILE *stream);
wint_t getwc(FILE *stream);
Description
getc returns the next character on the given input stream and increments the stream's file pointer to point to the next character.
Return Value
On success, getc returns the character read, after converting it to an int without sign extension.
Example
#include <stdio.h>
int main(void)
{
char ch;
printf("Input a character:");
/* read a character from the
standard input stream */
ch = getc(stdin);
printf("The character input was: '%c'\n", ch);
return 0;
}
Portability
stdio.h
Category
Prototype
1052
3.1 C++ Reference RAD Studio C Runtime Library Reference
int getchar(void);
wint_t getwchar(void);
Description
getchar is a macro that returns the next character on the named input stream stdin. It is defined to be getc(stdin).
Return Value
On success, getchar returns the character read, after converting it to an int without sign extension.
Example
#include <stdio.h>
int main(void)
{
int c;
/*
Note that getchar reads from stdin and is line buffered; this means it will not return until
you press ENTER.
*/
while ((c = getchar()) != '\n')
printf("%c", c);
return 0;
}
Portability
stdio.h
Category
Prototype
char *gets(char *s);
wchar_t *_getws(wchar_t *s); // Unicode version 3
Description
gets collects a string of characters terminated by a new line from the standard input stream stdin and puts it into s. The new line
is replaced by a null character (\0) in s.
gets allows input strings to contain certain whitespace characters (spaces, tabs). gets returns when it encounters a new line;
everything up to the new line is copied into s.
1053
C Runtime Library Reference RAD Studio 3.1 C++ Reference
The gets function is not length-terminated. If the input string is sufficiently large, data can be overwritten and corrupted. The fgets
function provides better control of input strings.
Return Value
Example
#include <stdio.h>
int main(void)
{
char string[80];
printf("Input a string:");
gets(string);
printf("The string input was: %s\n", string);
return 0;
}
Portability
3.1.4.28.42 _getw
Header File
stdio.h
Category
Input/output Routines
Prototype
int _getw(FILE *stream);
Description
_getw returns the next integer in the named input stream. It assumes no special alignment in the file.
_getw should not be used when the stream is opened in text mode.
Return Value
3 _getw returns the next integer on the input stream.
Note: Because EOF is a legitimate value for _getw to return, feof or ferror should be used to detect end-of-file or error.
Example
#include <stdio.h>
#include <stdlib.h>
#define FNAME "test.$$$"
1054
3.1 C++ Reference RAD Studio C Runtime Library Reference
int main(void)
{
FILE *fp;
int word;
/* place the word in a file */
fp = fopen(FNAME, "wb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
word = 94;
putw(word,fp);
if (ferror(fp))
printf("Error writing to file\n");
else
printf("Successful write\n");
fclose(fp);
/* reopen the file */
fp = fopen(FNAME, "rb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
/* extract the word */
word = getw(fp);
if (ferror(fp))
printf("Error reading file\n");
else
printf("Successful read: word = %d\n", word);
/* clean up */
fclose(fp);
unlink(FNAME);
return 0;
}
Portability
stdio.h
Category
Prototype
3
int printf(const char *format[, argument, ...]);
int wprintf(const wchar_t *format[, argument, ...]);
Description
1055
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1056
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
stdio.h
Category
Input/output Routines
Prototype
int putc(int c, FILE *stream);
wint_t putwc(wint_t c, FILE *stream);
Description
putc is a macro that outputs the character c to the stream given by stream.
Return Value
Example
#include <stdio.h>
int main(void)
{
char msg[] = "Hello world\n";
int i = 0;
while (msg[i])
putc(msg[i++], stdout);
return 0;
}
Portability
stdio.h
Category
1057
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
int putchar(int c);
wint_t putwchar(wint_t c);
Description
Return Value
Example
#include <stdio.h>
/* define some box-drawing characters */
#define LEFT_TOP 0xDA
#define RIGHT_TOP 0xBF
#define HORIZ 0xC4
#define VERT 0xB3
#define LEFT_BOT 0xC0
#define RIGHT_BOT 0xD9
int main(void)
{
char i, j;
/* draw the top of the box */
putchar(LEFT_TOP);
for (i=0; i<10; i++)
putchar(HORIZ);
putchar(RIGHT_TOP);
putchar('\n');
/* draw the middle */
for (i=0; i<4; i++)
{
putchar(VERT);
for (j=0; j<10; j++)
putchar(' ');
putchar(VERT);
putchar('\n');
}
/* draw the bottom */
putchar(LEFT_BOT);
for (i=0; i<10; i++)
putchar(HORIZ);
putchar(RIGHT_BOT);
putchar('\n');
return 0;
}
Portability
3 POSIX Win32 ANSI C ANSI C++
putchar + + + +
putwchar + + +
1058
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdio.h
Category
Prototype
int puts(const char *s);
int _putws(const wchar_t *s);
Description
puts copies the null-terminated string s to the standard output stream stdout and appends a newline character.
Return Value
On successful completion, puts returns a nonnegative value. Otherwise, it returns a value of EOF.
Example
#include <stdio.h>
int main(void)
{
char string[] = "This is an example output string\n";
puts(string);
return 0;
}
Portability
3.1.4.28.47 _putw
Header File
stdio.h
Category
3
Input/output Routines
Prototype
int _putw(int w, FILE *stream);
Description
1059
C Runtime Library Reference RAD Studio 3.1 C++ Reference
_putw outputs the integer w to the given stream. _putw neither expects nor causes special alignment in the file.
Return Value
On success, _putw returns the integer w. On error, _putw returns EOF. Because EOF is a legitimate integer, use ferror to detect
errors with _putw.
Example
#include <stdio.h>
#include <stdlib.h>
#define FNAME "test.$$$"
int main(void)
{
FILE *fp;
int word;
/* place the word in a file */
fp = fopen(FNAME, "wb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
word = 94;
putw(word,fp);
if (ferror(fp))
printf("Error writing to file\n");
else
printf("Successful write\n");
fclose(fp);
/* reopen the file */
fp = fopen(FNAME, "rb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
/* extract the word */
word = getw(fp);
if (ferror(fp))
printf("Error reading file\n");
else
printf("Successful read: word = %d\n", word);
/* clean up */
fclose(fp);
unlink(FNAME);
return 0;
}
Portability
3
3.1.4.28.48 remove, _wremove
Header File
stdio.h
Category
Input/output Routines
1060
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
int remove(const char *filename);
int _wremove(const wchar_t *filename);
Description
Removes a file.
remove deletes the file specified by filename. It is a macro that simply translates its call to a call to unlink. If your file is open, be
sure to close it before removing it.
Return Value
On successful completion, remove returns 0. On error, it returns -1, and the global variable errno is set to one of the following
values:
Example
#include <stdio.h>
int main(void)
{
char file[80];
/* prompt for file name to delete */
printf("File to delete: ");
gets(file);
/* delete the file */
if (remove(file) == 0)
printf("Removed %s.\n",file);
else
perror("remove");
return 0;
}
Portability
stdio.h
3
Category
Input/output Routines
Prototype
int rename(const char *oldname, const char *newname);
int _wrename(const wchar_t *oldname, const wchar_t *newname);
1061
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
Renames a file.
rename changes the name of a file from oldname to newname. If a drive specifier is given in newname, the specifier must be the
same as that given in oldname.
Directories in oldname and newname need not be the same, so rename can be used to move a file from one directory to
another. Wildcards are not allowed.
This function will fail (EEXIST) if either file is currently open in any process.
Return Value
On error (if the file cannot be renamed), it returns -1 and the global variable errno is set to one of the following values:
Example
#include <stdio.h>
int main(void)
{
char oldname[80], newname[80];
/* prompt for file to rename and new name */
printf("File to rename: ");
gets(oldname);
printf("New name: ");
gets(newname);
/* Rename the file */
if (rename(oldname, newname) == 0)
printf("Renamed %s to %s.\n", oldname, newname);
else
perror("rename");
return 0;
}
Portability
3.1.4.28.50 rewind
Header File
3
stdio.h
Category
Input/output Routines
Prototype
void rewind(FILE *stream);
1062
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
rewind(stream) is equivalent to fseek(stream, 0L, SEEK_SET), except that rewind clears the end-of-file and error indicators,
while fseek clears the end-of-file indicator only.
After rewind, the next operation on an update file can be either input or output.
Return Value
None.
Example
#include <stdio.h>
#include <dir.h>
int main(void)
{
FILE *fp;
char *fname = "TXXXXXX", *newname, first;
newname = mktemp(fname);
fp = fopen(newname,"w+");
fprintf(fp,"abcdefghijklmnopqrstuvwxyz");
rewind(fp);
fscanf(fp,"%c",&first);
printf("The first character is: %c\n",first);
fclose(fp);
remove(newname);
return 0;
}
Portability
3.1.4.28.51 _rmtmp
Header File
stdio.h
Category
Input/output Routines
Prototype
int _rmtmp(void);
Description
Return Value
_rmtmp returns the total number of temporary files it closed and deleted.
Example
1063
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <stdio.h>
#include <process.h>
void main()
{
FILE *stream;
int i;
stdio.h
Category
Prototype
int scanf(const char *format[, address, ...]);
int wscanf(const wchar_t *format[, address, ...]);
Description
1064
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
On success, scanf returns the number of input fields successfully scanned, converted, and stored. The return value does not
include scanned fields that were not stored.
On error:
• if no fields were stored, scanf returns 0.
• if scanf attempts to read at end-of-file or at end-of-string, it returns EOF.
More About scanf
Example
#include <stdio.h>
int main(void)
{
char label[20];
char name[20];
int entries = 0;
int loop, age;
double salary;
struct Entry_struct
{
char name[20];
int age;
float salary;
} entry[20];
/* Input a label as a string of characters restricting to 20 characters */
printf("\n\nPlease enter a label for the chart: ");
scanf("%20s", label);
fflush(stdin); /* flush the input stream in case of bad input */
/* Input number of entries as an integer */
printf("How many entries will there be? (less than 20) ");
scanf("%d", &entries);
fflush(stdin); /* flush the input stream in case of bad input */
/* input a name restricting input to only letters upper or lower case */
for (loop=0;loop<entries;++loop)
{
printf("Entry %d\n", loop);
printf(" Name : ");
scanf("%[A-Za-z]", entry[loop].name);
fflush(stdin); /* flush the input stream in case of bad input */
/* input an age as an integer */
printf(" Age : ");
scanf("%d", &entry[loop].age);
fflush(stdin); /* flush the input stream in case of bad input */
/* input a salary as a float */
printf(" Salary : ");
scanf("%f", &entry[loop].salary);
fflush(stdin); /* flush the input stream in case of bad input */
}
/* Input a name, age and salary as a string, integer, and double */
printf("\nPlease enter your name, age and salary\n");
scanf("%20s %d %lf", name, &age, &salary);
/* Print out the data that was input */
printf("\n\nTable %s\n",label);
printf("Compiled by %s age %d $%15.2lf\n", name, age, salary); 3
printf("-----------------------------------------------------\n");
for (loop=0;loop<entries;++loop)
printf("%4d | %-20s | %5d | %15.2lf\n",
loop + 1,
entry[loop].name,
entry[loop].age,
entry[loop].salary);
printf("-----------------------------------------------------\n");
return 0;
1065
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.28.53 setbuf
Header File
stdio.h
Category
Input/output Routines
Prototype
void setbuf(FILE *stream, char *buf);
Description
setbuf causes the buffer buf to be used for I/O buffering instead of an automatically allocated buffer. It is used after stream has
been opened.
If buf is null, I/O will be unbuffered; otherwise, it will be fully buffered. The buffer must be BUFSIZ bytes long (specified in stdio.h).
stdin and stdout are unbuffered if they are not redirected; otherwise, they are fully buffered. setbuf can be used to change the
buffering style used.
Unbuffered means that characters written to a stream are immediately output to the file or device, while buffered means that the
characters are accumulated and written as a block.
setbuf produces unpredictable results unless it is called immediately after opening stream or after a call to fseek. Calling setbuf
after stream has been unbuffered is legal and will not cause problems.
A common cause for error is to allocate the buffer as an automatic (local) variable and then fail to close the file before returning
from the function where the buffer was declared.
Return Value
None.
Example
#include <stdio.h>
/* BUFSIZ is defined in stdio.h */
char outbuf[BUFSIZ];
int main(void)
{
/* attach a buffer to the standard output stream */
setbuf(stdout, outbuf);
/* put some characters into the buffer */
puts("This is a test of buffered output.\n\n");
puts("This output will go into outbuf\n");
puts("and won't appear until the buffer\n");
puts("fills up or we flush the stream.\n");
3 /* flush the output buffer */
fflush(stdout);
return 0;
}
Portability
1066
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.28.54 setvbuf
Header File
stdio.h
Category
Input/output Routines
Prototype
int setvbuf(FILE *stream, char *buf, int type, size_t size);
Description
setvbuf causes the buffer buf to be used for I/O buffering instead of an automatically allocated buffer. It is used after the given
stream is opened.
If buf is null, a buffer will be allocated using malloc; the buffer will use size as the amount allocated. The buffer will be
automatically freed on close. The size parameter specifies the buffer size and must be greater than zero.
stdin and stdout are unbuffered if they are not redirected; otherwise, they are fully buffered. Unbuffered means that characters
written to a stream are immediately output to the file or device, while buffered means that the characters are accumulated and
written as a block.
_IOFBF fully buffered file. When a buffer is empty, the next input operation will attempt to fill the entire buffer.
On output, the buffer will be completely filled before any data is written to the file.
_IOLBF line buffered file. When a buffer is empty, the next input operation will still attempt to fill the entire
buffer. On output, however, the buffer will be flushed whenever a newline character is written to the
file.
_IONBF unbuffered file. The buf and size parameters are ignored. Each input operation will read directly from
the file, and each output operation will immediately write the data to the file.
A common cause for error is to allocate the buffer as an automatic (local) variable and then fail to close the file before returning
from the function where the buffer was declared.
Return Value
On error (if an invalid value is given for type or size, or if there is not enough space to allocate a buffer), it returns nonzero.
Example 3
#include <stdio.h>
int main(void)
{
FILE *input, *output;
char bufr[512];
input = fopen("file.in", "r+b");
output = fopen("file.out", "w");
/* set up input stream for minimal disk access,
using our own character buffer */
1067
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.28.55 snprintf;snwprintf
Header File
stdio.h
Category
Prototype
int snprintf(char* buffer, size_t nsize, const char* fmt, ...);
int snwprintf(wchar_t* buffer, size_t nsize, const wchar_t* fmt, ...);
Description
• < nsize, then all of the characters have been written, including the terminating ‘\0’ character.
• == nsize, then nsize characters are written, with no terminating ‘\0’ character.
> nsize, then only nsize characters are written, with no terminating ‘\0’ character.
If nsize is 0, then the string will not be written to (and may be NULL).
Return Value
Number of bytes output, or, if nsize is 0, the number of bytes needed, not including the terminating ‘\0’ character.
3
3.1.4.28.56 sprintf, swprintf
Header File
stdio.h
Category
1068
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
int sprintf(char *buffer, const char *format[, argument, ...]);
int swprintf(wchar_t *buffer, const wchar_t *format[, argument, ...]);
Description
sprintf accepts a series of arguments, applies to each a format specifier contained in the format string pointed to by format, and
outputs the formatted data to a string.
sprintf applies the first format specifier to the first argument, the second to the second, and so on. There must be the same
number of format specifiers as arguments.
Return Value
On success, sprintf returns the number of bytes output. The return value does not include the terminating null byte in the count.
Example
#include <stdio.h>
#include <math.h>
int main(void)
{
char buffer[80];
sprintf(buffer, "An approximation of Pi is %f\n", M_PI);
puts(buffer);
return 0;
}
Portability
stdio.h
Category
Description
1069
C Runtime Library Reference RAD Studio 3.1 C++ Reference
sscanf scans a series of input fields, one character at a time, reading from a string. Then each field is formatted according to a
format specifier passed to sscanf in the format string pointed to by format. Finally, sscanf stores the formatted input at an
address passed to it as an argument following format. There must be the same number of format specifiers and addresses as
there are input fields.
sscanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace) character, or it might
terminate entirely, for a number of reasons. See scanf for a discussion of possible causes.
Return Value
On success, sscanf returns the number of input fields successfully scanned, converted, and stored; the return value does not
include scanned fields that were not stored.
Example
#include <stdio.h>
#include <stdlib.h>
char *names[4] = {"Peter", "Mike", "Shea", "Jerry"};
#define NUMITEMS 4
int main(void)
{
int loop;
char temp[4][80];
char name[20];
int age;
long salary;
/* create name, age and salary data */
for (loop=0; loop < NUMITEMS; ++loop)
sprintf(temp[loop], "%s %d %ld", names[loop], random(10) + 20, random(5000) + 27500L);
/* print title bar */
printf("%4s | %-20s | %5s | %15s\n", "#", "Name", "Age", "Salary");
printf(" --------------------------------------------------\n");
/* input a name, age and salary data */
for (loop=0; loop < NUMITEMS; ++loop)
{
sscanf(temp[loop],"%s %d %ld", &name, &age, &salary);
printf("%4d | %-20s | %5d | %15ld\n", loop + 1, name, age, salary);
}
return 0;
}
Portability
3
3.1.4.28.58 stderr, stdin, stdout
Header File
stdio.h
Description
1070
3.1 C++ Reference RAD Studio C Runtime Library Reference
Name Meaning
stdin Standard input device
stdout Standard output device
stderr Standard error output device
stdio.h
Category
Input/output Routines
Prototype
char *_tempnam(char *dir, char *prefix)
wchar_t *_wtempnam(wchar_t *dir, wchar_t *prefix)
Description
The _tempnam function creates a unique file name in arbitrary directories. The unique file is not actually created; _tempnam only
verifies that it does not currently exist. It attempts to use the following directories, in the order shown, when creating the file name:
1071
C Runtime Library Reference RAD Studio 3.1 C++ Reference
else {
printf("Creating %s\n",name);
if ((stream = fopen(name,"wb")) == NULL)
perror("Could not open temporary file\n");
else
fclose(stream);
}
free(name);
}
printf("Warning: temp files not deleted.\n");
}
Portability
3.1.4.28.60 tmpfile
Header File
stdio.h
Category
Input/output Routines
Prototype
FILE *tmpfile(void);
Description
tmpfile creates a temporary binary file and opens it for update (w + b). If you do not change the directory after creating the
temporary file, the file is automatically removed when it’s closed or when your program terminates.
Return Value
tmpfile returns a pointer to the stream of the temporary file created. If the file can’t be created, tmpfile returns NULL.
Example
#include <stdio.h>
#include <process.h>
int main(void)
{
FILE *tempfp;
tempfp = tmpfile();
if (tempfp)
printf("Temporary file created\n");
3 else
{
printf("Unable to create temporary file\n");
exit(1);
}
return 0;
}
Portability
1072
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdio.h
Category
Input/output Routines
Prototype
char *tmpnam(char *s);
wchar_t *_wtmpnam(wchar_t *s);
Description
tmpnam creates a unique file name, which can safely be used as the name of a temporary file. tmpnam generates a different
string each time you call it, up to TMP_MAX times. TMP_MAX is defined in stdio.h as 65,535.
The parameter to tmpnam, s, is either null or a pointer to an array of at least L_tmpnam characters. L_tmpnam is defined in
stdio.h. If s is NULL, tmpnam leaves the generated temporary file name in an internal static object and returns a pointer to that
object. If s is not NULL, tmpnam overwrites the internal static object and places its result in the pointed-to array, which must be
at least L_tmpnam characters long, and returns s.
If you do create such a temporary file with tmpnam, it is your responsibility to delete the file name (for example, with a call to
remove). It is not deleted automatically. (tmpfile does delete the file name.)
Return Value
If s is null, tmpnam returns a pointer to an internal static object. Otherwise, tmpnam returns s.
Example
#include <stdio.h>
int main(void)
{
char name[13];
tmpnam(name);
printf("Temporary name: %s\n", name);
return 0;
}
Portability
1073
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdio.h
Category
Input/output Routines
Prototype
int ungetc(int c, FILE *stream);
wint_t ungetwc(wint_t c, FILE *stream);
Description
ungetc pushes the character c back onto the named input stream, which must be open for reading. This character will be
returned on the next call to getc or fread for that stream. One character can be pushed back in all situations. A second call to
ungetc without a call to getc will force the previous character to be forgotten. A call to fflush, fseek, fsetpos, or rewind erases all
memory of any pushed-back characters.
Return Value
Example
#include <stdio.h>
#include <ctype.h>
int main( void )
{
int i=0;
char ch;
puts("Input an integer followed by a char:");
/* read chars until non digit or EOF */
while((ch = getchar()) != EOF && isdigit(ch))
i = 10 * i + ch - 48; /* convert ASCII into int value */
/* if non digit char was read, push it back into input buffer */
if (ch != EOF)
ungetc(ch, stdin);
printf("i = %d, next char in buffer = %c\n", i, getchar());
return 0;
}
Portability
3
3.1.4.28.63 vfprintf, vfwprintf
Header File
stdio.h
Category
Input/output Routines
1074
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
int vfprintf(FILE *stream, const char *format, va_list arglist);
int vfwprintf(FILE *stream, const wchar_t *format, va_list arglist);
Description
The v...printf functions are known as alternate entry points for the ...printf functions. They behave exactly like their ...printf
counterparts, but they accept a pointer to a list of arguments instead of an argument list.
vfprintf accepts a pointer to a series of arguments, applies to each argument a format specifier contained in the format string
pointed to by format, and outputs the formatted data to a stream. There must be the same number of format specifiers as
arguments.
Return Value
Example
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
FILE *fp;
int vfpf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vfprintf(fp, fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
int inumber = 30;
float fnumber = 90.0;
char string[4] = "abc";
fp = tmpfile();
if (fp == NULL)
{
perror("tmpfile() call");
exit(1);
}
vfpf("%d %f %s", inumber, fnumber, string);
rewind(fp);
fscanf(fp,"%d %f %s", &inumber, &fnumber, string);
printf("%d %f %s\n", inumber, fnumber, string);
fclose(fp);
return 0; 3
}
Portability
1075
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.28.64 vfscanf
Header File
stdio.h
Category
Input/output Routines
Prototype
int vfscanf(FILE *stream, const char *format,va_list arglist);
Description
The v...scanf functions are known as alternate entry points for the ...scanf functions. They behave exactly like their ...scanf
counterparts but they accept a pointer to a list of arguments instead of an argument list.
vfscanf scans a series of input fields one character at a time reading from a stream. Then each field is formatted according to a
format specifier passed to vfscanf in the format string pointed to by format. Finally vfscanf stores the formatted input at an
address passed to it as an argument following format. There must be the same number of format specifiers and addresses as
there are input fields. vfscanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace)
character or it might terminate entirely for a number of reasons. See scanf for a discussion of possible causes.
Return Value
vfscanf returns the number of input fields successfully scanned converted and stored; the return value does not include scanned
fields that were not stored. If no fields were stored the return value is 0.
Example
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
FILE *fp;
int vfsf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vfscanf(fp, fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
3 int inumber = 30;
float fnumber = 90.0;
char string[4] = "abc";
fp = tmpfile();
if (fp == NULL)
{
perror("tmpfile() call");
exit(1);
}
fprintf(fp,"%d %f %s\n",inumber,fnumber,string);
rewind(fp);
1076
3.1 C++ Reference RAD Studio C Runtime Library Reference
vfsf("%d %f %s",&inumber,&fnumber,string);
printf("%d %f %s\n",inumber,fnumber,string);
fclose(fp);
return 0;
}
Portability
stdio.h
Category
Prototype
int vprintf(const char *format, va_list arglist);
int vwprintf(const wchar_t * format, va_list arglist);
Description
The v...printf functions are known as alternate entry points for the ...printf functions. They behave exactly like their ...printf
counterparts, but they accept a pointer to a list of arguments instead of an argument list.
vprintf accepts a pointer to a series of arguments, applies to each a format specifier contained in the format string pointed to by
format, and outputs the formatted data to stdout. There must be the same number of format specifiers as arguments.
Return Value
vprint returns the number of bytes output. In the event of error, vprint returns EOF.
Example
#include <stdio.h>
#include <stdarg.h>
int vpf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, fmt); 3
cnt = vprintf(fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
int inumber = 30;
float fnumber = 90.0;
char *string = "abc";
vpf("%d %f %s\n",inumber,fnumber,string);
1077
C Runtime Library Reference RAD Studio 3.1 C++ Reference
return 0;
}
Portability
3.1.4.28.66 vscanf
Header File
stdio.h
Category
Prototype
int vscanf(const char *format, va_list arglist);
Description
The v...scanf functions are known as alternate entry points for the ...scanf functions. They behave exactly like their ...scanf
counterparts, but they accept a pointer to a list of arguments instead of an argument list.
vscanf scans a series of input fields, one character at a time, reading from stdin. Then each field is formatted according to a
format specifier passed to vscanf in the format string pointed to by format. Finally, vscanf stores the formatted input at an
address passed to it as an argument following format. There must be the same number of format specifiers and addresses as
there are input fields.
vscanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace) character, or it might
terminate entirely, for a number of reasons. See scanf for a discussion of possible causes.
Return Value
vscanf returns the number of input fields successfully scanned, converted, and stored; the return value does not include scanned
fields that were not stored. If no fields were stored, the return value is 0.
Example
3 #include <stdio.h>
#include <stdarg.h>
int vscnf(char *fmt, ...)
{
va_list argptr;
int cnt;
printf("Enter an integer, a float, and a string (e.g. i,f,s,)\n");
va_start(argptr, fmt);
cnt = vscanf(fmt, argptr);
va_end(argptr);
return(cnt);
1078
3.1 C++ Reference RAD Studio C Runtime Library Reference
}
int main(void)
{
int inumber;
float fnumber;
char string[80];
vscnf("%d, %f, %s", &inumber, &fnumber, string);
printf("%d %f %s\n", inumber, fnumber, string);
return 0;
}
Portability
3.1.4.28.67 vsnprintf;vsnwprintf
Header File
stdio.h
Category
Prototype
int vsnprintf(char* buffer, size_t nsize, const char* format, va_list param);
int vsnwprintf(wchar_t* buffer, size_t nsize, const wchar_t* format, va_list param);
Description
• < nsize, then all of the characters have been written, including the terminating ‘\0’ character.
• == nsize, then nsize characters are written, with no terminating ‘\0’ character.
> nsize, then only nsize characters are written, with no terminating ‘\0’ character.
If nsize is 0, then the string will not be written to (and may be NULL).
Return Value
Number of bytes output, or, if nsize is 0, the number of bytes needed, not including the terminating ‘\0’ character.
stdio.h
3
Category
Prototype
int vsprintf(char *buffer, const char *format, va_list arglist);
int vswprintf(wchar_t *buffer, const wchar_t *format, va_list arglist);
1079
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
The v...printf functions are known as alternate entry points for the ...printf functions. They behave exactly like their ...printf
counterparts, but they accept a pointer to a list of arguments instead of an argument list.
vsprintf accepts a pointer to a series of arguments, applies to each a format specifier contained in the format string pointed to by
format, and outputs the formatted data to a string. There must be the same number of format specifiers as arguments.
Return Value
vsprintf returns the number of bytes output. In the event of error, vsprintf returns EOF.
Example
#include <stdio.h>
#include <conio.h>
#include <stdarg.h>
char buffer[80];
int vspf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsprintf(buffer, fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
int inumber = 30;
float fnumber = 90.0;
char string[4] = "abc";
vspf("%d %f %s", inumber, fnumber, string);
printf("%s\n", buffer);
return 0;
}
Portability
3.1.4.29 stdlib.h
The following functions, macros, and classes are provided in stdlib.h:
Topics
3 Name Description
EXIT_xxxx #defines ( see page 1095) Header File
stdlib.h
Description
Constants defining exit conditions for calls to the exit function.
RAND_MAX #define ( see page 1095) Header File
stdlib.h
Syntax
Description
Maximum value returned by rand function.
1080
3.1 C++ Reference RAD Studio C Runtime Library Reference
1081
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1082
3.1 C++ Reference RAD Studio C Runtime Library Reference
1083
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1084
3.1 C++ Reference RAD Studio C Runtime Library Reference
1085
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1086
3.1 C++ Reference RAD Studio C Runtime Library Reference
1087
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1088
3.1 C++ Reference RAD Studio C Runtime Library Reference
1089
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1090
3.1 C++ Reference RAD Studio C Runtime Library Reference
1091
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1092
3.1 C++ Reference RAD Studio C Runtime Library Reference
1093
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1094
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdlib.h
Description
Name Meaning
EXIT_SUCCESS Normal program termination
EXIT_FAILURE Abnormal program termination
stdlib.h
Syntax
Description
3.1.4.29.3 _argc
Header File
stdlib.h
Syntax
extern int _argc;
Description
_argc has the same value as argc (passed to main) when the program starts. This variable holds the number of arguments
passed to the program. The value includes the name of the program itself, so _argc and argc are always at least 1.
stdlib.h
Syntax 3
extern char **_argv;
extern wchar_t ** _wargv
Description
_argv points to an array containing the original command-line arguments (the elements of argv[]) passed to main when the
program starts.
1095
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Portability
stdlib.h
Category
Prototype
__int64 _atoi64(const char *s);
__int64 _wtoi64(const wchar_t *s);
Description
In this function, the first unrecognized character ends the conversion. There are no provisions for overflow in atoi (results are
undefined). There is no defined method to return an error indication to the caller. The result is undefined if the input string is
invalid.
Return Value
Returns the converted value of the input string. If the string cannot be converted to a __int64, the return value is 0.
Portability
3
3.1.4.29.6 _crotl, _crotr
Header File
stdlib.h
Category
Math Routines
1096
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
unsigned char _crotl(unsigned char val, int count);
unsigned char _crotr(unsigned char val, int count);
Description
_crotl rotates the given val to the left count bits. _crotr rotates the given val to the right count bits.
The argument val is an unsigned char, or its equivalent in decimal or hexadecimal form.
Return Value
3.1.4.29.7 _exit
Header File
stdlib.h
Category
Prototype
void _exit(int status);
Description
Terminates program.
_exit terminates execution without closing any files, flushing any output, or calling any exit functions.
The calling process uses status as the exit status of the process. Typically a value of 0 is used to indicate a normal exit, and a
nonzero value indicates some error.
Return Value
None.
Example
3
#include <stdlib.h>
#include <stdio.h>
void done(void);
int main(void)
{
atexit(done);
_exit(0);
return 0;
}
void done()
1097
C Runtime Library Reference RAD Studio 3.1 C++ Reference
{
printf("hello\n");
}
Portability
stdlib.h
Category
Prototype
char * _fullpath(char *buffer, const char *path, int buflen);
wchar_t * _wfullpath(wchar_t *buffer, const wchar_t *path, int buflen);
Description
_fullpath converts the relative path name in path to an absolute path name that is stored in the array of characters pointed to by
buffer. The maximum number of characters that can be stored at buffer is buflen. The function returns NULL if the buffer isn't big
enough to store the absolute path name or if the path contains an invalid drive letter.
If buffer is NULL, _fullpath allocates a buffer of up to _MAX_PATH characters. This buffer should be freed using free when it is
no longer needed. _MAX_PATH is defined in stdlib.h.
Return Value
If successful the _fullpath function returns a pointer to the buffer containing the absolute path name.
Example
#include <stdio.h>
#include <stdlib.h>
char buf[_MAX_PATH];
void main(int argc, char *argv[])
{
for ( ; argc; argv++, argc--)
{
if (_fullpath(buf, argv[0], _MAX_PATH) == NULL)
printf("Unable to obtain full path of %s\n",argv[0]);
3 else
printf("Full path of %s is %s\n",argv[0],buf);
}
}
Portability
1098
3.1 C++ Reference RAD Studio C Runtime Library Reference
_wfullpath NT only
3.1.4.29.9 _lrand
Header File
stdlib.h
Category
Math Routines
Prototype
long _lrand(void);
Description
_lrand is the long random number generator function. _rand uses a multiplicative congruential random number generator with
period 2^64 to return successive pseudo-random numbers in the range from 0 to 2^31 - 1.
The generator is reinitialized by calling srand with an argument value of 1. It can be set to a new starting point by calling srand
with a given seed number.
stdlib.h
Category
Math Routines
Prototype
unsigned long _lrotl(unsigned long val, int count);
unsigned long _lrotr(unsigned long val, int count);
Description
_Irotlrotates the given val to the left count bits. _lrotr rotates the given val to the right count bits.
Return Value
1099
C Runtime Library Reference RAD Studio 3.1 C++ Reference
{
unsigned long result;
unsigned long value = 100;
result = _lrotl(value,1);
printf("The value %lu rotated left one bit is: %lu\n", value, result);
return 0;
}
/* lrotr example */
int lrotr_example(void)
{
unsigned long result;
unsigned long value = 100;
result = _lrotr(value,1);
printf("The value %lu rotated right one bit is: %lu\n", value, result);
return 0;
}
int main(void)
{
lrotl_example();
lrotr_example();
return 0;
}
Portability
stdlib.h
Category
Prototype
void _makepath(char *path, const char *drive, const char *dir, const char *name, const char
*ext);
void _wmakepath(wchar_t *path, const wchar_t *drive, const wchar_t *dir, const wchar_t *name,
const wchar_t *ext);
Description
_makepath makes a path name from its components. The new path name is
X:\DIR\SUBDIR\NAME.EXT
3
where
drive = X:
dir = \DIR\SUBDIR\
name = NAME
ext = .EXT
1100
3.1 C++ Reference RAD Studio C Runtime Library Reference
If drive is empty or NULL, no drive is inserted in the path name. If it is missing a trailing colon (:), a colon is
inserted in the path name.
If dir is empty or NULL, no directory is inserted in the path name. If it is missing a trailing slash (\ or /), a
backslash is inserted in the path name.
If name is empty or NULL, no file name is inserted in the path name.
If ext is empty or NULL, no extension is inserted in the path name. If it is missing a leading period (.), a
period is inserted in the path name.
_makepath assumes there is enough space in path for the constructed path name. The maximum
constructed length is _MAX_PATH. _MAX_PATH is defined in stdlib.h.
_makepath and _splitpath are invertible; if you split a given path with _splitpath, then merge the resultant
components with _makepath, you end up with path.
If drive is empty or NULL, no drive is inserted in the path name. If it is missing a trailing colon (:), a colon is inserted in the path
name.
If dir is empty or NULL, no directory is inserted in the path name. If it is missing a trailing slash (\ or /), a backslash is inserted in
the path name.
If ext is empty or NULL, no extension is inserted in the path name. If it is missing a leading period (.), a period is inserted in the
path name.
_makepath assumes there is enough space in path for the constructed path name. The maximum constructed length is
_MAX_PATH. _MAX_PATH is defined in stdlib.h.
_makepath and _splitpath are invertible; if you split a given path with _splitpath, then merge the resultant components with
_makepath, you end up with path.
Return Value
Example
#include <dir.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char s[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char file[_MAX_FNAME];
char ext[_MAX_EXT];
getcwd(s,_MAX_PATH); /* get current working directory */
if (s[strlen(s)-1] != '\\')
strcat(s,"\\"); /* append a trailing \ character */
_splitpath(s,drive,dir,file,ext); /* split the string to separate
elems */
strcpy(file,"DATA"); 3
strcpy(ext,".TXT");
_makepath(s,drive,dir,file,ext); /* merge everything into one string */
puts(s); /* display resulting string */
return 0;
}
Portability
1101
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdlib.h
Category
Math Routines
Prototype
unsigned short _rotl(unsigned short value, int count);
unsigned short _rotr(unsigned short value, int count);
Description
Return Value
1102
3.1 C++ Reference RAD Studio C Runtime Library Reference
Portability
stdlib.h
Category
Miscellaneous Routines
Prototype
char *_searchenv(const char *file, const char *varname, char *buf);
char *_wsearchenv(const wchar_t *file, const wchar_t *varname, wchar_t *buf);
Description
_searchenv attempts to locate file, searching along the path specified by the operating system environment variable varname.
Typical environment variables that contain paths are PATH, LIB, and INCLUDE.
_searchenv searches for the file in the current directory of the current drive first. If the file is not found there, the environment
variable varname is fetched, and each directory in the path it specifies is searched in turn until the file is found, or the path is
exhausted.
When the file is located, the full path name is stored in the buffer pointed to by buf. This string can be used in a call to access the
file (for example, with fopen or exec...). The buffer is assumed to be large enough to store any possible file name. If the file
cannot be successfully located, an empty string (consisting of only a null character) will be stored at buf.
Return Value
None.
Example
#include <stdio.h>
#include <stdlib.h>
char buf[_MAX_PATH];
int main(void)
{
/* ILINK32 will be found in your installation directory */
_searchenv("ILINK32.EXE","PATH",buf); 3
if (buf[0] == '\0')
printf("ILINK32.EXE not found\n");
else
printf("ILINK32.EXE found in %s\n", buf);
1103
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdlib.h
Category
Miscellaneous Routines
Prototype
void _searchstr(const char *file, const char *ipath, char *buf);
void _wsearchstr(const wchar_t *file, const wchar_t *ipath,wchar_t *pathname);
Description
_searchstr attempts to locate file, searching along the path specified by the string ipath.
_searchstr searches for the file in the current directory of the current drive first. If the file is not found there, each directory in
ipath is searched in turn until the file is found, or the path is exhausted. The directories in ipath must be separated by semicolons.
When the file is located, the full path name is stored in the buffer pointed by by buf. This string can be used in a call to access
the file (for example, with fopen or exec...). The buffer is assumed to be large enough to store any possible file name. The
constant _MAX_PATH defined in stdlib.h, is the size of the largest file name. If the file cannot be successfully located, an empty
string (consisting of only a null character) will be stored at buf.
Return Value
None.
Example
#include <stdio.h>
#include <stdlib.h>
char buf[_MAX_PATH];
int main(void)
{
/* look for ILINK32.EXE */
3 _searchstr("ILINK32.EXE", "PATH", buf);
if (buf[0] == '\0')
printf ("ILINK32.EXE not found\n");
else
printf ("ILINK32.EXE found in %s\n", buf);
return 0;
}
Portability
1104
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdlib.h
Category
Prototype
void _splitpath(const char *path, char *drive, char *dir, char *name, char *ext);
void _wsplitpath(const wchar_t *path, wchar_t *drive, wchar_t *dir, wchar_t *name, wchar_t
*ext);
Description
_splitpath takes a file's full path name (path) as a string in the form
X:\DIR\SUBDIR\NAME.EXT
and splits path into its four components. It then stores those components in the strings pointed to by drive, dir, name, and ext.
(All five components must be passed, but any of them can be a null, which means the corresponding component will be parsed
but not stored.) The maximum sizes for these strings are given by the constants _MAX_DRIVE, _MAX_DIR, _MAX_PATH,
_MAX_FNAME, and _MAX_EXT (defined in stdlib.h), and each size includes space for the null-terminator. These constants are
defined in stdlib.h.
_MAX_PATH path
_MAX_DRIVE drive; includes colon (:)
_MAX_DIR dir; includes leading and trailing backslashes (\)
_MAX_FNAME name
_MAX_EXT ext; includes leading dot (.)
_splitpath assumes that there is enough space to store each non-null component.
1105
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Example
#include <dir.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char s[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char file[_MAX_FNAME];
char ext[_MAX_EXT];
/* get current working directory */
getcwd(s,_MAX_PATH);
if (s[strlen(s)-1] != '\\')
/* append a trailing \ character */
strcat(s,"\\");
/* split the string to separate elems */
_splitpath(s,drive,dir,file,ext);
strcpy(file,"DATA");
strcpy(ext,".TXT");
/* merge everything into one string */
_makepath(s,drive,dir,file,ext);
/* display resulting string */
puts(s);
return 0;
}
Portability
stdlib.h
Category
Prototype
char *_ui64toa(unsigned __int64 value, char *string, int radix);
wchar_t *_ui64tow(unsigned __int64 value, wchar_t *string, int radix);
Description
3 _ui64toa converts an unsigned __int64 to a string.
_ui64tow is the unicode version. _ui64tow converts an unsigned __int64 to a wide-character string.
These functions convert value to a null-terminated string and store the result in string. value is an __int64.
radix specifies the base to be used in converting value; it must be between 2 and 36, inclusive. If value is negative and radix is
10, the first character of string is the minus sign (-).
Note: The space allocated for string must be large enough to hold the returned string, including the terminating null character
1106
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
Portability
3.1.4.29.17 abort
Header File
stdlib.h
Category
Prototype
void abort(void);
Description
abort causes an abnormal program termination by calling raise(SIGABRT). If there is no signal handler for SIGABRT, then abort
writes a termination message (Abnormal program termination) on stderr, then aborts the program by a call to _exit with exit code
3.
Return Value
abort returns the exit code 3 to the parent process or to the operating system command processor.
Example
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("Calling abort()\n");
abort();
return 0; /* This is never reached */
}
Portability
3.1.4.29.18 atexit
Header File
stdlib.h
1107
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Prototype
int atexit(void (_USERENTRY * func)(void));
Description
atexit registers the function pointed to by func as an exit function. Upon normal termination of the program, exit calls func just
before returning to the operating system. fcmp must be used with the _USERENTRY calling convention.
Each call to atexit registers another exit function. Up to 32 functions can be registered. They are executed on a last-in, first-out
basis (that is, the last function registered is the first to be executed).
Return Value
atexit returns 0 on success and nonzero on failure (no space left to register the function).
Example
#include <stdio.h>
#include <stdlib.h>
void exit_fn1(void)
{
printf("Exit function #1 called\n");
}
void exit_fn2(void)
{
printf("Exit function #2 called\n");
}
int main(void)
{
/* post exit function #1 */
atexit(exit_fn1);
/* post exit function #2 */
atexit(exit_fn2);
return 0;
}
Portability
stdlib.h
3
Category
Prototype
int atoi(const char *s);
int _wtoi(const wchar_t *s);
1108
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
• atoi converts a string pointed to by s to int; atoi recognizes (in the following order)
• An optional string of tabs and spaces
• An optional sign
• A string of digits
The characters must match this generic format:
[ws] [sn] [ddd]
In this function, the first unrecognized character ends the conversion. There are no provisions for overflow in atoi (results are
undefined).
Return Value
atoi returns the converted value of the input string. If the string cannot be converted to a number of the corresponding type (int),
atoi returns 0.
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int n;
char *str = "12345.67";
n = atoi(str);
printf("string = %s integer = %d\n", str, n);
return 0;
}
Portability
stdlib.h
Category
Prototype
long atol(const char *s); 3
long _wtol(const wchar_t *s);
Description
• atol converts the string pointed to by s to long. atol recognizes (in the following order)
• An optional string of tabs and spaces
1109
C Runtime Library Reference RAD Studio 3.1 C++ Reference
• An optional sign
• A string of digits
The characters must match this generic format:
[ws] [sn] [ddd]
In this function, the first unrecognized character ends the conversion. There are no provisions for overflow in atol (results are
undefined).
Return Value
atol returns the converted value of the input string. If the string cannot be converted to a number of the corresponding type (b),
atol returns 0.
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
long l;
char *lstr = "98765432";
l = atol(lstr);
printf("string = %s integer = %ld\n", lstr, l);
return(0);
}
Portability
3.1.4.29.21 bsearch
Header File
stdlib.h
Category
Prototype
void *bsearch(const void *key, const void *base, size_t nelem, size_t width, int (_USERENTRY
*fcmp)(const void *, const void *));
Description
bsearch searches a table (array) of nelem elements in memory, and returns the address of the first entry in the table that
3
matches the search key. The array must be in order. If no match is found, bsearch returns 0.
Note: Because this is a binary search, the first matching entry is not necessarily the first entry in the table.
1110
3.1 C++ Reference RAD Studio C Runtime Library Reference
fcmp is called with two arguments: elem1 and elem2. Each argument points to an item to be compared. The comparison function
compares each of the pointed-to items (*elem1 and *elem2), and returns an integer based on the results of the comparison.
• For bsearch, the fcmp return value is
• < 0 if *elem1 < *elem2
• == 0 if *elem1 == *elem2
• > 0 if *elem1 > *elem2
Return Value
bsearch returns the address of the first entry in the table that matches the search key. If no match is found, bsearch returns 0.
Example
#include <stdlib.h>
#include <stdio.h>
typedef int (*fptr)(const void*, const void*);
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
int numarray[] = {123, 145, 512, 627, 800, 933};
int numeric (const int *p1, const int *p2)
{
return(*p1 - *p2);
}
#pragma argsused
int lookup(int key)
{
int *itemptr;
/* The cast of (int(*)(const void *,const void*))
is needed to avoid a type mismatch error at
compile time */
itemptr = (int *) bsearch (&key, numarray, NELEMS(numarray),
sizeof(int), (fptr)numeric);
return (itemptr != NULL);
}
int main(void)
{
if (lookup(512))
printf("512 is in the table.\n");
else
printf("512 isn't in the table.\n");
return 0;
}
Portability
3.1.4.29.22 div
Header File
stdlib.h 3
Category
Math Routines
Prototype
div_t div(int numer, int denom);
Description
1111
C Runtime Library Reference RAD Studio 3.1 C++ Reference
div divides two integers and returns both the quotient and the remainder as a div_t type. numer and denom are the numerator
and denominator, respectively. The div_t type is a structure of integers defined (with typedef) in stdlib.h as follows:
typedef struct {
int quot; /* quotient */
int rem; /* remainder */
} div_t;
Return Value
div returns a structure whose elements are quot (the quotient) and rem (the remainder).
Example
/* div example */
#include <stdlib.h>
#include <stdio.h>
div_t x;
int main(void)
{
x = div(10,3);
printf("10 div 3 = %d remainder %d\n",
x.quot, x.rem);
return 0;
}
Portability
3.1.4.29.23 ecvt
Header File
stdlib.h
Category
Prototype
char *ecvt(double value, int ndig, int *dec, int *sign);
Description
3 ecvt converts value to a null-terminated string of ndig digits, starting with the leftmost significant digit, and returns a pointer to the
string. The position of the decimal point relative to the beginning of the string is stored indirectly through dec (a negative value for
dec means that the decimal lies to the left of the returned digits). There is no decimal point in the string itself. If the sign of value
is negative, the word pointed to by sign is nonzero; otherwise, it's 0. The low-order digit is rounded.
Return Value
The return value of ecvt points to static data for the string of digits whose content is overwritten by each call to ecvt and fcvt.
Example
1112
3.1 C++ Reference RAD Studio C Runtime Library Reference
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *string;
double value;
int dec, sign;
int ndig = 10;
value = 9.876;
string = ecvt(value, ndig, &dec, &sign);
printf("string = %s dec = %d sign = %d\n", string, dec, sign);
value = -123.45;
ndig= 15;
string = ecvt(value,ndig,&dec,&sign);
printf("string = %s dec = %d sign = %d\n", string, dec, sign);
value = 0.6789e5; /* scientific notation */
ndig = 5;
string = ecvt(value,ndig,&dec,&sign);
printf("string = %s dec = %d sign = %d\n", string, dec, sign);
return 0;
}
Portability
stdlib.h
Syntax
extern char ** _environ;
extern wchar_t ** _wenviron
Description
_environ is an array of pointers to strings; it is used to access and alter the operating system environment variables. Each string
is of the form:
envvar = varvalue
where envvar is the name of an environment variable (such as PATH), and varvalue is the string value to which envvar is set
(such as C:\Utils;C:\MyPrograms). The string varvalue can be empty.
When a program begins execution, the operating system environment settings are passed directly to the program. Note that env,
the third argument to main, is equal to the initial setting of _environ.
The _environ array can be accessed by getenv; however, the putenv function is the only routine that should be used to add,
change or delete the _environ array entries. This is because modification can resize and relocate the process environment array,
3
but _environ is automatically adjusted so that it always points to the array.
Portability
1113
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.29.25 exit
Header File
stdlib.h
Category
Prototype
void exit(int status);
Description
Terminates program.
exit terminates the calling process. Before termination, all files are closed, buffered output (waiting to be output) is written, and
any registered "exit functions" (posted with atexit) are called.
status is provided for the calling process as the exit status of the process. Typically a value of 0 is used to indicate a normal exit,
and a nonzero value indicates some error. It can be, but is not required, to be set with one of the following:
EXIT_FAILURE Abnormal program termination; signal to operating system that program has terminated with an error
EXIT_SUCCESS Normal program termination
Return Value
None.
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int status;
printf("Enter either 1 or 2\n");
status = getchar();
exit(status - '0');
/* Note: this line is never reached */
return 0;
}
Portability
3 3.1.4.29.26 fcvt
Header File
stdlib.h
Category
1114
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
char *fcvt(double value, int ndig, int *dec, int *sign);
Description
fcvt converts value to a null-terminated string digit starting with the leftmost significant digit with ndig digits to the right of the
decimal point. fcvt then returns a pointer to the string. The position of the decimal point relative to the beginning of the string is
stored indirectly through dec (a negative value for dec means to the left of the returned digits). There is no decimal point in the
string itself. If the sign of value is negative the word pointed to by sign is nonzero; otherwise it is 0.
The correct digit has been rounded for the number of digits to the right of the decimal point specified by ndig.
Return Value
The return value of fcvt points to static data whose content is overwritten by each call to fcvt and ecvt.
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *str;
double num;
int dec, sign, ndig = 5;
/* a regular number */
num = 9.876;
str = fcvt(num, ndig, &dec, &sign);
printf("string = %10s decimal place = %d sign = %d\n", str, dec, sign);
/* a negative number */
num = -123.45;
str = fcvt(num, ndig, &dec, &sign);
printf("string = %10s decimal place = %d sign = %d\n", str, dec, sign);
/* scientific notation */
num = 0.678e5;
str = fcvt(num, ndig, &dec, &sign);
printf("string = %10s decimal place= %d sign = %d\n", str, dec, sign);
return 0;
}
Portability
3.1.4.29.27 gcvt
Header File
stdlib.h 3
Category
Prototype
char *gcvt(double value, int ndec, char *buf);
Description
1115
C Runtime Library Reference RAD Studio 3.1 C++ Reference
gcvt converts value to a null-terminated ASCII string and stores the string in buf. It produces ndec significant digits in FORTRAN
F format, if possible; otherwise, it returns the value in the printf E format (ready for printing). It might suppress trailing zeros.
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char str[25];
double num;
int sig = 5; /* significant digits */
/* a regular number */
num = 9.876;
gcvt(num, sig, str);
printf("string = %s\n", str);
/* a negative number */
num = -123.4567;
gcvt(num, sig, str);
printf("string = %s\n", str);
/* scientific notation */
num = 0.678e5;
gcvt(num, sig, str);
printf("string = %s\n", str);
return(0);
}
Portability
stdlib.h
Category
Prototype
char *getenv(const char *name);
wchar_t *_wgetenv(const wchar_t *name);
3
Description
The environment consists of a series of entries that are of the form name=string\0.
getenv returns the value of a specified variable. name can be either uppercase or lowercase. name must not include the equal
sign (=). If the specified environment variable does not exist, getenv returns a NULL pointer.
1116
3.1 C++ Reference RAD Studio C Runtime Library Reference
Note: Environment entries must not be changed directly. If you want to change an environment value, you must use putenv.
Return Value
If the specified name is not defined in the environment, getenv returns a NULL pointer.
Example
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <string.h>
int main(void)
{
char *path, *ptr;
int i = 0;
/* get the current path environment */
ptr = getenv("PATH");
/* set up new path */
path = (char *) malloc(strlen(ptr)+15);
strcpy(path,"PATH=");
strcat(path,ptr);
strcat(path,";c:\\temp");
/* replace the current path and display current environment */
putenv(path);
while (_environ[i])
printf("%s\n",_environ[i++]);
return 0;
}
Portability
stdlib.h
Category
Prototype
char *itoa(int value, char *string, int radix);
wchar_t *_itow(int value, wchar_t *string, int radix);
3
Description
itoa converts value to a null-terminated string and stores the result in string. With itoa, value is an integer. _itow is the unicode
version of the function. It converts an integer to a wide-character string.
radix specifies the base to be used in converting value; it must be between 2 and 36, inclusive. If value is negative and radix is
10, the first character of string is the minus sign (-).
1117
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Note: The space allocated for string must be large enough to hold the returned string, including the terminating null character
(\0). itoa can return up to 33 bytes.
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int number = 12345;
char string[25];
itoa(number, string, 10);
printf("integer = %d string = %s\n", number, string);
return 0;
}
Portability
3.1.4.29.30 labs
Header File
stdlib.h
Category
Math Routines
Prototype
long labs(long int x);
Description
Return Value
Example
#include <stdio.h>
#include <math.h>
int main(void)
3 {
long result;
long x = -12345678L;
result= labs(x);
printf("number: %ld abs value: %ld\n", x, result);
return 0;
}
Portability
1118
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.29.31 lfind
Header File
stdlib.h
Category
Prototype
void *lfind(const void *key, const void *base, size_t *num, size_t width, int (_USERENTRY
*fcmp)(const void *, const void *));
Description
lfind makes a linear search for the value of key in an array of sequential records. It uses a user-defined comparison routine fcmp.
The fcmp function must be used with the _USERENTRY calling convention.
The array is described as having *num records that are width bytes wide, and begins at the memory location pointed to by base.
Return Value
lfind returns the address of the first entry in the table that matches the search key. If no match is found, lfind returns NULL. The
comparison routine must return 0 if *elem1 == *elem2, and nonzero otherwise (elem1 and elem2 are its two parameters).
Example
#include <stdio.h>
#include <stdlib.h>
int compare(int *x, int *y)
{
return( *x - *y );
}
int main(void)
{
int array[5] = {35, 87, 46, 99, 12};
size_t nelem = 5;
int key;
int *result;
key = 99;
result = (int *) lfind(&key, array, &nelem,
sizeof(int), (int(*)(const void *,const void *))compare);
if (result)
printf("Number %d found\n",key);
else
printf("Number %d not found\n",key); 3
return 0;
}
Portability
1119
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.29.32 lsearch
Header File
stdlib.h
Category
Prototype
void *lsearch(const void *key, void *base, size_t *num, size_t width, int (_USERENTRY
*fcmp)(const void *, const void *));
Description
lsearch searches a table for information. Because this is a linear search, the table entries do not need to be sorted before a call
to lsearch. If the item that key points to is not in the table, lsearch appends that item to the table.
fcmp is free to interpret the search key and the table entries in any way.
Return Value
lsearch returns the address of the first entry in the table that matches the search key.
If the search key is not identical to *elem, fcmp returns a nonzero integer. If the search key is identical to *elem, fcmp returns 0.
Example
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* for strcmp declaration */
3 /* initialize number of colors */
char *colors[10] = { "Red", "Blue", "Green" };
int ncolors = 3;
int colorscmp(char **arg1, char **arg2)
{
return(strcmp(*arg1, *arg2));
}
int addelem(char **key)
{
int oldn = ncolors;
lsearch(key, colors, (size_t *)&ncolors, sizeof(char *),
1120
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdlib.h
Category
Prototype
char * ltoa(long value, char * string, int radix);
char *_ltoa(long value, char *string, int radix);
wchar_t *_ltow(long value, wchar_t *string, int radix);
Description
Converts a long to a string. _ltow is the unicode version. It converts a long to a wide-charater string.
Converts value to a null-terminated string and stores the result in string. value is a long.
radix specifies the base to be used in converting value; it must be between 2 and 36, inclusive. If value is negative and radix is
10, the first character of string is the minus sign (-).
Note: The space allocated for string must be large enough to hold the returned string, including the terminating null character
(\0). Can return up to 33 bytes.
3
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
1121
C Runtime Library Reference RAD Studio 3.1 C++ Reference
char string[25];
long value = 123456789L;
ltoa(value,string,10);
printf("number = %ld string = %s\n", value, string);
return 0;
}
Portability
3.1.4.29.34 max
Header File
stdlib.h
Category
Prototype
(type) max(a, b);
template <class T> T max( T t1, T t2 ); // C++ only
Description
The C macro and the C++ template function compare two values and return the larger of the two. Both arguments and the
routine declaration must be of the same type.
Return Value
Portability
3.1.4.29.35 mblen
3 Header File
stdlib.h
Category
Prototype
int mblen(const char *s, size_t n);
1122
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
If s is not null, mblen determines the number of bytes in the multibyte character pointed to by s. The maximum number of bytes
examined is specified by n.
The behavior of mblen is affected by the setting of LC_CTYPE category of the current locale.
Return Value
If s is null, mblen returns a nonzero value if multibyte characters have state-dependent encodings. Otherwise, mblen returns 0.
If s is not null, mblen returns 0 if s points to the null character, and -1 if the next n bytes do not comprise a valid multibyte
character; the number of bytes that comprise a valid multibyte character.
Example
#include <stdlib.h>
#include <stdio.h>
void main (void)
{
int i ;
char *mulbc = (char *)malloc( sizeof( char) );
wchar_t widec = L'a';
printf (" convert a wide character to multibyte character:\n" );
i = wctomb (mulbc, widec);
printf( "\tCharacters converted: %u\n", i);
printf( "\tMultibyte character: %x\n\n", mulbc);
printf( " Find length--in byte-- of multibyte character:\n");
i = mblen( mulbc, MB_CUR_MAX);
printf("\tLength--in bytes--if multiple character: %u\n",i);
printf("\tWide character: %x\n\n", mulbc);
printf( " Attempt to find length of a Wide character Null:\n");
widec = L'\0';
wctomb(mulbc, widec);
i = mblen( mulbc, MB_CUR_MAX);
printf("\tLength--in bytes--if multiple character: %u\n",i);
printf("\tWide character: %x\n\n", mulbc);
}
Portability
3.1.4.29.36 mbstowcs
Header File
stdlib.h
Category
3
Conversion Routines, Memory and String Manipulation Routines
Prototype
size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n);
Description
1123
C Runtime Library Reference RAD Studio 3.1 C++ Reference
The function converts the multibyte string s into the array pointed to by pwcs. No more than n values are stored in the array. If an
invalid multibyte sequence is encountered, mbstowcs returns (size_t) -1.
The pwcs array will not be terminated with a zero value if mbstowcs returns n.
Return Value
If an invalid multibyte sequence is encountered, mbstowcs returns (size_t) -1. Otherwise, the function returns the number of
array elements modified, not including the terminating code, if any.
Example
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int x;
char *mbst = (char *)malloc(MB_CUR_MAX);
wchar_t *pwst = L"Hi";
wchar_t *pwc = (wchar_t *)malloc(sizeof( wchar_t));
printf ("Convert to multibyte string:\n");
x = wcstombs (mbst, pwst, MB_CUR_MAX);
printf ("\tCharacters converted %u\n",x);
printf ("\tHEx value of first");
printf (" multibyte character: %#.4x\n\n", mbst);
printf ("Convert back to wide character string:\n");
x = mbstowcs(pwc, mbst, MB_CUR_MAX);
printf( "\tCharacters converted: %u\n",x);
printf( "\tHex value of first");
printf( "wide character: %#.4x\n\n", pwc);
}
Portability
3.1.4.29.37 mbtowc
Header File
stdlib.h
Category
Prototype
int mbtowc(wchar_t *pwc, const char *s, size_t n);
Description
3 Converts a multibyte character to wchar_t code.
If s is not null, mbtowc determines the number of bytes that comprise the multibyte character pointed to by s. Next, mbtowc
determines the value of the type wchar_t that corresponds to that multibyte character. If there is a successful match between
wchar_t and the multibyte character, and pwc is not null, the wchar_t value is stored in the array pointed to by pwc. At most n
characters are examined.
Return Value
When s points to an invalid multibyte character, -1 is returned. When s points to the null character, 0 is returned. Otherwise,
1124
3.1 C++ Reference RAD Studio C Runtime Library Reference
mbtowc returns the number of bytes that comprise the converted multibyte character.
Example
#include <stdlib.h>
#include<stdio.h>
void main(void)
{
int x;
char *mbchar = (char *)calloc(1, sizeof( char));
wchar_t wchar = L'a';
wchar_t *pwcnull = NULL;
wchar_t *pwchar = (wchar_t *)calloc(1, sizeof( wchar_t ));
printf ("Convert a wide character to multibyte character:\n");
x = wctomb( mbchar, wchar);
printf( "\tCharacters converted: %u\n", x);
printf( "\tMultibyte character: %x\n\n", mbchar);
printf ("Convert multibyte character back to a wide character:\n");
x = mbtowc( pwchar, mbchar, MB_CUR_MAX );
printf( "\tBytes converted: %u\n", x);
printf( "\tWide character: %x\n\n", pwchar);
printf ("Atempt to convert when target is NULL\n" );
printf (" returns the length of the multibyte character:\n" );
x = mbtowc (pwcnull, mbchar, MB_CUR_MAX );
printf ( "\tlength of multibyte character:%u\n\n", x );
printf ("Attempt to convert a NULL pointer to a" );
printf (" wide character:\n" );
mbchar = NULL;
x = mbtowc (pwchar, mbchar, MB_CUR_MAX);
printf( "\tBytes converted: %u\n", x );
}
Portability
3.1.4.29.38 min
Header File
stdlib.h
Category
Prototype
(type) min(a, b); /* macro version */
template <class T> T min( T t1, T t2 );// C++ only 3
Description
The C macro and the C++ template function compare two values and return the smaller of the two. Both arguments and the
routine declaration must be of the same type.
Return Value
1125
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdlib.h
Category
Prototype
int putenv(const char *name);
int _wputenv(const wchar_t *name);
Description
putenv accepts the string name and adds it to the environment of the current process. For example,
putenv(“PATH=C:\\BC”);
putenv can also be used to modify an existing name. name can be either uppercase or lowercase. name must not include the
equal sign (=). You can set a variable to an empty value by specifying an empty string on the right side of the ‘=’ sign.
putenv can be used only to modify the current program’s _environment. Once the program ends, the old _environment is
restored. The _environment of the current process is passed to child processes, including any changes made by putenv.
Note that the string given to putenv must be static or global. Unpredictable results will occur if a local or dynamic string given to
putenv is used after the string memory is released.
Return Value
Example
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <string.h>
int main(void)
{
char *path, *ptr;
int i = 0;
/* get the current path environment */
ptr = getenv("PATH");
/* set up new path */
path = (char *) malloc(strlen(ptr)+15);
strcpy(path,"PATH=");
strcat(path,ptr);
3 strcat(path,";c:\\temp");
/* replace the current path and display current environment */
putenv(path);
while (_environ[i])
printf("%s\n",_environ[i++]);
return 0;
}
Portability
1126
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.29.40 qsort
Header File
stdlib.h
Category
Prototype
void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const
void *));
Description
qsort is an implementation of the “median of three” variant of the quicksort algorithm. qsort sorts the entries in a table by
repeatedly calling the user-defined comparison function pointed to by fcmp.
1127
C Runtime Library Reference RAD Studio 3.1 C++ Reference
}
int sort_function( const void *a, const void *b)
{
return( strcmp((char *)a,(char *)b) );
}
Portability
3.1.4.29.41 rand
Header File
stdlib.h
Category
Math Routines
Prototype
int rand(void);
Description
rand uses a multiplicative congruential random number generator with period 2 to the 32nd power to return successive
pseudo-random numbers in the range from 0 to RAND_MAX. The symbolic constant RAND_MAX is defined in stdlib.h.
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int i;
randomize();
printf("Ten random numbers from 0 to 99\n\n");
for(i=0; i<10; i++)
printf("%d\n", rand() % 100);
return 0;
}
Portability
3.1.4.29.42 random
Header File
stdlib.h
1128
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Math Routines
Prototype
int random(int num);
Description
random returns a random number between 0 and (num-1). random(num) is a macro defined in stdlib.h. Both num and the
random number returned are integers.
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
/* prints a random number in the range 0 to 99 */
int main(void)
{
randomize();
printf("Random number in the 0-99 range: %d\n", random (100));
return 0;
}
Portability
3.1.4.29.43 randomize
Header File
stdlib.h, time.h
Category
Math Routines
Prototype
void randomize(void);
Description
Return Value
None.
Example
#include <stdlib.h>
#include <stdio.h>
1129
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <time.h>
int main(void)
{
int i;
randomize();
printf("Ten random numbers from 0 to 99\n\n");
for(i=0; i<10; i++)
printf("%d\n", rand() % 100);
return 0;
}
Portability
3.1.4.29.44 srand
Header File
stdlib.h
Category
Math Routines
Prototype
void srand(unsigned seed);
Description
The random number generator is reinitialized by calling srand with an argument value of 1. It can be set to a new starting point
by calling srand with a given seed number.
Return Value
None.
Example
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int i;
time_t t;
srand((unsigned) time(&t));
printf("Ten random numbers from 0 to 99\n\n");
for(i=0; i<10; i++)
3 printf("%d\n", rand() % 100);
return 0;
}
Portability
1130
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Prototype
size_t strlen(const char *s);
size_t wcslen(const wchar_t *s);
size_t _mbslen(const unsigned char *s);
size_t _mbstrlen(const char *s)
Description
_mbslen and _mbstrlen test the string argument to determine the number of multibyte characters they contain.
_mbstrlen is affected by the LC_CTYPE category setting as determined by the setlocale function. The function tests to determine
whether the string argument is a valid multibyte string.
_mbslen is affected by the code page that is in use. This function doesn’t test for multibyte validity.
Return Value
strlen returns the number of characters in s, not counting the null-terminating character.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *string = "CodeGear";
printf("%d\n", strlen(string));
return 0;
}
Portability
stdlib.h
1131
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Prototype
double strtod(const char *s, char **endptr);
double wcstod(const wchar_t *s, wchar_t **endptr);
long double _strtold(const char *s, char **endptr);
long double _wcstold(const wchar_t *s, wchar_t **endptr);
Description
strtod converts a character string, s, to a double value. s is a sequence of characters that can be interpreted as a double value;
the characters must match this generic format:
[ws] [sn] [ddd] [.] [ddd] [fmt[sn]ddd]
where:
strtod also recognizes +INF and -INF for plus and minus infinity, and +NAN and -NAN for not-a-number.
For example, here are some character strings that strtod can convert to double:
+ 1231.1981 e-1
502.85E2
+ 2010.952
strtod stops reading the string at the first character that cannot be interpreted as an appropriate part of a double value.
If endptr is not null, strtod sets *endptr to point to the character that stopped the scan (*endptr = &stopper). endptr is useful for
error detection.
_strtold is the long double version; it converts a string to a long double value.
Return Value
These functions return the value of s as a double (strtod) or a long double (_strtold). In case of overflow, they return plus or
minus HUGE_VAL (strtod) or _LHUGE_VAL (_strtold).
3 Example
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char input[80], *endptr;
double value;
printf("Enter a floating point number:");
gets(input);
value = strtod(input, &endptr);
1132
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdlib.h
Category
Prototype
long strtol(const char *s, char **endptr, int radix);
long wcstol(const wchar_t *s, wchar_t **endptr, int radix);
Description
strtol converts a character string, s, to a long integer value. s is a sequence of characters that can be interpreted as a long
value; the characters must match this generic format:
[ws] [sn] [0] [x] [ddd]
where:
strtol stops reading the string at the first character it doesn't recognize.
If radix is between 2 and 36, the long integer is expressed in base radix. If radix is 0, the first few characters of s determine the
base of the value being converted.
3
If radix is 1, it is considered to be an invalid value. If radix is less than 0 or greater than 36, it is considered to be an invalid value.
Any invalid value for radix causes the result to be 0 and sets the next character pointer *endptr to the starting string pointer.
If the value in s is meant to be interpreted as octal, any character other than 0 to 7 will be unrecognized.
If the value in s is meant to be interpreted as decimal, any character other than 0 to 9 will be unrecognized.
1133
C Runtime Library Reference RAD Studio 3.1 C++ Reference
If the value in s is meant to be interpreted as a number in any other base, then only the numerals and letters used to represent
numbers in that base will be recognized. (For example, if radix equals 5, only 0 to 4 will be recognized; if radix equals 20, only 0
to 9 and A to J will be recognized.)
If endptr is not null, strtol sets *endptr to point to the character that stopped the scan (*endptr = &stopper).
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *string = "87654321", *endptr;
long lnumber;
/* strtol converts string to long integer */
lnumber = strtol(string, &endptr, 10);
printf("string = %s long = %ld\n", string, lnumber);
return 0;
}
Portability
stdlib.h
Category
Prototype
unsigned long strtoul(const char *s, char **endptr, int radix);
unsigned long wcstoul(const wchar_t *s, wchar_t **endptr, int radix);
Description
strtoul operates the same as strtol, except that it converts a string str to an unsigned long value (where strtol converts to a
long). Refer to the entry for strtol for more information.
3
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
1134
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.29.49 swab
Header File
stdlib.h
Category
Prototype
void swab(char *from, char *to, int nbytes);
Description
Swaps bytes.
swab copies nbytes bytes from the from string to the to string. Adjacent even- and odd-byte positions are swapped. This is useful
for moving data from one machine to another machine with a different byte order. nbytes should be even.
Return Value
None.
Example
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char source[15] = "rFna koBlrna d";
char target[15];
int main(void)
{
swab(source, target, strlen(source));
printf("This is target: %s\n", target);
return 0;
}
Portability 3
POSIX Win32 ANSI C ANSI C++
+ +
1135
C Runtime Library Reference RAD Studio 3.1 C++ Reference
stdlib.h
Category
Prototype
int system(const char *command);
int _wsystem(const wchar_t *command);
Description
system invokes the operating system command processor to execute an operating system command, batch file, or other
program named by the string command, from inside an executing C program.
To be located and executed, the program must be in the current directory or in one of the directories listed in the PATH string in
the environment.
The COMSPEC environment variable is used to find the command processor program, so it need not be in the current directory.
Return Value
If command is not a NULL pointer, system returns 0 if the command processor was successfully started.
Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
printf("About to spawn a command-line program.\n");
system("dir");
return 0;
}
Portability
3 POSIX Win32 ANSI C ANSI C++
system + +
_wsystem NT only
1136
3.1 C++ Reference RAD Studio C Runtime Library Reference
stdlib.h
Category
Prototype
char *ultoa(unsigned long value, char *string, int radix);
wchar_t *_ultow(unsigned long value, wchar_t *string, int radix);
Description
ultoa converts value to a null-terminated string and stores the result in string. value is an unsigned long.
radix specifies the base to be used in converting value; it must be between 2 and 36, inclusive. ultoa performs no overflow
checking, and if value is negative and radix equals 10, it does not set the minus sign.
Note: The space allocated for string must be large enough to hold the returned string, including the terminating null character
(\0). ultoa can return up to 33 bytes.
Return Value
Example
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
unsigned long lnumber = 3123456789L;
char string[25];
ultoa(lnumber,string,10);
printf("string = %s unsigned long = %lu\n",string,lnumber);
return 0;
}
Portability
3.1.4.29.52 wcstombs 3
Header File
stdlib.h
Category
1137
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
size_t wcstombs(char *s, const wchar_t *pwcs, size_t n);
Description
wcstombs converts the type wchar_t elements contained in pwcs into a multibyte character string s. The process terminates if
either a null character or an invalid multibyte character is encountered.
No more than n bytes are modified. If n number of bytes are processed before a null character is reached, the array s is not null
terminated.
The behavior of wcstombs is affected by the setting of LC_CTYPE category of the current locale.
Return Value
If an invalid multibyte character is encountered, wcstombs returns (size_t) -1. Otherwise, the function returns the number of
bytes modified, not including the terminating code, if any.
Example
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int x;
char *pbuf = (char*)malloc( MB_CUR_MAX);
wchar_t *pwcsEOL = L'\0';
char *pwchi= L"Hi there!";
}
Portability
3.1.4.29.53 wctomb
Header File
3 stdlib.h
Category
Prototype
int wctomb(char *s, wchar_t wc);
Description
1138
3.1 C++ Reference RAD Studio C Runtime Library Reference
If s is not null, wctomb determines the number of bytes needed to represent the multibyte character corresponding to wc
(including any change in shift state). The multibyte character is stored in s. At most MB_CUR_MAX characters are stored. If the
value of wc is zero, wctomb is left in the initial state.
The behavior of wctomb is affected by the setting of LC_CTYPE category of the current locale.
Return Value
If s is a NULL pointer, wctomb returns a nonzero value if multibyte character encodings do have state-dependent encodings, and
a zero value if they do not.
If s is not a NULL pointer, wctomb returns -1 if the wc value does not represent a valid multibyte character. Otherwise, wctomb
returns the number of bytes that are contained in the multibyte character corresponding to wc. In no case will the return value be
greater than the value of MB_CUR_MAX macro.
Example
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int x;
wchar_t wc = L'a';
char *pmbNULL = NULL;
char *pmb = (char *)malloc(sizeof( char ));
printf (" Convert a wchar_t array into a multibyte string:\n");
x = wctomb( pmb, wc);
printf ("Character converted: %u\n", x);
printf ("Multibyte string: %1s\n\n",pmb);
printf (" Convert when target is NULL\n");
x = wctomb( pmbNULL, wc);
printf ("Character converted: %u\n",x);
printf ("Multibyte stri ng: %1s\n\n",pmbNULL);
}
Portability
3.1.4.30 string.h
The following functions, macros, and classes are provided in string.h:
1139
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Topics
Name Description
_ismbblead, _ismbbtrail ( see page 1152) Header File
mbstring.h
Category
Classification Routines
Prototype
int _ismbblead(unsigned int c);
int _ismbbtrail(unsigned int c);
Description
_ismbblead and _ismbbtrail are used to test whether the argument c is the first or
the second byte of a multibyte character.
_ismbblead and _ismbbtrail are affected by the code page in use. You can set
the code page by using the _setlocale function.
Return Value
If c is in the lead byte of a multibyte character, _ismbblead returns true.
If c is in the trail byte of a multibyte character, _ismbbtrail returns a nonzero value.
_ismbclegal ( see page 1153) Header File
mbstring.h
Category
Classification Routines
Prototype
int _ismbclegal(unsigned int c);
Description
_ismbclegal tests whether each byte of the c argument is in the code page that is
currently in use.
Return Value
_ismbclegal returns a nonzero value if the argument c is a valid multibyte
character on the current code page. Otherwise, the function returns zero.
_ismbslead, _ismbstrail ( see page 1153) Header File
mbstring.h
Category
Classification Routines
Prototype
int _ismbslead(const unsigned char *s1, const unsigned char
*s2);
int _ismbstrail(const unsigned char *s1, const unsigned
char *s2);
Description
The _ismbslead and _ismbstrail functions test the s1 argument to determine
whether the s2 argument is a pointer to the lead byte or the trail byte. The test is
case-sensitive.
Return Value
The _ismbslead and _ismbstrail routines return -1 if s2 points to a lead byte or a
trail byte, respectively. If the test is false, the routines return zero.
_mbbtype ( see page 1154) Header File
mbstring.h
Category
Classification Routines
Prototype
int _mbbtype(unsigned char ch, int mode);
Description
The _mbbtype function inspects the multibyte argument, character ch, to
determine whether it is a single-byte character, or whether ch is the leadbyte or
3 trailing byte in a multibyte character. The _mbbtype function can determine
whether ch is an invalid character.
Return Value
The value that _mbbtype returns is one of the following manifest constants,
defined in mbctype.h. The return value depends on the value of ch and the test
which you want performed on ch.
1140
3.1 C++ Reference RAD Studio C Runtime Library Reference
1141
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1142
3.1 C++ Reference RAD Studio C Runtime Library Reference
1143
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1144
3.1 C++ Reference RAD Studio C Runtime Library Reference
1145
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1146
3.1 C++ Reference RAD Studio C Runtime Library Reference
1147
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1148
3.1 C++ Reference RAD Studio C Runtime Library Reference
strncoll, strnicoll, _mbsncoll, _mbsnicoll, _wcsncoll, _wcsnicoll ( see page 1175) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines
Prototype
int _strncoll(const char *s1, const char *s2, size_t n);
int _wcsncoll(const wchar_t *s1, const wchar_t *s2, size_t
n);
int _strnicoll(const char *s1, const char *s2, size_t n);
int _wcsnicoll(const wchar_t *s1, const wchar_t *s2, size_t
n);
int _mbsncoll(const unsigned char *s1, const unsigned char
*s2, size_t n);
int _mbsnicoll(const unsigned char *s1, const unsigned char
*s2, size_t n);
Description
_strncoll compares n number of elements from the string pointed to by s1 to the
string pointed to by s2, according to the current locale's LC_COLLATE category.
_strnicoll performs like... more ( see page 1175)
strncpy, _mbsncpy, wcsncpy ( see page 1176) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
Prototype
char *strncpy(char *dest, const char *src, size_t maxlen);
wchar_t *wcsncpy(wchar_t *dest, const wchar_t *src, size_t
maxlen);
unsigned char *_mbsncpy(unsigned char *dest, const unsigned
char *src, size_t maxlen);
Description
Copies a given number of bytes from one string into another, truncating or
padding as necessary.
strncpy copies up to maxlen characters from src into dest, truncating or
null-padding dest. The target string, dest, might not be null-terminated if the
length of src is maxlen or more.
Return Value
strncpy returns dest.
Example
strnicmp, _mbsnicmp, _wcsnicmp ( see page 1176) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines
Prototype
int strnicmp(const char *s1, const char *s2, size_t maxlen);
int _wcsnicmp(const wchar_t *s1, const wchar_t *s2, size_t
maxlen);
int _mbsnicmp(const unsigned char *s1, const unsigned char
*s2, size_t maxlen);
Description
Compares a portion of one string to a portion of another, without case sensitivity.
strnicmp performs a signed comparison of s1 to s2, for a maximum length of
maxlen bytes, starting with the first character in each string and continuing with
subsequent characters until the corresponding characters differ or until the end of
the strings is reached. The comparison... more ( see page 1176)
1149
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1150
3.1 C++ Reference RAD Studio C Runtime Library Reference
1151
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Classification Routines
Prototype
int _ismbblead(unsigned int c);
1152
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
_ismbblead and _ismbbtrail are used to test whether the argument c is the first or the second byte of a multibyte character.
_ismbblead and _ismbbtrail are affected by the code page in use. You can set the code page by using the _setlocale function.
Return Value
3.1.4.30.2 _ismbclegal
Header File
mbstring.h
Category
Classification Routines
Prototype
int _ismbclegal(unsigned int c);
Description
_ismbclegal tests whether each byte of the c argument is in the code page that is currently in use.
Return Value
_ismbclegal returns a nonzero value if the argument c is a valid multibyte character on the current code page. Otherwise, the
function returns zero.
mbstring.h
Category
Classification Routines
Prototype
int _ismbslead(const unsigned char *s1, const unsigned char *s2);
int _ismbstrail(const unsigned char *s1, const unsigned char *s2);
Description
3
The _ismbslead and _ismbstrail functions test the s1 argument to determine whether the s2 argument is a pointer to the lead
byte or the trail byte. The test is case-sensitive.
Return Value
The _ismbslead and _ismbstrail routines return -1 if s2 points to a lead byte or a trail byte, respectively. If the test is false, the
routines return zero.
1153
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.30.4 _mbbtype
Header File
mbstring.h
Category
Classification Routines
Prototype
int _mbbtype(unsigned char ch, int mode);
Description
The _mbbtype function inspects the multibyte argument, character ch, to determine whether it is a single-byte character, or
whether ch is the leadbyte or trailing byte in a multibyte character. The _mbbtype function can determine whether ch is an invalid
character.
Return Value
The value that _mbbtype returns is one of the following manifest constants, defined in mbctype.h. The return value depends on
the value of ch and the test which you want performed on ch.
3.1.4.30.5 _mbccpy
Header File
mbstring.h
Category
Prototype
void _mbccpy(unsigned char *dest, unsigned char *src);
Description
The _mbccpy function copies a multibyte character from src to dest. The _mbccpy function makes an implicit call to _ismbblead
so that the src pointer references a lead byte. If src doesn’t reference a lead byte, no copy is performed.
Return Value
None.
3.1.4.30.6 _mbsbtype
3 Header File
mbstring.h
Category
Classification Routines
Prototype
int _mbsbtype(const unsigned char *str, size_t nbyte);
1154
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
The nbyte argument specifies the number of bytes from the start of the zero-based string.
The _mbsbtype function inspects the argument str to determine whether the byte at the position specified by nbyte is a
single-byte character, or whether it is the leadbyte or trailing byte in a multibyte character. The _mbsbtype function can
determine whether the byte pointed at is an invalid character or a NULL byte.
Return Value
The value that _mbsbtype returns is one of the following manifest constants, defined in mbctype.h.
3.1.4.30.7 _mbsnbcmp
Header File
mbstring.h
Category
Prototype
int _mbsnbcmp(const unsigned char *s1, const unsigned char s2, size_t maxlen);
Description
_mbsnbcmp makes an case-sensitive comparison of s1 and s2 for no more than maxlen bytes. It starts with the first byte in each
string and continues with subsequent bytes until the corresponding bytes differ or until it has examined maxlen bytes.
Return Value
• _mbsnbcmp returns an integer value based on the result of comparing s1 (or part of it) to s2 (or part of it):
• < 0 if s1 is less than s2
• == 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
mbstring.h
3
Category
Prototype
size_t _mbsnbcnt(const unsigned char * str, size_t nmbc);
size_t _mbsnccnt(const unsigned char * str, size_t nbyte);
1155
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
If _MBCS is defined:
_tcsnbcnt and _tcsnccnt are mapped to the _strncnt macro _strncnt is the single-byte version of these functions. _wcsncnt is the
wide-character version of these functions.
_strncnt and _wcsncnt are available only for generic-text mappings. They should not be used directly.
_mbsnbcnt examines the first nmbc multibyte characters of the str argument. The function returns the number of bytes found in
the those characters.
_mbsnccnt examines the first nmbc bytes of the str argument. The function returns the number of characters found in those
bytes. If NULL is encountered in the second byte of a multibyte character, the whole character is considered NULL and will not
be included in the return value.
Each of the functions ends its examination of the str argument if NULL is reached before the specified number of characters or
bytes is examined.
If str has fewer than the specified number of characters or bytes, the function return the number of characters or bytes found in
str.
Return Value
mbstring.h
Category
Prototype
int _mbsnbcoll(const unsigned char *s1, const unsigned char *s2, maxlen);
int _mbsnbicoll(const unsigned char *s1, const unsigned char *s2, maxlen);
3 Description
These functions collate the strings specified by arguments s1 and s2. The collation order is determined by lexicographic order as
specified by the current multibyte code page. At most, maxlen number of bytes are collated.
Note: Note:
The lexicographic order is not always the same as the order of characters in the character set.If the last byte in s1 or s2 is a
1156
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
• Each of these functions return an integer value based on the result of comparing s1 (or part of it) to s2 (or part of it):
• < 0 if s1 is less than s2
• == 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
On error, each of these functions returns _NLSCMPERROR.
3.1.4.30.10 _mbsnbcpy
Header File
mbstring.h
Category
Prototype
unsigned char *_mbsnbcpy(unsigned char *dest, unsigned char *src, size_t maxlen);
Description
The _mbsnbcpy function copies at most maxlen number of characters from the src buffer to the dest buffer. The dest buffer is
null terminated after the copy.
It is the user’s responsibility to be sure that dest is large enough to allow the copy. An improper buffer size can result in memory
corruption.
Return Value
3.1.4.30.11 _mbsnbicmp
Header File
mbstring.h
Category
Prototype
int _mbsnbicmp(const unsigned char *s1, const unsigned char s2, size_t maxlen);
Description 3
_mbsnbicmp ignores case while making a comparison of s1 and s2 for no more than maxlen bytes. It starts with the first byte in
each string and continues with subsequent bytes until the corresponding bytes differ or until it has examined maxlen bytes.
1157
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
• _mbsnbicmp returns an integer value based on the result of comparing s1 (or part of it) to s2 (or part of it):
• < 0 if s1 is less than s2
• == 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
3.1.4.30.12 _mbsnbset
Header File
mbstring.h
Category
Prototype
unsigned char *_mbsnbset(unsigned char str, unsigned int ch, size_t maxlen);
Description
_mbsnbset sets at most maxlen number of bytes in the string str to the character ch. The argument ch can be a single or
multibyte character.
The function quits if the terminating null character is found before maxlen is reached. If ch is a multibyte character that cannot be
accomodated at the end of str, the last character in str is set to a blank character.
Return Value
mbstring.h
Category
Prototype
unsigned char *_mbsninc(const unsigned char *str, size_t num);
Description
The functions increment the character array str by num number of characters.
3 These functions should be accessed through the portable macro, _tcsninc, defined in tchar.h.
Return value
The functions return a pointer to the resized character string specified by the argument str.
1158
3.1 C++ Reference RAD Studio C Runtime Library Reference
mbstring.h
Category
Prototype
unsigned char *_mbsspnp(const unsigned char *s1, const unsigned char *s2);
Description
Each of these functions search for the first character in s1 that is not contained in s2.
Use the portable macro, _tcsspnp, defined in tchar.h, to access these functions.
Return Value
The functions return a pointer to the first character in s1 that is not found in the character set for s2.
If every character from s1 is found in s2, each of the functions return NULL.
mbstring.h, tchar.h
Category
Prototype
unsigned char *_mbsdec(const unsigned char *s, const unsigned char *p);
inline char *_strdec(const char * s1, const char * s2) { return (char *)(s1,(s2-1));
// From tchar.h
#define _tcsdec _strdec
#define _tcsdec _wcsdec
Description
_mbsdec returns a pointer p indicating the character in string s back to 1 byte backward. If there are no more characters before
string p (it is the same position as s), _mbsdec returns a null pointer.
Return Value
3.1.4.30.16 _strerror
Header File
string.h, stdio.h
Category
1159
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Prototype
char *_strerror(const char *s);
Description
_strerror lets you generate customized error messages; it returns a pointer to a null-terminated string containing an error
message.
• If s is null, the return value points to the most recent error message.
• If s is not null, the return value contains s (your customized error message), a colon, a space, the most-recently generated
system error message, and a new line. s should be 94 characters or less.
Return Value
_strerror returns a pointer to a constructed error string. The error message string is constructed in a static buffer that is
overwritten with each call to _strerror.
Example
#include <stdio.h>
#include <errno.h>
int main(void)
{
char *buffer;
buffer = strerror(errno);
printf("Error: %s\n", buffer);
return 0;
}
Portability
mbstring.h, tchar.h
Category
Prototype
unsigned char *_mbsinc(const unsigned char *p);
// From tchar.h
3
#define _tcsinc _strinc
#define _tcsinc _wcsinc
inline char * strinc(const char * s) { return (char *)(s+1); }
Description
1160
3.1 C++ Reference RAD Studio C Runtime Library Reference
Return Value
3.1.4.30.18 _strnextc,_mbsnextc,_wcsnextc
Header File
tchar.h, mbstring.h
Category
Prototype
unsigned int _strnextc(const char *str);
unsigned int _mbsnextc (const unsigned char *str);
Description
These routines should be accessed by using the portable _tcsnextc function. The functions inspect the current character in str.
The pointer to str is not advanced.
Return Value
The functions return the integer value of the character pointed to by str.
Example
#include <tchar.h>
#include <stdio.h>
int main()
{
unsigned int retval = 0;
const unsigned char *string = "ABC";
retval = _strnextc(string);
printf("The starting character:%c", retval);
retval = _strnextc(++string);
printf("\nThe next character:%c", retval);
return 0;
}
/***
The starting character:A
The next character:B
***/
Category
Prototype
char *stpcpy(char *dest, const char *src);
1161
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
_stpcpy copies the string src to dest, stopping after the terminating null character of src has been reached.
Return Value
If UNICODE is defined, _wcspcpy returns a pointer to the terminating null character of the wchar_t dest string.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[10];
char *str1 = "abcdefghi";
stpcpy(string, str1);
printf("%s\n", string);
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
char *strcat(char *dest, const char *src);
wchar_t *wcscat(wchar_t *dest, const wchar_t *src);
unsigned char *_mbscat(unsigned char *dest, const unsigned char *src);
Description
Return Value
Example
#include <string.h>
#include <stdio.h>
1162
3.1 C++ Reference RAD Studio C Runtime Library Reference
int main(void)
{
char destination[25];
char *blank = " ", *c = "C++", *CodeGear = "CodeGear";
strcpy(destination, CodeGear);
strcat(destination, blank);
strcat(destination, c);
printf("%s\n", destination);
return 0;
}
Portability
string.h
Category
Memory and String Manipulation Routines, Inline Routines, C++ Prototyped Routines
Prototype
char *strchr(const char *s, int c);/* C only */
const char *strchr(const char *s, int c);// C++ only
char *strchr( char *s, int c);// C++ only
wchar_t *wcschr(const wchar_t *s, int c);
unsigned char * _mbschr(const unsigned char *s, unsigned int c);
Description
strchr scans a string in the forward direction, looking for a specific character. strchr finds the first occurrence of the character c in
the string s. The null-terminator is considered to be part of the string.
For example:
strchr(strs,0)
Return Value 3
strchr returns a pointer to the first occurrence of the character c in s; if c does not occur in s, strchr returns null.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char string[15];
1163
C Runtime Library Reference RAD Studio 3.1 C++ Reference
string.h, mbstring.h
Category
Prototype
int strcmp(const char *s1, const char *s2);
int wcscmp(const wchar_t *s1, const wchar_t *s2);
int _mbscmp(const unsigned char *s1, const unsigned char *s2);
Description
strcmp performs an unsigned comparison of s1 to s2, starting with the first character in each string and continuing with
subsequent characters until the corresponding characters differ or until the end of the strings is reached.
Return Value
Example
3 #include <string.h>
#include <stdio.h>
int main(void)
{
char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc";
int ptr;
ptr = strcmp(buf2, buf1);
if (ptr > 0)
printf("buffer 2 is greater than buffer 1\n");
else
printf("buffer 2 is less than buffer 1\n");
1164
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.30.23 strcmpi
Header File
string.h, wchar.h
Category
Prototype
int strcmpi(const char *s1, const char *s2);
int _wcscmpi(const wchar_t *s1, const wchar_t *s2);
Description
strcmpi performs an unsigned comparison of s1 to s2, without case sensitivity (same as stricmp--implemented as a macro).
It returns a value (< 0, 0, or > 0) based on the result of comparing s1 (or part of it) to s2 (or part of it).
The routine strcmpi is the same as stricmp. strcmpi is implemented through a macro in string.h and translates calls from strcmpi
to stricmp. Therefore, in order to use strcmpi, you must include the header file string.h for the macro to be available. This macro
is provided for compatibility with other C compilers.
Return Value
Example 3
/* strncmpi example */
#include <string.h>
#include <stdio.h>
int main(void)
{
char *buf1 = "BBB", *buf2 = "bbb";
int ptr;
ptr = strcmpi(buf2, buf1);
if (ptr > 0)
1165
C Runtime Library Reference RAD Studio 3.1 C++ Reference
string.h, mbstring.h
Category
Prototype
int strcoll(const char *s1, const char *s2);
int wcscoll(const wchar_t *s1, const wchar_t *s2);
int _stricoll(const char *s1, const char *s2);
int _wcsicoll(const wchar_t *s1, wconst_t char *s2);
int _mbscoll(const unsigned char *s1, const unsigned char *s2);
int _mbsicoll(const unsigned char *s1, const unsigned char *s2);
Description
strcoll compares the string pointed to by s1 to the string pointed to by s2, according to the current locale's LC_COLLATE
category.
Note: Note
_stricoll does not compare string according to the current locale's LC_COLLATE category. _stricoll gives you a stricmp. The
required collation is obtained by calling _lstricoll, or just plain stricoll (which maps to _lstricoll).
The real collation (_lstricoll) returns -1, 0 or 1, whereas _stricoll does a codepoint comparison, and returns < 0, 0 or > 0.
3
Return Value
Example
1166
3.1 C++ Reference RAD Studio C Runtime Library Reference
#include <stdio.h>
#include <string.h>
int main(void)
{
char *two = "International";
char *one = "Borland";
int check;
check = strcoll(one, two);
if (check == 0)
printf("The strings are equal\n");
if (check < 0)
printf("%s comes before %s\n", one, two);
if (check > 0)
printf("%s comes before %s\n", two, one);
return 0;
}
Portability
3.1.4.30.25 strcpy
Header File
Category
Prototype
char *strcpy(char *dest, const char *src);
wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
unsigned char *_mbscpy(unsigned char *dest, const unsigned char *src);
Description
Copies string src to dest, stopping after the terminating null character has been moved.
3
Return Value
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
1167
C Runtime Library Reference RAD Studio 3.1 C++ Reference
char string[10];
char *str1 = "abcdefghi";
strcpy(string, str1);
printf("%s\n", string);
return 0;
}
Portability
Category
Prototype
size_t strcspn(const char *s1, const char *s2);
size_t wcscspn(const wchar_t *s1, const wchar_t *s2);
size_t _mbscspn(const unsigned char *s1, const unsigned char *s2);
Description
Scans a string for the initial segment not containing any subset of a given set of characters.
The strcspn functions search s1 until any one of the characters contained in s2 is found. The number of characters which were
read in s1 is the return value. The string termination character is not counted. Neither string is altered during the search.
Return Value
strcspn returns the length of the initial segment of string s1 that consists entirely of characters not from string s2.
Example
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
char *string1 = "1234567890";
char *string2 = "747DC8";
3 int length;
length = strcspn(string1, string2);
printf("Character where strings intersect is at position %d\n",
length);
return 0;
}
Portability
1168
3.1 C++ Reference RAD Studio C Runtime Library Reference
string.h, mbstring.h
Category
Prototype
char *strdup(const char *s);
wchar_t *_wcsdup(const wchar_t *s);
unsigned char *_mbsdup(const wchar_t *s);
Description
strdup makes a duplicate of string s, obtaining space with a call to malloc. The allocated space is (strlen(s) + 1) bytes long. The
user is responsible for freeing the space allocated by strdup when it is no longer needed.
Return Value
strdup returns a pointer to the storage location containing the duplicated string, or returns null if space could not be allocated.
Example
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
char *dup_str, *string = "abcde";
dup_str = strdup(string);
printf("%s\n", dup_str);
free(dup_str);
return 0;
}
Portability
1169
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.30.28 strerror
Header File
string.h
Category
Prototype
char *strerror(int errnum);
Description
strerror takes an int parameter errnum, an error number, and returns a pointer to an error message string associated with
errnum.
Return Value
strerror returns a pointer to a constructed error string. The error message string is constructed in a static buffer that is overwritten
with each call to strerror.
Example
#include <stdio.h>
#include <errno.h>
int main(void)
{
char *buffer;
buffer = strerror(errno);
printf("Error: %s\n", buffer);
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
int stricmp(const char *s1, const char *s2);
int _wcsicmp(const wchar_t *s1, const wchar_t *s2);
int _mbsicmp(const unsigned char *s1, const unsigned char *s2);
Description
1170
3.1 C++ Reference RAD Studio C Runtime Library Reference
stricmp performs an unsigned comparison of s1 to s2, starting with the first character in each string and continuing with
subsequent characters until the corresponding characters differ or until the end of the strings is reached. The comparison is not
case sensitive.
It returns a value (< 0, 0, or > 0) based on the result of comparing s1 (or part of it) to s2 (or part of it).
The routines stricmp and strcmpi are the same; strcmpi is implemented through a macro in string.h that translates calls from
strcmpi to stricmp. Therefore, in order to use stricmp, you must include the header file string.h for the macro to be available.
Return Value
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char *buf1 = "BBB", *buf2 = "bbb";
int ptr;
ptr = stricmp(buf2, buf1);
if (ptr > 0)
printf("buffer 2 is greater than buffer 1\n");
if (ptr < 0)
printf("buffer 2 is less than buffer 1\n");
if (ptr == 0)
printf("buffer 2 equals buffer 1\n");
return 0;
}
Portability
string.h, mbstring.h
Category
3
Conversion Routines, Memory and String Manipulation Routines
Prototype
char *strlwr(char *s);
wchar_t *_wcslwr(wchar_t *s);
unsigned char *_mbslwr(unsigned char *s);
1171
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Description
strlwr converts uppercase letters in string s to lowercase according to the current locale's LC_CTYPE category. For the C locale,
the conversion is from uppercase letters (A to Z) to lowercase letters (a to z). No other characters are changed.
Return Value
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *string = "CodeGear";
printf("string prior to strlwr: %s\n", string);
strlwr(string);
printf("string after strlwr: %s\n", string);
return 0;
}
Portability
3.1.4.30.31 strncat
Header File
string.h, mbstring.h
Category
Prototype
char *strncat(char *dest, const char *src, size_t maxlen);
wchar_t *wcsncat(wchar_t *dest, const wchar_t *src, size_t maxlen);
unsigned char *_mbsncat(unsigned char *dest, const unsigned char *src, size_t maxlen);
unsigned char *_mbsnbcat(unsigned char *__dest, const unsigned char *__src, _SIZE_T __maxlen);
Description
3 Appends a portion of one string to another.
strncat copies at most maxlen characters of src to the end of dest and then appends a null character. The maximum length of the
resulting string is strlen(dest) + maxlen.
For _mbsnbcat, if the second byte of 2-bytes character is null, the first byte of this character is regarded as null.
These four functions behave identically and differ only with respect to the type of arguments and return types.
Return Value
1172
3.1 C++ Reference RAD Studio C Runtime Library Reference
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char destination[25];
char *source = " States";
strcpy(destination, "United");
strncat(destination, source, 7);
printf("%s\n", destination);
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
int strncmp(const char *s1, const char *s2, size_t maxlen);
int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t maxlen);
int _mbsncmp(const unsigned char *s1, const unsigned char *s2, size_t maxlen);
#define _mbccmp(__s1, __s2) _mbsncmp((__s1),(__s2),1)
Description
strncmp makes the same unsigned comparison as strcmp, but looks at no more than maxlen characters. It starts with the first
character in each string and continues with subsequent characters until the corresponding characters differ or until it has
examined maxlen characters.
3
Return Value
• strncmp returns an int value based on the result of comparing s1 (or part of it) to s2 (or part of it):
• < 0 if s1 is less than s2
• == 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
Example
1173
C Runtime Library Reference RAD Studio 3.1 C++ Reference
#include <string.h>
#include <stdio.h>
int main(void)
{
char *buf1 = "aaabbb", *buf2 = "bbbccc", *buf3 = "ccc";
int ptr;
ptr = strncmp(buf2,buf1,3);
if (ptr > 0)
printf("buffer 2 is greater than buffer 1\n");
else
printf("buffer 2 is less than buffer 1\n");
ptr = strncmp(buf2,buf3,3);
if (ptr > 0)
printf("buffer 2 is greater than buffer 3\n");
else
printf("buffer 2 is less than buffer 3\n");
return(0);
}
Portability
string.h
Category
Prototype
int strncmpi(const char *s1, const char *s2, size_t n);
int wcsncmpi(const wchar_t *s1, const wchar_t *s2, size_t n);
Description
strncmpi performs a signed comparison of s1 to s2, for a maximum length of n bytes, starting with the first character in each
string and continuing with subsequent characters until the corresponding characters differ or until n characters have been
examined. The comparison is not case sensitive. (strncmpi is the same as strnicmp--implemented as a macro). It returns a value
3 (< 0, 0, or > 0) based on the result of comparing s1 (or part of it) to s2 (or part of it).
The routines strnicmp and strncmpi are the same; strncmpi is implemented through a macro in string.h that translates calls from
strncmpi to strnicmp. Therefore, in order to use strncmpi, you must include the header file string.h for the macro to be available.
This macro is provided for compatibility with other C compilers.
Return Value
1174
3.1 C++ Reference RAD Studio C Runtime Library Reference
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char *buf1 = "BBBccc", *buf2 = "bbbccc";
int ptr;
ptr = strncmpi(buf2,buf1,3);
if (ptr > 0)
printf("buffer 2 is greater than buffer 1\n");
if (ptr < 0)
printf("buffer 2 is less than buffer 1\n");
if (ptr == 0)
printf("buffer 2 equals buffer 1\n");
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
int _strncoll(const char *s1, const char *s2, size_t n);
int _wcsncoll(const wchar_t *s1, const wchar_t *s2, size_t n);
int _strnicoll(const char *s1, const char *s2, size_t n);
int _wcsnicoll(const wchar_t *s1, const wchar_t *s2, size_t n);
int _mbsncoll(const unsigned char *s1, const unsigned char *s2, size_t n);
int _mbsnicoll(const unsigned char *s1, const unsigned char *s2, size_t n); 3
Description
_strncoll compares n number of elements from the string pointed to by s1 to the string pointed to by s2, according to the current
locale's LC_COLLATE category.
Return Value
1175
C Runtime Library Reference RAD Studio 3.1 C++ Reference
string.h, mbstring.h
Category
Prototype
char *strncpy(char *dest, const char *src, size_t maxlen);
wchar_t *wcsncpy(wchar_t *dest, const wchar_t *src, size_t maxlen);
unsigned char *_mbsncpy(unsigned char *dest, const unsigned char *src, size_t maxlen);
Description
Copies a given number of bytes from one string into another, truncating or padding as necessary.
strncpy copies up to maxlen characters from src into dest, truncating or null-padding dest. The target string, dest, might not be
null-terminated if the length of src is maxlen or more.
Return Value
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[10];
char *str1 = "abcdefghi";
strncpy(string, str1, 3);
string[3] = '\0';
printf("%s\n", string);
return 0;
}
Portability
1176
3.1 C++ Reference RAD Studio C Runtime Library Reference
string.h, mbstring.h
Category
Prototype
int strnicmp(const char *s1, const char *s2, size_t maxlen);
int _wcsnicmp(const wchar_t *s1, const wchar_t *s2, size_t maxlen);
int _mbsnicmp(const unsigned char *s1, const unsigned char *s2, size_t maxlen);
Description
strnicmp performs a signed comparison of s1 to s2, for a maximum length of maxlen bytes, starting with the first character in
each string and continuing with subsequent characters until the corresponding characters differ or until the end of the strings is
reached. The comparison is not case sensitive.
It returns a value (< 0, 0, or > 0) based on the result of comparing s1 (or part of it) to s2 (or part of it).
Return Value
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char *buf1 = "BBBccc", *buf2 = "bbbccc";
int ptr;
ptr = strnicmp(buf2, buf1, 3);
if (ptr > 0)
printf("buffer 2 is greater than buffer 1\n");
if (ptr < 0)
printf("buffer 2 is less than buffer 1\n");
if (ptr == 0)
printf("buffer 2 equals buffer 1\n");
return 0;
}
Portability
string.h
1177
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Prototype
char *strnset(char *s, int ch, size_t n);
wchar_t *_wcsnset(wchar_t *s, wchar_t ch, size_t n);
unsigned char *_mbsnset(unsigned char *s, unsigned int ch, size_t n);
Description
strnset copies the character ch into the first n bytes of the string s. If n > strlen(s), then strlen(s) replaces n. It stops when n
characters have been set, or when a null character is found.
Return Value
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *string = "abcdefghijklmnopqrstuvwxyz";
char letter = 'x';
printf("string before strnset: %s\n", string);
strnset(string, letter, 13);
printf("string after strnset: %s\n", string);
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
char *strpbrk(const char *s1, const char *s2); /* C only */
const char *strpbrk(const char *s1, const char *s2); // C++ only
char *strpbrk(char *s1, const char *s2); // C++ only
wchar_t * wcspbrk(const wchar_t *s1, const wchar_t *s2);
1178
3.1 C++ Reference RAD Studio C Runtime Library Reference
unsigned char *_mbspbrk(const unsigned char *s1, const unsigned char *s2);
Description
Scans a string for the first occurrence of any character from a given set.
strpbrk scans a string, s1, for the first occurrence of any character appearing in s2.
Return Value
strpbrk returns a pointer to the first occurrence of any of the characters in s2. If none of the s2 characters occur in s1, strpbrk
returns null.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *string1 = "abcdefghijklmnopqrstuvwxyz";
char *string2 = "onm";
char *ptr;
ptr = strpbrk(string1, string2);
if (ptr)
printf("strpbrk found first character: %c\n", *ptr);
else
printf("strpbrk didn't find character in set\n");
return 0;
}
Portability
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines, C++ Prototyped Routines
Prototype
char *strrchr(const char *s, int c); /* C only */
const char *strrchr(const char *s, int c); // C++ only
3
char *strrchr(char *s, int c); // C++ only
wchar_t *wcsrchr(const wchar_t *s, wchar_t c);
unsigned char * _mbsrchr(const unsigned char *s, unsigned int c);
Description
strrchr scans a string in the reverse direction, looking for a specific character. strrchr finds the last occurrence of the character c
1179
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
strrchr returns a pointer to the last occurrence of the character c. If c does not occur in s, strrchr returns null.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char string[15];
char *ptr, c = 'r';
strcpy(string, "This is a string");
ptr = strrchr(string, c);
if (ptr)
printf("The character %c is at position: %d\n", c, ptr-string);
else
printf("The character was not found\n");
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
char *strrev(char *s);
wchar_t *_wcsrev(wchar_t *s);
unsigned char *_mbsrev(unsigned char *s);
Description
Reverses a string.
strrev changes all characters in a string to reverse order, except the terminating null character. (For example, it would change
3
string\0 to gnirts\0.)
Return Value
Example
#include <string.h>
#include <stdio.h>
1180
3.1 C++ Reference RAD Studio C Runtime Library Reference
int main(void)
{
char *forward = "string";
printf("Before strrev(): %s\n", forward);
strrev(forward);
printf("After strrev(): %s\n", forward);
return 0;
}
Portability
string.h, mbstring.h
Category
Prototype
char *strset(char *s, int ch);
wchar_t *_wcsset(wchar_t *s, wchar_t ch);
unsigned char *_mbsset(unsigned char *s, unsigned int ch);
Description
strset sets all characters in the string s to the character ch. It quits when the terminating null character is found.
Return Value
strset returns s.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[10] = "123456789";
char symbol = 'c';
printf("Before strset(): %s\n", string);
strset(string, symbol); 3
printf("After strset(): %s\n", string);
return 0;
}
Portability
1181
C Runtime Library Reference RAD Studio 3.1 C++ Reference
_mbsset +
_wcsset +
string.h, mbstring.h
Category
Prototype
size_t strspn(const char *s1, const char *s2);
size_t wcsspn(const wchar_t *s1, const wchar_t *s2);
size_t _mbsspn(const unsigned char *s1, const unsigned char *s2);
Description
Scans a string for the first segment that is a subset of a given set of characters.
strspn finds the initial segment of string s1 that consists entirely of characters from string s2.
Return Value
strspn returns the length of the initial segment of s1 that consists entirely of characters from s2.
Example
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
char *string1 = "1234567890";
char *string2 = "123DC8";
int length;
length = strspn(string1, string2);
printf("Character where strings differ is at position %d\n", length);
return 0;
}
Portability
string.h
1182
3.1 C++ Reference RAD Studio C Runtime Library Reference
Category
Prototype
char *strstr(const char *s1, const char *s2); /* C only */
const char *strstr(const char *s1, const char *s2); // C++ only
char *strstr(char *s1, const char *s2); // C++ only
wchar_t * wcsstr(const wchar_t *s1, const wchar_t *s2);
unsigned char * _mbsstr(const unsigned char *s1, const unsigned char *s2);
Description
Return Value
strstr returns a pointer to the element in s1, where s2 begins (points to s2 in s1). If s2 does not occur in s1, strstr returns null.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *str1 = "CodeGear", *str2 = "nation", *ptr;
ptr = strstr(str1, str2);
printf("The substring is: %s\n", ptr);
return 0;
}
Portability
string.h, mbstring.h
Category
Description
1183
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Searches one string for tokens, which are separated by delimiters defined in a second string.
strtok considers the string s1 to consist of a sequence of zero or more text tokens, separated by spans of one or more characters
from the separator string s2.
The first call to strtok returns a pointer to the first character of the first token in s1 and writes a null character into s1 immediately
following the returned token. Subsequent calls with null for the first argument will work through the string s1 in this way, until no
tokens remain.
Note: Calls to strtok cannot be nested with a function call that also uses strtok. Doing so will causes an endless loop.
Return Value
strtok returns a pointer to the token found in s1. A NULL pointer is returned when there are no more tokens.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char input[16] = "abc,d";
char *p;
/* strtok places a NULL terminator
in front of the token, if found */
p = strtok(input, ",");
if (p) printf("%s\n", p);
/* A second call to strtok using a NULL
as the first parameter returns a pointer
to the character following the token */
p = strtok(NULL, ",");
if (p) printf("%s\n", p);
return 0;
}
Portability
string.h, mbstring.h
Category
3
Conversion Routines, Memory and String Manipulation Routines
Prototype
char *strupr(char *s);
wchar_t *_wcsupr(wchar_t *s);
unsigned char *_mbsupr(unsigned char *s);
1184
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
strupr converts lowercase letters in string s to uppercase according to the current locale's LC_CTYPE category. For the default C
locale, the conversion is from lowercase letters (a to z) to uppercase letters (A to Z). No other characters are changed.
Return Value
strupr returns s.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *string = "abcdefghijklmnopqrstuvwxyz", *ptr;
/* converts string to upper case characters */
ptr = strupr(string);
printf("%s\n", ptr);
return 0;
}
Portability
string.h
Category
Prototype
size_t strxfrm(char *target, const char *source, size_t n);
size_t wcsxfrm(wchar_t *target, const wchar_t *source, size_t n);
Description
strxfrm transforms the string pointed to by source into the string target for no more than n characters. The transformation is such
that if the strcmp function is applied to the resulting strings, its return corresponds with the return values of the strcoll function. 3
No more than n characters, including the terminating null character, are copied to target.
strxfrm transforms a character string into a special string according to the current locale's LC_COLLATE category. The special
string that is built can be compared with another of the same type, byte for byte, to achieve a locale-correct collation result.
These special strings, which can be thought of as keys or tokenized strings, are not compatible across the different locales.
The tokens in the tokenized strings are built from the collation weights used by strcoll from the active locale's collation tables.
1185
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Processing stops only after all levels have been processed for the character string or the length of the tokenized string is equal to
the maxlen parameter.
All redundant tokens are removed from each level's set of tokens.
The tokenized string buffer must be large enough to contain the resulting tokenized string. The length of this buffer depends on
the size of the character string, the number of collation levels, the rules for each level and whether there are any special
characters in the character string. Certain special characters can cause extra character processing of the string resulting in more
space requirements. For example, the French character "oe" will take double the space for itself because in some locales, it
expands to collation weights for each level. Substrings that have substitutions will also cause extra space requirements.
There is no safe formula to determine the required string buffer size, but at least (levels * string length) are required.
Return Value
Number of characters copied not including the terminating null character. If the value returned is greater than or equal to n, the
content of target is indeterminate.
Example
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
char *target;
char *source = "Frank Borland";
int length;
/* allocate space for the target string */
target = (char *) calloc(80, sizeof(char));
/* copy the source over to the target and get the length */
length = strxfrm(target, source, 80);
/* print out the results */
printf("%s has the length %d\n", target, length);
return 0;
}
Portability
3.1.4.31 sys\stat.h
The following functions, macros, and classes are provided in sys\stat.h:
Topics
Name Description
3 S_Ixxxx #defines ( see page 1187) Header File
sys\stat.h
Description
Definitions used for file status and directory functions.
1186
3.1 C++ Reference RAD Studio C Runtime Library Reference
sys\stat.h
Description
Name Meaning
S_IFMT File type mask 3
S_IFDIR Directory
S_IFIFO FIFO special
S_IFCHR Character special
S_IFBLK Block special
S_IFREG Regular file
1187
C Runtime Library Reference RAD Studio 3.1 C++ Reference
sys\stat.h, tchar.h
Category
Prototype
int stati64(const char *pathname, struct stati64 *buff);
int _stati64(const char *__path, struct stati64 *__statbuf);
int _wstati64(const wchar_t *pathname, struct stati64 *buff);
// From tchar.h
#define _tstati64 _stati64
Description
Gather statistics about the file named by *pathP and place them in the buffer *bufP.
st_ino0
st_nlink1
st_uid0
st_gid0
st_rdevsame as st_dev
st_mtimesame as st_atime
st_ctimesame as st_atime
3
The file access rights bit-set may contain S_IFCHR, S_IFDIR, S_IFREG, S_IREAD, S_IWRITE, or S_IEXEC.
If the name is for a device, the time fields will be zero and the size field is undefined.
Return Value
The return value is 0 if the call was successful, otherwise -1 is returned and errno contains the reason. The buffer is not touched
unless the call is successful.
Portability
1188
3.1 C++ Reference RAD Studio C Runtime Library Reference
sys\stat.h
Category
Input/output Routines
Prototype
int fstat(int handle, struct stat *statbuf);
int stat(const char *path, struct stat *statbuf);
int _wstat(const wchar_t *path, struct stat *statbuf);
Description
fstat stores information in the stat structure about the file or directory associated with handle.
stat stores information about a given file or directory in the stat structure. The name of the file is path.
statbuf points to the stat structure (defined in sys\stat.h). That structure contains the following fields:
The stat structure contains three more fields not mentioned here. They contain values that are meaningful only in UNIX.
The st_mode bit mask that gives information about the mode of the open file includes the following bits:
The HPFS and NTFS file-management systems make the following distinctions:
1189
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
fstat and stat return 0 if they successfully retrieved the information about the open file.
On error (failure to get the information) these functions return -1 and set the global variable errno to
Example
#include <sys\stat.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
struct stat statbuf;
FILE *stream;
/* open a file for update */
if ((stream = fopen("DUMMY.FIL", "w+"))
== NULL)
{
fprintf(stderr, "Cannot open output file.\n");
return(1);
}
fprintf(stream, "This is a test");
fflush(stream);
/* get information about the file */
fstat(fileno(stream), &statbuf);
fclose(stream);
/* display the information returned */
if (statbuf.st_mode & S_IFCHR)
printf("Handle refers to a device.\n");
if (statbuf.st_mode & S_IFREG)
printf("Handle refers to an ordinary file.\n");
if (statbuf.st_mode & S_IREAD)
printf("User has read permission on file.\n");
if (statbuf.st_mode & S_IWRITE)
printf("User has write permission on file.\n");
printf("Drive letter of file: %c\n", 'A'+statbuf.st_dev);
printf("Size of file in bytes: %ld\n", statbuf.st_size);
printf("Time file last opened: %s\n", ctime(&statbuf.st_ctime));
return 0;
}
3.1.4.32 sys\timeb.h
3 The following functions, macros, and classes are provided in sys\timeb.h:
1190
3.1 C++ Reference RAD Studio C Runtime Library Reference
Topics
Name Description
ftime ( see page 1191) Header File
sys\timeb.h
Category
Time and Date Routines
Prototype
void ftime(struct timeb *buf)
Description
Stores current time in timeb structure.
On UNIX platforms ftime is available only on System V systems.
ftime determines the current time and fills in the fields in the timeb structure
pointed to by buf. The timeb structure contains four fields: time, millitm,
_timezone, and dstflag:
struct timeb {
long time ;
short millitm ;
short _timezone ;
short dstflag ;
};
3.1.4.32.1 ftime
Header File
sys\timeb.h
Category
Prototype
void ftime(struct timeb *buf)
Description
ftime determines the current time and fills in the fields in the timeb structure pointed to by buf. The timeb structure contains four
fields: time, millitm, _timezone, and dstflag:
struct timeb {
long time ;
short millitm ; 3
short _timezone ;
short dstflag ;
};
• timeprovides the time in seconds since 00:00:00 Greenwich mean time (GMT) January 1 1970.
• millitmis the fractional part of a second in milliseconds.
1191
C Runtime Library Reference RAD Studio 3.1 C++ Reference
• _timezoneis the difference in minutes between GMT and the local time. This value is computed going west from GMT. ftime
gets this field from the global variable _timezone which is set by tzset.
• dstflagis set to nonzero if daylight saving time is taken into account during time calculations.
Note: ftime calls tzset. Therefore it isn't necessary to call tzset explicitly when you use ftime.
Return Value
None.
Example
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys\timeb.h>
/* pacific standard & daylight savings */
char *tzstr = "TZ=PST8PDT";
int main(void)
{
struct timeb t;
putenv(tzstr);
tzset();
ftime(&t);
printf("Seconds since 1/1/1970 GMT: %ld\n", t.time);
printf("Thousandths of a second: %d\n", t.millitm);
printf("Difference between local time and GMT: %d\n", t._timezone);
printf("Daylight savings in effect (1) not (0): %d\n", t.dstflag);
return 0;
}
Portability
3.1.4.33 sys\types.h
The following functions, macros, and classes are provided in sys\types.h:
Topics
Name Description
time_t ( see page 1192) Header File
sys\types.h
time.h
Syntax
typedef long time_t;
Description
Defines the value used by the time functions declared in time.h.
3 3.1.4.33.1 time_t
Header File
sys\types.h
time.h
Syntax
typedef long time_t;
1192
3.1 C++ Reference RAD Studio C Runtime Library Reference
Description
3.1.4.34 time.h
The following functions, macros, and classes are provided in time.h:
Topics
Name Description
_strdate, _wstrdate ( see page 1197) Header File
time.h
Category
Conversion Routines, Time and Date Routines
Prototype
char *_strdate(char *buf);
wchar_t *_wstrdate(wchar_t *buf);
Description
Converts current date to string.
_strdate converts the current date to a string, storing the string in the buffer buf.
The buffer must be at least 9 characters long.
The string has the form MM/DD/YY where MM, DD, and YY are all two-digit
numbers representing the month, day, and year. The string is terminated by a
null character.
Return Value
_strdate returns buf, the address of the date string.
Example
_strtime, _wstrtime ( see page 1198) Header File
time.h
Category
Time and Date Routines
Prototype
char *_strtime(char *buf);
wchar_t *_wstrtime(wchar_t *buf);
Description
Converts current time to string.
_strtime converts the current time to a string, storing the string in the buffer buf.
The buffer must be at least 9 characters long.
The string has the following form:
HH:MM:SS
where HH, MM, and SS are all two-digit numbers representing the hour, minute,
and second, respectively. The string is terminated by a null character.
Return Value
_strtime returns buf, the address of the time string.
Example
1193
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1194
3.1 C++ Reference RAD Studio C Runtime Library Reference
1195
C Runtime Library Reference RAD Studio 3.1 C++ Reference
1196
3.1 C++ Reference RAD Studio C Runtime Library Reference
time.h
1197
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Category
Prototype
char *_strdate(char *buf);
wchar_t *_wstrdate(wchar_t *buf);
Description
_strdate converts the current date to a string, storing the string in the buffer buf. The buffer must be at least 9 characters long.
The string has the form MM/DD/YY where MM, DD, and YY are all two-digit numbers representing the month, day, and year. The
string is terminated by a null character.
Return Value
Example
#include <time.h>
#include <stdio.h>
void main(void)
{
char datebuf[9];
char timebuf[9];
_strdate(datebuf);
_strtime(timebuf);
printf("Date: %s Time: %s\n",datebuf,timebuf);
}
Portability
time.h
Category
Prototype
3
char *_strtime(char *buf);
wchar_t *_wstrtime(wchar_t *buf);
Description
_strtime converts the current time to a string, storing the string in the buffer buf. The buffer must be at least 9 characters long.
1198
3.1 C++ Reference RAD Studio C Runtime Library Reference
where HH, MM, and SS are all two-digit numbers representing the hour, minute, and second, respectively. The string is
terminated by a null character.
Return Value
Example
#include <time.h>
#include <stdio.h>
void main(void)
{
char datebuf[9];
char timebuf[9];
_strdate(datebuf);
_strtime(timebuf);
printf("Date: %s Time: %s\n",datebuf,timebuf);
}
Portability
3.1.4.34.3 asctime
Header File
time.h
Category
Prototype
char *asctime(const struct tm *tblock);
wchar_t *_wasctime(const struct tm *tblock);
Description
asctime and _wasctime convert a time stored as a structure to a 26 (wide) character string in the following form:
3
Mon Nov 21 11:31:54 1983\n\0
All the fields have a constant width. The output string day-of-the-week and month correspond to the following:
1199
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
asctime and _wasctime return a pointer to the (wide) character string containing the date and time. This string is a static which is
overwritten with each call. asctime converts a time stored as a structure in *tblock to a 26-character string of the same form as
the ctime string:
Sun Sep 16 01:03:52 1973\n\0
Example
#include <string.h>
#include <time.h>
#include <stdio.h>
int main(void)
{
struct tm t;
char str[80];
/* sample loading of tm structure */
t.tm_sec = 1; /* Seconds */
t.tm_min = 30; /* Minutes */
t.tm_hour = 9; /* Hour */
t.tm_mday = 22; /* Day of the Month */
t.tm_mon = 11; /* Month */
t.tm_year = 56; /* Year - does not include century */
t.tm_wday = 4; /* Day of the week */
t.tm_yday = 0; /* Does not show in asctime */
t.tm_isdst = 0; /* Is Daylight SavTime; does not show in asctime */
/* converts structure to null terminated string */
strcpy(str, asctime(&t));
printf("%s\n", str);
return 0;
}
Portability
3.1.4.34.4 clock
Header File
time.h
Category
Prototype
clock_t clock(void);
3
Description
clock can be used to determine the time interval between two events. To determine the time in seconds, the value returned by
clock should be divided by the value of the macro CLK_TCK.
Return Value
On success, clock returns the processor time elapsed since the beginning of the program invocation.
1200
3.1 C++ Reference RAD Studio C Runtime Library Reference
On error (if the processor time is not available or its value cannot be represented), clock returns -1.
Example
#include <time.h>
#include <stdio.h>
#include <dos.h>
int main(void)
{
clock_t start, end;
start = clock();
delay(2000);
end = clock();
printf("The time was: %f\n", (end - start) / CLK_TCK);
return 0;
}
Portability
3.1.4.34.5 clock_t
Header File
time.h
Syntax
typedef long clock_t;
Description
Portability
time.h
Category
Description
1201
C Runtime Library Reference RAD Studio 3.1 C++ Reference
ctime converts a time value pointed to by time (the value returned by the function time) into a 26-character string in the following
form, terminating with a newline character and a null character:
Mon Nov 21 11:31:54 1983\n\0
The global long variable _timezone contains the difference in seconds between GMT and local standard time (in PST, _timezone
is 8*60*60). The global variable _daylight is used to tell the RTL's functions (mktime & localtime) whether they should take
daylight saving time into account if it runs into a date that would normally fall into that category. It is set to 1 if the daylight
savings time conversion should be applied.. These variables are set by the tzset function, not by the user program directly.
Return Value
ctime returns a pointer to the character string containing the date and time. The return value points to static data that is
overwritten with each call to ctime.
Example
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t t;
time(&t);
printf("Today's date and time: %s\n", ctime(&t));
return 0;
}
Portability
3.1.4.34.7 _daylight
Header File
time.h
Syntax
extern int _daylight;
Description
_daylight is used by the time and date functions. It is used to tell the RTL's functions (mktime & localtime) whether they should
take daylight saving time into account if it runs into a date that would normally fall into that category. _daylight is initialized from
the values specified in the TZ environment variable and is set to 1 if the daylight savings time conversion should be applied. If TZ
3 is not set, the value of _daylight is obtained from the operating system.
3.1.4.34.8 difftime
Header File
time.h
Category
1202
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
double difftime(time_t time2, time_t time1);
Description
Return Value
Example
#include <time.h>
#include <stdio.h>
#include <dos.h>
#include <conio.h>
int main(void)
{
time_t first, second;
clrscr();
first = time(NULL); /* Gets system
time */
delay(2000); /* Waits 2 secs */
second = time(NULL); /* Gets system time
again */
printf("The difference is: %f seconds\n",difftime(second,first));
getch();
return 0;
}
Portability
3.1.4.34.9 gmtime
Header File
time.h
Category
Prototype
struct tm *gmtime(const time_t *timer);
3
Description
gmtime accepts the address of a value returned by time and returns a pointer to the structure of type tm containing the time
elements. gmtime converts directly to GMT.
The global long variable _timezone should be set to the difference in seconds between GMT and local standard time (in PST
_timezone is 8 x 60 x 60). The global variable _daylight should be set to nonzero only if the standard U.S. daylight saving time
1203
C Runtime Library Reference RAD Studio 3.1 C++ Reference
These quantities give the time on a 24-hour clock, day of month (1 to 31), month (0 to 11), weekday (Sunday equals 0), year -
1900, day of year (0 to 365), and a flag that is nonzero if daylight saving time is in effect.
Return Value
gmtime returns a pointer to the structure containing the time elements. This structure is a static that is overwritten with each call.
Example
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* Pacific Standard Time & Daylight Savings */
char *tzstr = "TZ=PST8PDT";
int main(void)
{
time_t t;
struct tm *gmt, *area;
putenv(tzstr);
tzset();
t = time(NULL);
area = localtime(&t);
printf("Local time is: %s", asctime(area));
gmt = gmtime(&t);
printf("GMT is: %s", asctime(gmt));
return 0;
}
Portability
3 + + + +
3.1.4.34.10 localtime
Header File
time.h
Category
1204
3.1 C++ Reference RAD Studio C Runtime Library Reference
Prototype
struct tm *localtime(const time_t *timer);
Description
localtime accepts the address of a value returned by time and returns a pointer to the structure of type tm containing the time
elements. It corrects for the time zone and possible daylight saving time.
The global long variable _timezone contains the difference in seconds between GMT and local standard time (in PST, _timezone
is 8 x 60 x 60). The global variable _daylight is used to tell the RTL’s functions (mktime & localtime) whether they should take
daylight saving time into account if it runs into a date that would normally fall into that category. It is set to 1 if the daylight
savings time conversion should be applied. These values are set by tzset, not by the user program directly.
These quantities give the time on a 24-hour clock, day of month (1 to 31), month (0 to 11), weekday (Sunday equals 0), year -
1900, day of year (0 to 365), and a flag that is nonzero if the daylight saving time conversion should be applied.
Return Value
localtime returns a pointer to the structure containing the time elements. This structure is a static that is overwritten with each call.
Example
#include <time.h>
#include <stdio.h>
int main(void)
{
time_t timer;
struct tm *tblock;
/* gets time of day */ 3
timer = time(NULL);
/* converts date/time to a structure */
tblock = localtime(&timer);
printf("Local time is: %s", asctime(tblock));
return 0;
}
Portability
1205
C Runtime Library Reference RAD Studio 3.1 C++ Reference
3.1.4.34.11 mktime
Header File
time.h
Category
Prototype
Description
Converts the time in the structure pointed to by t into a calendar time with the same format used by the time function. The
original values of the fields tm_sec, tm_min, tm_hour, tm_mday, and tm_mon are not restricted to the ranges described in the tm
structure. If the fields are not in their proper ranges, they are adjusted. Values for fields tm_wday and tm_yday are computed
after the other fields have been adjusted.
The tm_isdst (Daylight Savings Time) field is adjusted with the correct value after calling the function mktime. Also, tm_isdst is
used for adusting the value of tm_hour. For example, if the value of tm_isdst is 1, but the current date is not DST, mktime
updates tm_hour (tm_hour = tm_hour - 1) and sets tm_isdst to 0.
The allowable range of calendar times is Jan 1 1970 00:00:00 to Jan 19 2038 03:14:07.
Return Value
On error (if the calendar time cannot be represented), mktime returns -1.
Example
#include <stdio.h> #include <time.h>
char *wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "Unknown"}; int main(void) { struct tm time_check; int year, month, day; /*
Input a year, month and day to find the weekday for */ printf("Year: "); scanf("%d",
&year); printf("Month: "); scanf("%d", &month); printf("Day: "); scanf("%d",
&day); /* load the time_check structure with the data */ time_check.tm_year = year -
1900; time_check.tm_mon = month - 1; time_check.tm_mday = day; time_check.tm_hour = 0;
time_check.tm_min = 0; time_check.tm_sec = 1; time_check.tm_isdst = -1; /* call mktime
to
fill in the weekday field of the structure */ if (mktime(&time_check) == -1)
time_check.tm_wday = 7; /* print out the day of the week */ printf("That day is a
3 %s\n",
wday[time_check.tm_wday]); return 0; }
Portability
1206
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.34.12 stime
Header File
time.h
Category
Prototype
int stime(time_t *tp);
Description
stime sets the system time and date. tp points to the value of the time as measured in seconds from 00:00:00 GMT, January 1,
1970.
Return Value
Example
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t t;
t = time(NULL);
printf("Current date is %s", ctime(&t));
t -= 24L*60L*60L; /* Back up to same time previous day */
stime(&t);
printf("\nNew date is %s", ctime(&t));
return 0;
}
Portability
time.h
Category 3
Time and Date Routines
Prototype
size_t strftime(char *s, size_t maxsize, const char *fmt, const struct tm *t);
size_t wcsftime(wchar_t *s, size_t maxsize, const wchar_t *fmt, const struct tm *t);
Description
1207
C Runtime Library Reference RAD Studio 3.1 C++ Reference
strftime formats the time in the argument t into the array pointed to by the argument s according to the fmt specifications. All
ordinary characters are copied unchanged. No more than maxsize characters are placed in s.
Return Value
On error (if the number of characters required is greater than maxsize), strftime returns 0.
Example
#include <stdio.h>
#include <time.h>
#include <dos.h>
int main(void)
{
struct tm *time_now;
time_t secs_now;
char str[80];
tzset();
time(&secs_now);
time_now = localtime(&secs_now);
strftime(str, 80,
"It is %M minutes after %I o'clock (%Z) %A, %B %d 19%y",
time_now);
printf("%s\n",str);
return 0;
}
Portability
3.1.4.34.14 time
Header File
time.h
Category
Prototype
3 time_t time(time_t *timer);
Description
time gives the current time, in seconds, elapsed since 00:00:00 GMT, January 1, 1970, and stores that value in the location
pointed to by timer, provided that timer is not a NULL pointer.
Return Value
1208
3.1 C++ Reference RAD Studio C Runtime Library Reference
Example
#include <time.h>
#include <stdio.h>
int main(void)
{
time_t t;
t = time(NULL);
printf("The number of seconds since January 1, 1970 is %ld",t);
return 0;
}
Portability
3.1.4.34.15 _timezone
Header File
time.h
Syntax
extern long _timezone;
Description
_timezone is used by the time-and-date functions. It is calculated by the tzset function; it is assigned a long value that is the
difference, in seconds, between the current local time and Greenwich mean time.
3.1.4.34.16 tm
Header File
time.h
Syntax
struct tm {
int tm_sec; /* Seconds */
int tm_min; /* Minutes */
int tm_hour; /* Hour (0--23) */
int tm_mday; /* Day of month (1--31) */ 3
int tm_mon; /* Month (0--11) */
int tm_year; /* Year (calendar year minus 1900) */
int tm_wday; /* Weekday (0--6; Sunday = 0) */
int tm_yday; /* Day of year (0--365) */
int tm_isdst; /* 0 if daylight savings time is not in effect) */
1209
C Runtime Library Reference RAD Studio 3.1 C++ Reference
};
Description
Example
3.1.4.34.17 _tzname,_wtzname
Header File
time.h
Syntax
extern char * _tzname[2]
extern wchar_t *const _wtzname[2]
Description
The global variable _tzname is an array of pointers to strings containing abbreviations for time zone names. _tzname[0] points to
a three-character string with the value of the time zone name from the TZ environment string. The global variable _tzname[1]
points to a three-character string with the value of the daylight saving time zone name from the TZ environment string. If no
daylight saving name is present, _tzname[1] points to a null string.
time.h
Category
Prototype
void _tzset(void)
void _wtzset(void)
Description
3 _tzset sets the _daylight, _timezone, and _tzname global variables based on the environment variable TZ. _wtzset sets the
_daylight, _timezone, and _wtzname global variables. The library functions ftime and localtime use these global variables to
adjust Greenwich Mean Time (GMT) to the local time zone. The format of the TZ environment string is:
TZ = zzz[+/-]d[d][lll]
where zzz is a three-character string representing the name of the current time zone. All three characters are required. For
example, the string “PST” could be used to represent Pacific standard time.
[+/-]d[d] is a required field containing an optionally signed number with 1 or more digits. This number is the local time zone’s
1210
3.1 C++ Reference RAD Studio C Runtime Library Reference
difference from GMT in hours. Positive numbers adjust westward from GMT. Negative numbers adjust eastward from GMT. For
example, the number 5 = EST, +8 = PST, and -1 = continental Europe. This number is used in the calculation of the global
variable _timezone. _timezone is the difference in seconds between GMT and the local time zone.
lll is an optional three-character field that represents the local time zone, daylight saving time. For example, the string “PDT”
could be used to represent pacific daylight saving time. If this field is present, it causes the global variable _daylight to be set
nonzero. If this field is absent, _daylight is set to zero.
If the TZ environment string isn’t present or isn’t in the preceding form, a default TZ = “EST5EDT” is presumed for the purposes
of assigning values to the global variables _daylight, _timezone, and _tzname. On a Win32 system, none of these global
variables are set if TZ is null.
The global variables _tzname[0] and _wtzname[1] point to a three-character string with the value of the time-zone name from the
TZ environment string. _tzname[1] and _wtzname[1] point to a three-character string with the value of the daylight saving
time-zone name from the TZ environment string. If no daylight saving name is present, _tzname[1] and _wtzname[1] point to a
null string.
Return Value
None.
Example
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
time_t td;
putenv("TZ=PST8PDT");
tzset();
time(&td);
printf("Current time = %s\n", asctime(localtime(&td)));
return 0;
}
Portability
3.1.4.35 typeinfo.h
The following functions, macros, and classes are provided in typeinfo.h:
Topics
Name Description
bad_cast class ( see page 1212) Header File 3
typeinfo.h
Description
When dynamic_cast fails to make a cast to reference, the expression can throw
bad_cast. Note that when dynamic_cast fails to make a cast to pointer type, the
result is the null pointer.
1211
C Runtime Library Reference RAD Studio 3.1 C++ Reference
typeinfo.h
Description
When dynamic_cast fails to make a cast to reference, the expression can throw bad_cast. Note that when dynamic_cast fails to
make a cast to pointer type, the result is the null pointer.
typeinfo.h
Description
When the operand of typeid is a dereferenced null pointer, the typeid operator can throw bad_typeid.
typeinfo.h
Description
Constructor
Only a private constructor is provided. You cannot create type_info objects. By declaring your objects to be _ _rtti types, or by
3
using the -RT compiler switch, the compiler provides your objects with the elements of type_info. type_info references are
generated by the typeid operator.
Operators
1212
3.1 C++ Reference RAD Studio C Runtime Library Reference
3.1.4.36 utime.h
The following functions, macros, and classes are provided in utime.h:
Topics
Name Description
_utime, _wutime ( see page 1213) Header File
utime.h
Category
Input/output Routines
Prototype
int _utime(char *path, struct utimbuf *times);
int _wutime(wchar_t *path, struct _utimbuf *times);
Description
Sets file time and date.
_utime sets the modification time for the file path. The modification time is
contained in the utimbuf structure pointed to by times. This structure is defined in
utime.h, and has the following format:
struct utimbuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
};
The FAT (file allocation table) file system supports only a modification time;
therefore, on FAT file systems _utime ignores actime and uses only modtime to
set... more ( see page 1213)
utime.h
Category
Input/output Routines
Prototype
int _utime(char *path, struct utimbuf *times);
int _wutime(wchar_t *path, struct _utimbuf *times);
Description
_utime sets the modification time for the file path. The modification time is contained in the utimbuf structure pointed to by times.
This structure is defined in utime.h, and has the following format:
struct utimbuf {
time_t actime; /* access time */
3
time_t modtime; /* modification time */
};
The FAT (file allocation table) file system supports only a modification time; therefore, on FAT file systems _utime ignores actime
and uses only modtime to set the file’s modification time.
If times is NULL, the file’s modification time is set to the current time.
_wutime is the Unicode version of _utime. The Unicode version accepts a filename that is a wchar_t character string. Otherwise,
1213
C Runtime Library Reference RAD Studio 3.1 C++ Reference
Return Value
On error, it returns -1, and sets the global variable errno to one of the following values:
Example
/* Copy timestamp from one file to another */
#include <sys\stat.h>
#include <utime.h>
#include <stdio.h>
if (stat(argv[1],&src_stat) != 0) {
perror("Unable to get status of source file");
return 1;
}
3.1.4.37 values.h
3 The following functions, macros, and classes are provided in values.h:
Topics
Name Description
BITSPERBYTE #define ( see page 1215) Header File
values.h
Description
Number of bits in a byte.
1214
3.1 C++ Reference RAD Studio C Runtime Library Reference
values.h
Description
values.h
Description
Bit mask for the high (sign) bit of standard integer types.
Name Meaning
HIBITS For type short
HIBITI For type int
HIBITL For type long
values.h
Description
1215
C Runtime Library Reference RAD Studio 3.1 C++ Reference
values.h
Description
1216
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Topics
Name Description
Component Writer's Guide ( see page 1217) The Component Writer's Guide covers all the information relating to creating VCL
components in the Delphi personality.
Developing COM-based Applications ( see page 1381) Contains the Developer's Guide topics for creating COM-based applications in
Delphi.
Developing Database Applications ( see page 1469) The Borland Database Engine (BDE) has been deprecated, so it will not be
enhanced. For instance, BDE will never have Unicode support. You should not
undertake new development with BDE. Consider migrating your existing
database applications from BDE to dbExpress.
Contains the Developer's Guide topics for programming database applications.
Programming with Delphi ( see page 1879) Contains the Developer's Guide topics for programming with Delphi.
Writing Internet Applications ( see page 2243) Contains the Developer's Guide topics for writing internet applications in Delphi.
Topics
Name Description
Creating a graphic component ( see page 1218)
Creating events ( see page 1231)
Creating methods ( see page 1241)
Creating properties ( see page 1245)
Customizing a grid ( see page 1258)
Extending the IDE ( see page 1276)
Handling messages ( see page 1298)
Introduction to component creation ( see page 1310)
Making a control data aware ( see page 1325)
Making components available at design time ( see page 1339)
Making a dialog box a component ( see page 1358)
Modifying an existing component ( see page 1363)
Object-oriented programming for component writers ( see page 1367)
Using graphics in components ( see page 1376)
1217
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1218
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Drawing the Component Image ( see page 1224) The essential element of a graphic control is the way it paints its image on the
screen. The abstract type TGraphicControl defines a method called Paint that
you override to paint the image you want on your control.
The Paint method for the shape control needs to do several things:
3
3.2.1.1.1 Adding Graphic Capabilities
Once you have declared your graphic component and published any inherited properties you want to make available, you can
add the graphic capabilities that distinguish your component. You have two tasks to perform when creating a graphic control:
1219
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
The graphic control presented in the following topics is TShape, the shape component on the Additional page of the Tool palette.
Although the component created is identical to the standard shape component, you need to call it something different to avoid
duplicate identifiers. The following topics use the name TSampleShape and show you all the steps involved in creating the shape
component:
For this example, follow the general procedure for creating a component, with these specifics:
1. Call the component's unit Shapes.
2. Derive a new component type called TSampleShape, descended from TGraphicControl.
3. Register TSampleShape on the Samples category of the Tool palette.
The resulting unit should look like this:
unit Shapes;
interface
uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms;
type
TSampleShape = class(TGraphicControl)
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponent('Samples', [TSampleShape]);
end;
end.
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Shapes.h"
//---------------------------------------------------------------------------
#pragma package(smart_init);
//---------------------------------------------------------------------------
3 // ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TSampleShape *)
{
new TSampleShape(NULL);
}
//---------------------------------------------------------------------------
__fastcall TSampleShape::TGraphicControl(TComponent* Owner)
: TGraphicControl(Owner)
1220
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
{
}
//---------------------------------------------------------------------------
namespace Shapes
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TSampleShape)};
RegisterComponents("Samples", classes, 0);
}
}
//---------------------------------------------------------------------------
#ifndef ShapesH
#define ShapesH
//---------------------------------------------------------------------------
#include <sysutils.hpp>
#include <controls.hpp>
#include <classes.hpp>
#include <forms.hpp>
//---------------------------------------------------------------------------
class PACKAGE TSampleShape : public TGraphicControl
{
private:
protected:
public:
__published:
};
//---------------------------------------------------------------------------
#endif
To the shape control, add properties that provide access to the pen and brush fields. You will also declare methods for reacting
to changes to the pen or brush.
type
TSampleShape = class(TGraphicControl)
.
.
.
private { these methods should be private }
procedure SetBrush(Value: TBrush);
procedure SetPen(Value: TPen);
published { make these available at design time }
property Brush: TBrush read FBrush write SetBrush;
property Pen: TPen read FPen write SetPen;
end;
class PACKAGE TSampleShape : public TGraphicControl
{
.
. 3
.
private:
TPen *FPen;
TBrush *FBrush;
void __fastcall SetBrush(TBrush *Value);
void __fastcall SetPen(TPen *Value);
.
.
.
__published:
1221
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Fields for owned objects are nearly always declared as private. If applications (or other components) need access to the owned
objects, you can declare published or public properties for this purpose.
1222
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
For the shape control, you will declare a field that holds the current shape, then declare a property that reads that field and writes
to it through a method call.
For the shape control, you need an enumerated type with an element for each kind of shape the control can draw.
Add the following type definition above the shape control class's declaration.
type
TSampleShapeType = (sstRectangle, sstSquare, sstRoundRect, sstRoundSquare,
sstEllipse, sstCircle);
TSampleShape = class(TGraphicControl) { this is already there }
enum TSampleShapeType { sstRectangle, sstSquare, sstRoundRect, sstRoundSquare, sstEllipse,
sstCircle };
class PACKAGE TSampleShape : public TGraphicControl // this is already there
You can now use this type to declare a new property in the class.
In general, the appearance of a graphic control depends on some combination of its properties. The gauge control, for example,
has properties that determine its shape and orientation and whether it shows its progress numerically as well as graphically. 3
Similarly, the shape control has a property that determines what kind of shape it should draw.
To give your control a property that determines the shape it draws, add a property called Shape. This requires
1223
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Creating properties is explained in more detail in Creating properties ( see page 1249).
The Paint method for the shape control needs to do several things:
1224
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Because you have added a pen and a brush to the shape control, you need to initialize them in the shape control's
constructor and destroy them in the control's destructor:
1. Construct the pen and brush in the shape control constructor:
constructor TSampleShape.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { always call the inherited constructor }
Width := 65;
Height := 65;
FPen := TPen.Create; { construct the pen }
FBrush := TBrush.Create; { construct the brush }
end;
__fastcall TSampleShape::TSampleShape(TComponent* Owner) : TGraphicControl(Owner)
{
Width = 65;
Height = 65; 3
FBrush = new TBrush(); // construct the pen
FPen = new TPen(); // construct the brush
}
2. Add the overridden destructor to the declaration of the component class:
type
TSampleShape = class(TGraphicControl)
public { destructors are always public}
constructor Create(AOwner: TComponent); override;
destructor Destroy; override; { remember override directive }
1225
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
end;
class PACKAGE TSampleShape : public TGraphicControl
{
.
.
.
public: // destructors are always public
virtual __fastcall TSampleShape(TComponent* Owner);
__fastcall ~TSampleShape(); // the destructor
.
.
.
};
3. Write the new destructor in the implementation part of the unit:
destructor TSampleShape.Destroy;
begin
FPen.Free; { destroy the pen object }
FBrush.Free; { destroy the brush object }
inherited Destroy; { always call the inherited destructor, too }
end;
__fastcall TSampleShape::~TSampleShape()
{
delete FPen; // delete the pen object
delete FBrush; // delete the brush object
}
In this example, the shape control sets its size to a square 65 pixels on each side.
1. Add the overridden constructor to the declaration of the component class:
type
TSampleShape = class(TGraphicControl)
public { constructors are always public }
constructor Create(AOwner: TComponent); override { remember override directive }
end;
class PACKAGE TSampleShape : public TGraphicControl
{
public:
virtual __fastcall TSampleShape(TComponent *Owner);
};
2. Redeclare the Height and Width properties with their new default values:
type
3 TSampleShape = class(TGraphicControl)
.
.
.
published
property Height default 65;
property Width default 65;
end;
class PACKAGE TSampleShape : public TGraphicControl
{
.
1226
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
.
.
__published:
__property Height;
__property Width;
}
3. Write the new constructor in the implementation part of the unit:
constructor TSampleShape.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { always call the inherited constructor }
Width := 65;
Height := 65;
end;
__fastcall TSampleShape::TSampleShape(TComponent* Owner) : TGraphicControl(Owner)
{
Width = 65;
Height = 65;
}
Publishing inherited properties and events is explained in Publishing inherited properties ( see page 1250) and Making events
visible. ( see page 1238) Both processes involve redeclaring just the name of the properties in the published part of the class
declaration.
For the shape control, you can publish the three mouse events, the three drag-and-drop events, and the two drag-and-drop
properties:
type
TSampleShape = class(TGraphicControl)
published
property DragCursor; { drag-and-drop properties }
property DragMode;
property OnDragDrop; { drag-and-drop events }
property OnDragOver;
property OnEndDrag;
property OnMouseDown; { mouse events }
property OnMouseMove;
property OnMouseUp;
end;
class PACKAGE TSampleShape : public TGraphicControl
{
private:
__published:
__property DragCursor ;
__property DragMode ;
__property OnDragDrop ;
__property OnDragOver ; 3
__property OnEndDrag ;
__property OnMouseDown ;
__property OnMouseMove ;
__property OnMouseUp ;
};
The sample shape control now makes mouse and drag-and-drop interactions available to its users.
1227
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Here is a refined Paint method that adjusts for squares and ellipses:
procedure TSampleShape.Paint;
var
X, Y, W, H, S: Integer;
begin with Canvas do
begin
Pen := FPen; { copy the component's pen }
Brush := FBrush; { copy the component's brush }
W := Width; { use the component width }
H := Height; { use the component height }
if W < H then S := W else S := H; { save smallest for circles/squares }
case FShape of { adjust height, width and position }
sstRectangle, sstRoundRect, sstEllipse:
begin
X := 0; { origin is top-left for these shapes }
Y := 0;
end;
sstSquare, sstRoundSquare, sstCircle:
begin
X := (W - S) div 2; { center these horizontally... }
Y := (H - S) div 2; { ...and vertically }
W := S; { use shortest dimension for width... }
H := S; { ...and for height }
end;
end;
case FShape of
sstRectangle, sstSquare:
Rectangle(X, Y, X + W, Y + H); { draw rectangles and squares }
sstRoundRect, sstRoundSquare:
3 RoundRect(X, Y, X + W, Y + H, S div 4, S div 4); { draw rounded shapes }
sstCircle, sstEllipse:
Ellipse(X, Y, X + W, Y + H); { draw round shapes }
end;
end;
end;
void __fastcall TSampleShape::Paint(void)
{
int X,Y,W,H,S;
Canvas->Pen = FPen; // copy the component's pen
Canvas->Brush = FBrush; // copy the component's brush
1228
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Add the following method to the shape control, and update the component's constructor to set the pen and brush events to the
new method:
type 3
TSampleShape = class(TGraphicControl)
published
procedure StyleChanged(Sender: TObject);
end;
.
.
.
implementation
.
.
1229
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
.
constructor TSampleShape.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { always call the inherited constructor }
Width := 65;
Height := 65;
FPen := TPen.Create; { construct the pen }
FPen.OnChange := StyleChanged; { assign method to OnChange event }
FBrush := TBrush.Create; { construct the brush }
FBrush.OnChange := StyleChanged; { assign method to OnChange event }
end;
procedure TSampleShape.StyleChanged(Sender: TObject);
begin
Invalidate; { erase and repaint the component }
end;
//header file
class PACKAGE TSampleShape : public TGraphicControl
{
.
.
.
public:
void __fastcall StyleChanged(TObject* Owner);
.
.
.
};
//implmentation file
__fastcall TSampleShape::TSampleShape(TComponent* Owner) : TGraphicControl(Owner)
{
Width = 65;
Height = 65;
FBrush = new TBrush();
FBrush->OnChange = StyleChanged;
FPen = new TPen();
FPen->OnChange = StyleChanged;
}
//also include StyleChanged method in the implementation file
void __fastcall TSampleShape::StyleChanged( TObject* Sender)
{
Invalidate(); // repaints the component
}
With these changes, the component redraws to reflect changes to either the pen or the brush.
Add the implementation of the SetShape method to the implementation part of the unit:
procedure TSampleShape.SetShape(Value: TSampleShapeType);
begin
3 if FShape <> Value then { ignore if this isn"t a change }
begin
FShape := Value; { store the new value }
Invalidate; { force a repaint with the new shape }
end;
end;
void __fastcall TSampleShape::SetShape(TSampleShapeType Value)
{
if (FShape != Value) // ignore if this isn't a change
{
FShape = Value; // store the new value
1230
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1231
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Event Handler Types Are Procedures ( see page 1236) Although the compiler allows you to declare method-pointer types that are
functions, you should never do so for handling events. Because an empty
function returns an undefined result, an empty event handler that was a function
might not always be valid. For this reason, all your events and their associated
event handlers should be procedures.
Although an event handler cannot be a function, you can still get information from
the application developer's code using var parameters. When doing this, make
sure you assign a valid value to the parameter before calling the handler so you
don't require the user's code... more ( see page 1236)
Event Handlers Have A Return Type of void (C++) ( see page 1236) Event handlers must have a return type of void. Even though the handler can
return only void, you can still get information back from the user's code by
passing arguments by reference. When you do this, make sure you assign a valid
value to the argument before calling the handler so you do not require the user's
code to change the value.
An example of passing arguments by reference to an event handler is the
key-pressed event, of type TKeyPressEvent. TKeyPressEvent defines two
arguments: one to indicate which object generated the event, and one to indicate
which... more ( see page 1236)
Event Types Are closure Types (C++) ( see page 1236) Because an event is a pointer to an event handler, the type of the event property
must be a closure type. Similarly, any code to be used as an event handler must
be an appropriately typed method of a class.
To be compatible with an event of a given type, an event-handler method must
have the same number and type of parameters, in the same order, passed in the
same way.
C++Builder defines closures for all its standard events. When you create your
own events, you can use an existing closure if that is appropriate, or define one
of your... more ( see page 1236)
Event Handlers Are Optional ( see page 1237) When creating events, remember that developers using your components may
not attach handlers to them. This means that your component should not fail or
generate errors simply because there is no handler attached to a particular event.
(The mechanics of calling handlers and dealing with events that have no
attached handler are explained in Calling the event ( see page 1240).)
Events happen almost constantly in a GUI application. Just moving the mouse
pointer across a visual component sends numerous mouse-move messages,
which the component translates into OnMouseMove events. In most cases,
developers do not want to handle the mouse-move events, and this... more (
see page 1237)
Implementing the Standard Events ( see page 1237) The controls that come with the component library inherit events for the most
common occurrences. These are called the standard events. Although all these
events are built into the controls, they are often protected, meaning developers
cannot attach handlers to them. When you create a control, you can choose to
make events visible to users of your control.
There are three things you need to consider when incorporating the standard
events into your controls:
1232
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Defining Your Own Events ( see page 1238) Defining entirely new events is relatively unusual. There are times, however,
when a component introduces behavior that is entirely different from that of any
other component, so you will need to define an event for it.
There are the issues you will need to consider when defining an event:
1233
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Events for the most common user actions (such as mouse actions) are built into all the standard components, but you can also
define new events. To create events in a component, you need to understand the following:
From the application developer's perspective, an event is just a name related to a system occurrence, such as OnClick, to which
specific code can be attached. For example, a push button called Button1 has an OnClick method. By default, when you assign
a value to the OnClick event, the Form Designer generates an event handler called Button1Click in the form that contains the
button and assigns it to OnClick. When a click event occurs in the button, the button calls the method assigned to OnClick, in this
case, Button1Click.
Closures maintain a hidden pointer to a class instance. When the user assigns a handler to a component's event, the
assignment is not just to a method with a particular name, but rather to a specific method of a specific class instance. That
instance is usually the form that contains the component, but it need not be.
3
3.2.1.2.4 Events Are Method Pointers
Delphi uses method pointers to implement events. A method pointer is a special pointer type that points to a specific method in a
specific class instance. As a component writer, you can treat the method pointer as a placeholder: When your code detects that
an event occurs, you call the method (if any) specified by the user for that event.
Method pointers work just like any other procedural type, but they maintain a hidden pointer to a class instance. When the
application developer assigns a handler to a component's event, the assignment is not just to a method with a particular name,
but rather to a method of a specific class instance. That instance is usually the form that contains the component, but it need not
be.
1234
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
By convention, the field's name is the name of the property preceded by the letter F. For example, the OnClick method's pointer
is stored in a field called FOnClick of type TNotifyEvent, and the declaration of the OnClick event property looks like this:
type
TControl = class(TComponent)
private
FOnClick: TNotifyEvent; { declare a field to hold the method pointer }
.
.
.
protected
property OnClick: TNotifyEvent read FOnClick write FOnClick;
end;
class PACKAGE TControl : public TComponent
{
private:
TNotifyEvent FOnClick;
.
.
.
protected:
__property TNotifyEvent OnClick = {read=FOnClick, write=FOnClick};
.
.
.
};
To learn about TNotifyEvent and other event types, see the next section, Event types are method-pointer types. ( see page
1235)
As with any other property, you can set or change the value of an event at runtime. The main advantage to having events be
properties, however, is that component users can assign handlers to events at design time, using the Object Inspector.
All event-handler methods are procedures. To be compatible with an event of a given type, an event-handler method must have
the same number and type of parameters, in the same order, passed in the same way.
Delphi defines method types for all its standard events. When you create your own events, you can use an existing type if that is
appropriate, or define one of your own.
1235
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Although an event handler cannot be a function, you can still get information from the application developer's code using var
parameters. When doing this, make sure you assign a valid value to the parameter before calling the handler so you don't
require the user's code to change the value.
An example of passing var parameters to an event handler is the OnKeyPress event, of type TKeyPressEvent. TKeyPressEvent
defines two parameters, one to indicate which object generated the event, and one to indicate which key was pressed:
type
TKeyPressEvent = procedure(Sender: TObject; var Key: Char) of object;
Normally, the Key parameter contains the character pressed by the user. Under certain circumstances, however, the user of the
component may want to change the character. One example might be to force all characters to uppercase in an editor. In that
case, the user could define the following handler for keystrokes:
procedure TForm1.Edit1KeyPressed(Sender: TObject; var Key: Char);
begin
Key := UpCase(Key);
end;
You can also use var parameters to let the user override the default handling.
An example of passing arguments by reference to an event handler is the key-pressed event, of type TKeyPressEvent.
TKeyPressEvent defines two arguments: one to indicate which object generated the event, and one to indicate which key was
pressed:
typedef void __fastcall (__closure *TKeyPressEvent)(TObject *Sender, Char &Key);
Normally, the Key parameter contains the character pressed by the user. Under certain circumstances, however, the user of the
component might want to change the character. One example might be to force all characters to uppercase in an edit control. In
that case, the user could define the following handler for keystrokes:
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, Char &Key)
{
Key = UpCase(Key);
}
You can also use arguments passed by reference to let the user override the default handling.
3
3.2.1.2.10 Event Types Are closure Types (C++)
Because an event is a pointer to an event handler, the type of the event property must be a closure type. Similarly, any code to
be used as an event handler must be an appropriately typed method of a class.
To be compatible with an event of a given type, an event-handler method must have the same number and type of parameters,
in the same order, passed in the same way.
1236
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
C++Builder defines closures for all its standard events. When you create your own events, you can use an existing closure if that
is appropriate, or define one of your own.
Events happen almost constantly in a GUI application. Just moving the mouse pointer across a visual component sends
numerous mouse-move messages, which the component translates into OnMouseMove events. In most cases, developers do
not want to handle the mouse-move events, and this should not cause a problem. So the components you create should not
require handlers for their events.
Moreover, application developers can write any code they want in an event handler. The components in the class library have
events written in such a way as to minimize the chance of an event handler generating errors. Obviously, you cannot protect
against logic errors in application code, but you can ensure that data structures are initialized before calling events so that
application developers do not try to access invalid data.
There are three things you need to consider when incorporating the standard events into your controls:
• OnClick
• OnDblClick
• OnDragDrop
• OnDragOver 3
• OnEndDrag
• OnMouseMove
• OnMouseDown
• OnMouseUp
The standard events have corresponding protected virtual methods declared in TControl, with names that correspond to the
event names. For example, OnClick events call a method named Click, and OnEndDrag events call a method named
1237
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
DoEndDrag.
Standard events for standard controls
In addition to the events common to all controls, standard windowed controls (those that descend from TWinControl) have the
following events:
• OnEnter
• OnKeyPress
• OnKeyDown
• OnKeyUp
• OnExit
Like the standard events in TControl, the windowed control events have corresponding methods. The standard key events listed
above respond to all normal keystrokes.
Note: To respond to special keystrokes (such as the Alt
key), however, you must respond to the WM_GETDLGCODE or CM_WANTSPECIALKEYS message from Windows. See
Handling messages and system notifications ( see page 1308) for information on writing message handlers.
Redeclaring a property without specifying its implementation keeps the same implementation methods, but changes the
protection level. You can, therefore, take an event that is defined in TControl but not made visible, and surface it by declaring it
as public or published.
This is the reason for the protected implementation methods associated with each of the standard events. By overriding the
implementation method, you can modify the internal event handling; and by calling the inherited method you can maintain the
standard handling, including the event for the application developer's code.
The order in which you call the methods is significant. As a rule, call the inherited method first, allowing the application
developer's event-handler to execute before your customizations (and in some cases, to keep the customizations from
executing). There may be times when you want to execute your code before calling the inherited method, however. For example,
if the inherited code is somehow dependent on the status of the component and your code changes that status, you should make
the changes and then allow the user's code to respond to them.
3
3.2.1.2.16 Defining Your Own Events
Defining entirely new events is relatively unusual. There are times, however, when a component introduces behavior that is
entirely different from that of any other component, so you will need to define an event for it.
There are the issues you will need to consider when defining an event:
1238
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
However, some events are less clearly tied to specific external occurrences. For example, a scroll bar has an OnChange event,
which is triggered by several kinds of occurrence, including keystrokes, mouse clicks, and changes in other controls. When
defining your events, you must ensure that all the appropriate occurrences call the proper events.
You have total control over the triggering of the events you define. Define the events with care so that developers are able to
understand and use them.
Simple notifications
A notification event is one that only tells you that the particular event happened, with no specific information about when or
where. Notifications use the type TNotifyEvent, which carries only one parameter, the sender of the event. All a handler for a
notification "knows" about the event is what kind of event it was, and what component the event happened to. For example, click
events are notifications. When you write a handler for a click event, all you know is that a click occurred and which component
was clicked.
Notification is a one-way process. There is no mechanism to provide feedback or prevent further handling of a notification.
Event-specific handlers
In some cases, it is not enough to know which event happened and what component it happened to. For example, if the event is
a key-press event, it is likely that the handler will want to know which key the user pressed. In these cases, you need handler
types that include parameters for additional information. 3
If your event was generated in response to a message, it is likely that the parameters you pass to the event handler come
directly from the message parameters.
1239
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
For example, all the key events (OnKeyDown, OnKeyUp, and OnKeyPress) pass by reference the value of the key pressed in a
parameter named Key. The event handler can change Key so that the application sees a different key as being involved in the
event. This is a way to force typed characters to uppercase, for example.
Developers expect to find events in the alphabetical list of names starting with "On." Using other kinds of names is likely to
confuse them.
Note: The main exception to this rule is that many events that occur before and after some occurrence begin with "Before" and
"After."
Putting all the event calls in one place ensures that someone deriving a new component from yours can customize event
handling by overriding a single method, rather than searching through your code for places where you call the event.
3 This is in keeping with the rule that an empty handler should have the same effect as no handler at all. Because an empty
handler will not change the values of arguments passed by reference, the default handling always takes place after calling the
empty handler.
1240
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1241
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Methods That Should Be Protected ( see page 1244) Any implementation methods for the component should be protected so that
applications cannot call them at the wrong time. If you have methods that
application code should not call, but that are called in derived classes, declare
them as protected.
For example, suppose you have a method that relies on having certain data set
up for it beforehand. If you make that method public, there is a chance that
applications will call it before setting up the data. On the other hand, by making it
protected, you ensure that applications cannot call it directly. You can then...
more ( see page 1244)
Methods That Should Be Public ( see page 1244) Any method that application developers need to call must be declared as public.
Keep in mind that most method calls occur in event handlers, so methods should
avoid tying up system resources or putting the operating system in a state where
it cannot respond to the user.
Note: Constructors and destructors should always be public.
Naming Methods ( see page 1244) Delphi imposes no restrictions on what you name methods or their parameters.
There are a few conventions that make methods easier for application
developers, however. Keep in mind that the nature of a component architecture
dictates that many different kinds of people can use your components.
If you are accustomed to writing code that only you or a small group of
programmers use, you might not think too much about how you name things. It is
a good idea to make your method names clear because people unfamiliar with
your code (and even unfamiliar with coding) might have to use... more ( see
page 1244)
Protecting Methods ( see page 1245) All parts of classes, including fields, methods, and properties, have a level of
protection or "visibility," as explained in Controlling access. ( see page 1371)
Choosing the appropriate visibility for a method is simple.
Most methods you write in your components are public or protected. You rarely
need to make a method private, unless it is truly specific to that type of
component, to the point that even derived components should not have access to
it.
Making Methods Virtual ( see page 1245) You make methods virtual when you want different types to be able to execute
different code in response to the same method call.
If you create components intended to be used directly by application developers,
you can probably make all your methods nonvirtual. On the other hand, if you
create abstract components from which other components will be derived,
consider making the added methods virtual. This way, derived components can
override the inherited virtual methods.
While you can create an instance object of a class that contains an abstract member, it is not recommended. Calling the abstract
member leads to an EAbstractError exception.
The abstract directive is used to indicate parts of classes that should be surfaced and defined in descendant components; it
forces component writers to redeclare the abstract member in descendant classes before actual instances of the class can be
created.
1242
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
The best way to handle these situations is to ensure that you provide ways out of them. For example, if calling a method puts
your component into a state where calling another method might be invalid, then write that second method so that if an
application calls it when the component is in a bad state, the method corrects the state before executing its main code. At a
minimum, you should raise an exception in cases when a user calls a method that is invalid.
In other words, if you create a situation where parts of your code depend on each other, the burden should be on you to be sure
that using the code in incorrect ways does not cause problems. A warning message, for example, is preferable to a system
failure if the user does not accommodate your dependencies.
C++
This is the interface definition in the .H file:
class PACKAGE TSampleComponent : public TControl
{
protected:
void __fastcall MakeBigger();
public:
virtual int __fastcall CalculateArea();
.
3
.
.
};
This is the code in the .CPP file of the unit that implements the methods:
void __fastcall TSampleComponent::MakeBigger()
{
Height = Height + 5;
Width = Width + 5;
1243
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
}
int __fastcall TSampleComponent::CalculateArea()
{
return Width * Height;
}
Delphi
type
TSampleComponent = class(TControl)
protected
procedure MakeBigger; { declare protected static method }
public
function CalculateArea: Integer; virtual; { declare public virtual method }
end;
.
.
.
implementation
.
.
.
procedure TSampleComponent.MakeBigger; { implement first method }
begin
Height := Height + 5;
Width := Width + 5;
end;
function TSampleComponent.CalculateArea: Integer; { implement second method }
begin
Result := Width * Height;
end;
For example, suppose you have a method that relies on having certain data set up for it beforehand. If you make that method
public, there is a chance that applications will call it before setting up the data. On the other hand, by making it protected, you
ensure that applications cannot call it directly. You can then set up other, public methods that ensure that data setup occurs
before calling the protected method.
Property-implementation methods should be declared as virtual protected methods. Methods that are so declared allow the
application developers to override the property implementation, either augmenting its functionality or replacing it completely.
Such properties are fully polymorphic. Keeping access methods protected ensures that developers do not accidentally call
them, inadvertently modifying a property.
1244
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
If you are accustomed to writing code that only you or a small group of programmers use, you might not think too much about
how you name things. It is a good idea to make your method names clear because people unfamiliar with your code (and even
unfamiliar with coding) might have to use your components.
• Make names descriptive. Use meaningful verbs. A name like PasteFromClipboard is much more informative than simply
Paste or PFC.
• Function names should reflect the nature of what they return.
Although it might be obvious to you as a programmer that a function named X returns the horizontal position of something, a
name like GetHorizontalPosition is more universally understandable.
As a final consideration, make sure the method really needs to be a method. A good guideline is that method names have verbs
in them. If you find that you create a lot of methods that do not have verbs in their names, consider whether those methods
ought to be properties.
Most methods you write in your components are public or protected. You rarely need to make a method private, unless it is
truly specific to that type of component, to the point that even derived components should not have access to it.
If you create components intended to be used directly by application developers, you can probably make all your methods
nonvirtual. On the other hand, if you create abstract components from which other components will be derived, consider making
the added methods virtual. This way, derived components can override the inherited virtual methods.
1245
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Why Create Properties? ( see page 1249) From the application developer's standpoint, properties look like variables.
Developers can set or read the values of properties as if they were fields. (About
the only thing you can do with a variable that you cannot do with a property is
pass it as a var parameter.)
Properties provide more power than simple fields because
1246
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Internal Data Storage ( see page 1251) There are no restrictions on how you store the data for a property. In general,
however, Delphi components follow these conventions:
1247
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Creating Array Properties ( see page 1253) Some properties lend themselves to being indexed like arrays. For example, the
Lines property of TMemo is an indexed list of the strings that make up the text of
the memo; you can treat it as an array of strings. Lines provides natural access to
a particular element (a string) in a larger set of data (the memo text).
Array properties are declared like other properties, except that
1248
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Initializing After Loading ( see page 1256) After a component reads all its property values from its stored description, it calls
a virtual method named Loaded, which performs any required initializations. The
call to Loaded occurs before the form and its controls are shown, so you do not
need to worry about initialization causing flicker on the screen.
To initialize a component after it loads its property values, override the Loaded
method.
Note: The first thing to do in any Loaded method is call the inherited Loaded
method. This ensures that any inherited properties are correctly initialized before
you initialize your own component.
The following code... more ( see page 1256)
Storing and Loading Unpublished Properties ( see page 1256) By default, only published properties are loaded and saved with a component.
However, it is possible to load and save unpublished properties. This allows you
to have persistent properties that do not appear in the Object Inspector. It also
allows components to store and load property values that Delphi does not know
how to read or write because the value of the property is too complex. For
example, the TStrings object can't rely on Delphi's automatic behavior to store
and load the strings it represents and must use the following mechanism.
You can save unpublished properties by adding code that... more ( see page
1256)
Creating Methods to Store and Load Property Values ( see page 1256) To store and load unpublished properties, you must first create a method to store
your property value and another to load your property value. You have two
choices:
To make the best use of properties in your components, you should understand the following:
1249
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
as if they were fields. (About the only thing you can do with a variable that you cannot do with a property is pass it as a var
parameter.)
• Application developers can set properties at design time. Unlike methods, which are available only at runtime, properties let
the developer customize components before running an application. Properties can appear in the Object Inspector, which
simplifies the programmer's job; instead of handling several parameters to construct an object, the Object Inspector supplies
the values. The Object Inspector also validates property assignments as soon as they are made.
• Properties can hide implementation details. For example, data stored internally in an encrypted form can appear unencrypted
as the value of a property; although the value is a simple number, the component may look up the value in a database or
perform complex calculations to arrive at it. Properties let you attach complex effects to outwardly simple assignments; what
looks like an assignment to a field can be a call to a method which implements elaborate processing.
• Properties can be virtual. Hence, what looks like a single property to an application developer may be implemented differently
in different components.
A simple example is the Top property of all controls. Assigning a new value to Top does not just change a stored value; it
repositions and repaints the control. And the effects of setting a property need not be limited to an individual component; for
example, setting the Down property of a speed button to True sets Down property of all other speed buttons in its group to
False.
Property treatment
type
Simple Numeric, character, and string properties appear as numbers, characters, and strings. The application developer
can edit the value of the property directly.
Enumerated Properties of enumerated types (including Boolean) appear as editable strings. The developer can also cycle
through the possible values by double-clicking the value column, and there is a drop-down list that shows all
possible values.
Set Properties of set types appear as sets. By double-clicking on the property, the developer can expand the set and
treat each element as a Boolean value (true if it is included in the set).
Object Properties that are themselves classes often have their own property editors, specified in the component's
registration procedure. If the class held by a property has its own published properties, the Object Inspector lets
the developer to expand the list (by double-clicking) to include these properties and edit them individually. Object
properties must descend from TPersistent.
Interface Properties that are interfaces can appear in the Object Inspector as long as the value is an interface that is
implemented by a component (a descendant of TComponent). Interface properties often have their own property
editors.
Array Array properties must have their own property editors; the Object Inspector has no built-in support for editing
them. You can specify a property editor when you register your components.
3
To make a protected or public property available at design time in the Object Inspector, you must redeclare the property as
1250
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
published. Redeclaring means adding a declaration for the inherited property to the declaration of the descendant class.
It is common to have direct access for the read part of a property declaration but use an access method for the write part. This
allows the status of the component to be updated when the property value changes.
1251
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Avoid making access methods public. Keeping them protected ensures that application developers do not inadvertently modify a
property by calling one of these methods.
The only exceptions to the no-parameters rule are for array properties and properties that use index specifiers (see Creating
array properties ( see page 1253)), both of which pass their index values as parameters. (Use index specifiers to create a
single read method that is shared by several properties. For more information about index specifiers, see the Delphi Language
Guide.)
If you do not declare a read method, the property is write-only. Write-only properties are seldom used.
The only exceptions to the single-parameter rule are for array properties and properties that use index specifiers, both of which
pass their index values as a second parameter. (Use index specifiers to create a single write method that is shared by several
properties. For more information about index specifiers, see the Delphi Language Guide.)
Write methods commonly test whether a new value differs from the current value before changing the property. For example,
here is a simple write method for an integer property called Count that stores its current value in a field called FCount.
procedure TMyComponent.SetCount(Value: Integer);
begin
if Value <> FCount then
begin
FCount := Value;
Update;
3 end;
end;
void __fastcall TMyComponent::SetCount( int Value )
{
if ( Value != FCount )
{
FCount = Value;
Update();
}
1252
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
To specify a default value for a property, append the default directive to the property's declaration (or redeclaration), followed by
the default value. For example,
property Cool Boolean read GetCool write SetCool default True;
__property bool IsTrue = {read=GetIsTrue, write=SetIsTrue, default=true};
Note: Declaring a default value does not set the property to that value. The component's constructor method should initialize
property values when appropriate. However, since objects always initialize their fields to 0, it is not strictly necessary for the
constructor to set integer properties to 0, string properties to null, or Boolean properties to False.
To designate a property as having no default value, append the nodefault directive to the property's declaration. For example,
property FavoriteFlavor string nodefault;
__property int NewInteger = {nodefault};
When you declare a property for the first time, there is no need to include nodefault. The absence of a declared default value
means that there is no default.
• The declaration includes one or more indexes with specified types. The indexes can be of any type.
• The read and write parts of the property declaration, if specified, must be methods. They cannot be fields.
The read and write methods for an array property take additional parameters that correspond to the indexes. The parameters
must be in the same order and of the same type as the indexes specified in the declaration.
There are a few important differences between array properties and arrays. Unlike the index of an array, the index of an array
property does not have to be an integer type. You can index a property on a string, for example. In addition, you can reference
only individual elements of an array property, not the entire range of the property.
To handle this situation, you can call your component's ReferenceInterface method:
procedure TDemoComponent.SetMyIntfProp(const Value: IMyInterface);
1253
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
begin
ReferenceInterface(FIntfField, opRemove);
FIntfField := Value;
ReferenceInterface(FIntfField, opInsert);
end;
Calling ReferenceInterface with a specified interface does the same thing as calling another component's FreeNotification
method. Thus, after calling ReferenceInterface from the property setter, you can override the Notification method to handle the
notifications from the implementor of the interface:
procedure TDemoComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Assigned(MyIntfProp)) and (AComponent.IsImplementorOf(MyInftProp)) then
MyIntfProp := nil;
end;
Note that the Notification code assigns nil to the MyIntfProp property, not to the private field (FIntfField). This ensures that
Notification calls the property setter, which calls ReferenceInterface to remove the notification request that was established when
the property value was set previously. All assignments to the interface property must be made through the property setter.
Subcomponents can be any persistent object (any descendant of TPersistent). Unlike separate components that happen to be
assigned as the value of a property, the published properties of subcomponents are saved with the component that creates
them. In order for this to work, however, the following conditions must be met:
• The Owner of the subcomponent must be the component that creates it and uses it as the value of a published property. For
subcomponents that are descendants of TComponent, you can accomplish this by setting the Owner property of the
subcomponent. For other subcomponents, you must override the GetOwner method of the persistent object so that it returns
the creating component.
• If the subcomponent is a descendant of TComponent, it must indicate that it is a subcomponent by calling the
SetSubComponent method. Typically, this call is made either by the owner when it creates the subcomponent or by the
constructor of the subcomponent.
Note: When a component that has subcomponents is streamed, the subcomponents will have their csLoading flag set and
their Loaded method called. This can create a complication for any subcomponent properties that are writable. If you allow
your subcomponent property to be assigned to an external component reference, then you cannot free your subcomponent
until it's owner's Loaded method is called. Otherwise, the streaming system will attempt to call the subcomponent's Loaded
method after the subcomponent has been freed.
Typically, properties whose values are subcomponents are read-only. If you allow a property whose value is a subcomponent
to be changed, the property setter must free the subcomponent when another component is assigned as the property value.
In addition, the component often re-instantiates its subcomponent when the property is set to nil. Otherwise, once the property
is changed to another component, the subcomponent can never be restored at design time.
3 Note that the property setter above called the FreeNotification method of the component that is set as the property value. This
call ensures that the component that is the value of the property sends a notification if it is about to be destroyed. It sends this
notification by calling the Notification method. You handle this call by overriding the Notification method.
1254
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
write their properties to the form file when saved. Similarly, when loaded into Delphi or executed as part of an application, the
components must restore themselves from the form file.
Most of the time you will not need to do anything to make your components work with form files because the ability to store a
representation and load from it are part of the inherited behavior of components. Sometimes, however, you might want to alter
the way a component stores itself or the way it initializes when loaded; so you should understand the underlying mechanism.
By default, when storing itself, a component writes the values of all its published properties that differ from their default values, in
the order of their declaration. When loading itself, a component first constructs itself, setting all properties to their default values,
then reads the stored, non-default property values.
This default mechanism serves the needs of most components, and requires no action at all on the part of the component writer.
There are several ways you can customize the storing and loading process to suit the needs of your particular components,
however.
To specify a default value for a property, add the default directive and the new default value to the end of the property
declaration.
You can also specify a default value when re-declaring a property. In fact, one reason to re-declare a property is to designate a
different default value.
__property Alignment = {default=taCenter};
Note: Specifying the default value does not automatically assign that value to the property on creation of the object. You must
make sure that the component's constructor assigns the necessary value. A property whose value is not set by a component's
constructor assumes a zero value- that is, whatever value the property assumes when its storage memory is set to 0. Thus
numeric values default to 0, Boolean values to False, pointers to nil, and so on. If there is any doubt, assign a value in the
constructor method.
3
To control whether Delphi stores a property, add the stored directive to the property declaration, followed by True, False, or the
1255
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
To initialize a component after it loads its property values, override the Loaded method.
Note: The first thing to do in any Loaded method is call the inherited Loaded method. This ensures that any inherited properties
are correctly initialized before you initialize your own component.
The following code comes from the TDatabase component. After loading, the database tries to reestablish any connections that
were open at the time it was stored, and specifies how to handle any exceptions that occur while connecting.
procedure TDatabase.Loaded;
begin
inherited Loaded; { call the inherited method first}
try
if FStreamedConnected then Open { reestablish connections }
else CheckSessionName(False);
except
if csDesigning in ComponentState then { at design time... }
Application.HandleException(Self) { let Delphi handle the exception }
else raise; { otherwise, reraise }
end;
end;
You can save unpublished properties by adding code that tells Delphi how to load and save your property's value.
To write your own code to load and save properties, use the following steps:
1. Create methods to store and load the property value ( see page 1256).
2. Override the DefineProperties method ( see page 1257), passing those methods to a filer object.
1256
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
No matter which method you use to define the property, you pass it the methods that store and load your property value as well
as a boolean value indicating whether the property value needs to be written. If the value can be inherited or has a default value,
you do not need to write it.
For example, given the LoadCompProperty method of type TReaderProc and the StoreCompProperty method of type
TWriterProc, you would override DefineProperties as follows:
procedure TSampleComponent.DefineProperties(Filer: TFiler);
function DoWrite: Boolean;
begin
if Filer.Ancestor <> nil then { check Ancestor for an inherited value }
begin
if TSampleComponent(Filer.Ancestor).MyCompProperty = nil then
Result := MyCompProperty <> nil
else if (MyCompProperty = nil) or
(TMy5Comp(Filer.Ancestor).MyCompProperty.Name <> MyCompProperty.Name) then
Result := True 3
else Result := False;
end
else { no inherited value -- check for default (nil) value }
Result := MyCompProperty <> nil;
end;
begin
inherited; { allow base classes to define properties }
Filer.DefineProperty('MyCompProperty', LoadCompProperty, StoreCompProperty, DoWrite);
end;
void __fastcall TSampleComponent::DefineProperties(TFiler *Filer)
1257
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
{
// before we do anything, let the base class define its properties.
// Note that this example assumes that TSampleComponent derives directly from TComponent
TComponent::DefineProperties(Filer);
bool WriteValue;
if (Filer->Ancestor) // check for inherited value
{
if ((TSampleComponent *)Filer->Ancestor)->MyCompProperty == NULL)
WriteValue = (MyCompProperty != NULL);
else if ((MyCompProperty == NULL) ||
(((TSampleComponent *)Filer->Ancestor)->MyCompProperty->Name !=
MyCompProperty->Name))
WriteValue = true;
else WriteValue = false;
}
else // no inherited value, write property if not null
WriteValue = (MyCompProperty != NULL);
Filer->DefineProperty("MyCompProperty ",LoadCompProperty,StoreCompProperty, WriteValue);
end;
1258
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Customizing a Grid: Overview ( see page 1264) The component library provides abstract components you can use as the basis
for customized components. The most important of these are grids and list
boxes. The following topics describe how to create a small one month calendar
from the basic grid component, TCustomGrid:
1259
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Navigating Months and Years ( see page 1269) Properties are useful for manipulating components, especially at design time. But
sometimes there are types of manipulations that are so common or natural, often
involving more than one property, that it makes sense to provide methods to
handle them. One example of such a natural manipulation is a "next month"
feature for a calendar. Handling the wrapping around of months and
incrementing of years is simple, but very convenient for the developer using the
component.
The only drawback to encapsulating common manipulations into methods is that
methods are only available at runtime. However, such manipulations are
generally only cumbersome when... more ( see page 1269)
Providing an OnChange Event ( see page 1270) Now that users of the calendar can change the date within the calendar, it makes
sense to allow applications to respond to those changes.
Publishing Inherited Properties (Grid) ( see page 1271) The abstract grid component, TCustomGrid, provides a large number of
protected properties. You can choose which of those properties you want to
make available to users of the calendar control.
To make inherited protected properties available to users of your components,
redeclare the properties in the published part of your component's declaration.
For the calendar control, publish the following properties and events, as shown
here:
Resizing the Cells ( see page 1272) Note: When a user or application changes the size of a window or control,
Windows sends a message called WM_SIZE to the affected window or control so
it can adjust any settings needed to later paint its image in the new size. Your
VCL component can respond to that message by altering the size of the cells so
they all fit inside the boundaries of the control. To respond to the WM_SIZE
message, you will add a message-handling method to the component.
Creating a message-handling method is described in detail in the section
Creating new message handlers. ( see page 1304)
In this case,... more ( see page 1272)
Selecting the Current Day ( see page 1274) Now that you have numbers in the calendar cells, it makes sense to move the
selection highlighting to the cell containing the current day. By default, the
selection starts on the top left cell, so you need to set the Row and Column
properties both when constructing the calendar initially and when the date
changes.
To set the selection on the current day, change the UpdateCalendar method to
set Row and Column before calling Refresh:
Storing the Internal Date ( see page 1274) To store the date for the calendar, you need a private field to hold the date and a
runtime-only property that provides access to that date.
Tracking the Date ( see page 1275) For the calendar control to be useful, users and applications must have a
mechanism for setting the day, month, and year. Delphi stores dates and times in
variables of type TDateTime. TDateTime is an encoded numeric representation
of the date and time, which is useful for programmatic manipulation, but not
convenient for human use.
You can therefore store the date in encoded form, providing runtime access to
that value, but also provide Day, Month, and Year properties that users of the
calendar component can set at design time.
Tracking the date in the calendar consists of the... more ( see page 1275)
Because each element of the date (day, month, and year) is an integer, and because setting each requires encoding the date
when set, you can avoid duplicating the code each time by sharing the implementation methods for all three properties. That is,
you can write two methods, one to read an element and one to write one, and use those methods to get and set all three
properties.
3
To provide design-time access to the day, month, and year, you do the following:
1. Declare the three properties, assigning each a unique index number:
type
TSampleCalendar = class(TCustomGrid)
public
property Day: Integer index 3 read GetDateElement write SetDateElement;
property Month: Integer index 2 read GetDateElement write SetDateElement;
1260
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1261
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
// implementation file
int __fastcall TSampleCalendar::GetDateElement(int Index)
{
unsigned short AYear, AMonth, ADay;
int result;
FDate.DecodeDate(&AYear, &AMonth, &ADay); // break encoded date into elements
switch (Index)
{
case 1: result = AYear; break;
case 2: result = AMonth; break;
case 3: result = ADay; break;
default: result = -1;
}
return result;
}
void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
{
unsigned short AYear, AMonth, ADay;
if (Value > 0) // all elements must be positive
{
FDate.DecodeDate(&AYear, &AMonth, &ADay); // get current date elements
switch (Index)
{
case 1: AYear = Value; break;
case 2: AMonth = Value; break;
case 3: ADay = Value; break;
default: return;
}
}
FDate = TDateTime(AYear, AMonth, ADay); // encode the modified date
Refresh(); // update the visible calendar
}
Now you can set the calendar's day, month, and year at design time using the Object Inspector or at runtime using code. Of
course, you have not yet added the code to paint the dates into the cells, but now you have the needed data.
To change the initial values of the component's properties, override the constructor to set the desired values. The constructor
must be virtual.
Remember that you need to add the constructor to the public part of the component's object declaration, then write the new
constructor in the implementation part of the component's unit. The first statement in the new constructor should always be a
call to the inherited constructor. Then add the StdCtrls unit to the uses clause.
type
TSampleCalendar = class(TCustomGrid)
3 public
constructor Create(AOwner: TComponent); override;
.
.
.
end;
.
.
.
constructor TSampleCalendar.Create(AOwner: TComponent);
begin
1262
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
For this example, follow the general procedure for creating a component, with these specifics:
1. Save the component's unit as CalSamp.
2. Derive a new component type called TSampleCalendar, descended from TCustomGrid.
3. Register TSampleCalendar on the Samples category of the Tool palette.
The resulting unit descending from TCustomGrid in a VCL application should look like this:
unit CalSamp; 3
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids;
type
TSampleCalendar = class(TCustomGrid)
end;
procedure Register;
implementation
procedure Register;
begin
1263
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
RegisterComponents('Samples', [TSampleCalendar]);
end;
end.
#include <vcl\vcl.h>
#pragma hdrstop
#include "CalSamp.h"
//---------------------------------------------------------------------------
#pragma package(smart_init);
//---------------------------------------------------------------------------
static inline TSampleCalendar *ValidCtrCheck()
{
return new TSampleCalendar(NULL);
}
//---------------------------------------------------------------------------
namespace Calsamp
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TSampleCalendar)};
RegisterComponents("Samples", classes, 0); //Use a different page in CLX applications
}
}
#ifndef CalSampH
#define CalSampH
//---------------------------------------------------------------------------
#include <vcl\sysutils.hpp>
#include <vcl\controls.hpp>
#include <vcl\classes.hpp>
#include <vcl\forms.hpp>
#include <vcl\grids.hpp>
//---------------------------------------------------------------------------
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
protected:
public:
__published:
};
//---------------------------------------------------------------------------
#endif
If you install the calendar component now, you will find that it appears on the Samples category. The only properties available
are the most basic control properties. The next step is to make some of the more specialized properties available to users of the
calendar.
Note: While you can install the sample calendar component you have just compiled, do not try to place it on a form yet. The
TCustomGrid component has an abstract DrawCell method that must be redeclared before instance objects can be created.
Overriding the DrawCell method is described in Filling in the cells ( see page 1265)
1264
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
To control whether a given cell is selectable, override the SelectCell method of the grid.
SelectCell is a function that takes a column and row as parameters, and returns a Boolean value indicating whether the specified
cell is selectable.
You can override SelectCell to return False if the cell does not contain a valid date:
function TSampleCalendar.SelectCell(ACol, ARow: Longint): Boolean;
begin
if DayNum(ACol, ARow) = -1 then Result := False { -1 indicates invalid date }
else Result := inherited SelectCell(ACol, ARow); { otherwise, use inherited value }
end;
bool __fastcall TSampleCalendar::SelectCell(int ACol, int ARow)
{
if (DayNum(ACol,ARow) == -1) return false; // -1 indicates invalid date
else return TCustomGrid::SelectCell(ACol, ARow); // otherwise, use inherited value
}
Now if the user clicks a blank cell or tries to move to one with an arrow key, the calendar leaves the current cell selected.
The easiest part to fill in is the heading cells in the fixed row. The runtime library contains an array with short day names, so for
the calendar, use the appropriate one for each column:
type
TSampleCalendar = class(TCustomGrid)
protected
procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
override;
end;
.
.
.
procedure TSampleCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState);
begin 3
if ARow = 0 then
Canvas.TextOut(ARect.Left, ARect.Top, ShortDayNames[ACol + 1]); { use RTL strings }
end;
void __fastcall TSampleCalendar::DrawCell(int ACol, int ARow, const Windows::TRect &ARect,
TGridDrawState AState)
{
String TheText;
int TempDay;
if (ARow == 0) TheText = ShortDayNames[ACol + 1];
1265
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
else
{
TheText = "";
TempDay = DayNum(ACol, ARow); // DayNum is defined later
if (TempDay != -1) TheText = IntToStr(TempDay);
}
Canvas->TextRect(ARect, ARect.Left + (ARect.Right - ARect.Left
- Canvas->TextWidth(TheText)) / 2,
ARect.Top + (ARect.Bottom - ARect.Top - Canvas->TextHeight(TheText)) / 2, TheText);
}
Once you have the information on leap years and days per month, you can calculate where in the grid the individual dates go.
The calculation is based on the day of the week the month starts on.
Because you will need the month-offset number for each cell you fill in, the best practice is to calculate it once when you change
the month or year, then refer to it each time. You can store the value in a class field, then update that field each time the date
changes.
1266
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
.
.
.
};
void __fastcall TSampleCalendar::UpdateCalendar(void)
{
unsigned short AYear, AMonth, ADay;
TDateTime FirstDate; // date of first day of the month
if ((int)FDate != 0) // only calculate offset if date is valid
{
FDate.DecodeDate(&AYear, &AMonth, &ADay); // get elements of date
FirstDate = TDateTime(AYear, AMonth, 1); // date of the first
FMonthOffset = 2 - FirstDate.DayOfWeek(); // generate the offset into the grid
}
Refresh(); // always repaint the control
}
2. Add statements to the constructor and the SetCalendarDate and SetDateElement methods that call the new update method
whenever the date changes:
constructor TSampleCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { this is already here }
. { other initializations here }
.
.
UpdateCalendar; { set proper offset }
end;
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime);
begin FDate := Value; { this was already here }
UpdateCalendar; { this previously called Refresh }
end;
procedure TSampleCalendar.SetDateElement(Index: Integer; Value: Integer);
begin
.
.
.
FDate := EncodeDate(AYear, AMonth, ADay); { encode the modified date }
UpdateCalendar; { this previously called Refresh }
end;
end;
__fastcall TSampleCalendar::TSampleCalendar(TComponent *Owner)
: TCustomGrid(Owner)
{
.
.
.
UpdateCalendar();
}
void __fastcall TSampleCalendar::SetCalendarDate(TDateTime Value)
{
FDate = Value; // this was already here
UpdateCalendar(); // this previously called Refresh
}
void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
{
. 3
.
.
FDate = TDateTime(AYear, AMonth, ADay); // this was already here
UpdateCalendar(); // this previously called Refresh
}
3. Add a method to the calendar that returns the day number when passed the row and column coordinates of a cell:
function TSampleCalendar.DayNum(ACol, ARow: Integer): Integer;
begin
Result := FMonthOffset + ACol + (ARow - 1) * 7; { calculate day for this cell }
1267
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
4. Now that you can calculate where the dates go, you can update DrawCell to fill in the dates:
procedure TCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
TheText: string;
TempDay: Integer;
begin
if ARow = 0 then { if this is the header row ...}
TheText := ShortDayNames[ACol + 1] { just use the day name }
else begin
TheText := ''; { blank cell is the default }
TempDay := DayNum(ACol, ARow); { get number for this cell }
if TempDay <> -1 then TheText := IntToStr(TempDay); { use the number if valid }
end;
with ARect, Canvas do
TextRect(ARect, Left + (Right - Left - TextWidth(TheText)) div 2,
Top + (Bottom - Top - TextHeight(TheText)) div 2, TheText);
end;
void __fastcall TSampleCalendar::DrawCell(int ACol, int ARow, const TRect &ARect,
TGridDrawState AState)
{
String TheText;
int TempDay;
if (ARow == 0) // this is the header row
TheText = ShortDayNames[ACol + 1]; // just use the day name
else
{
TheText = ""; // blank cell is the default
TempDay = DayNum(ACol, ARow); // get number for this cell
if (TempDay != -1) TheText = IntToStr(TempDay); // use the number if valid
}
Canvas->TextRect(ARect, ARect.Left + (ARect.Right - ARect.Left -
Canvas->TextWidth(TheText)) / 2,
ARect.Top + (ARect.Bottom - ARect.Top - Canvas->TextHeight(TheText)) / 2, TheText);
}
Now if you reinstall the calendar component and place one on a form, you will see the proper information for the current month.
When you override a method such as Click that is tied in with user interactions, you will nearly always include a call to the
inherited method, so as not to lose the standard behavior.
The following is an overridden Click method for the calendar grid. Be sure to add the declaration of Click to TSampleCalendar,
including the override directive afterward.
procedure TSampleCalendar.Click;
1268
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
var
TempDay: Integer;
begin
inherited Click; { remember to call the inherited method! }
TempDay := DayNum(Col, Row); { get the day number for the clicked cell }
if TempDay <> -1 then Day := TempDay; { change day if valid }
end;
void __fastcall TSampleCalendar::Click()
{
int TempDay = DayNum(Col, Row); // get the day number for the clicked cell
if (TempDay != -1) Day = TempDay; // change day if valid
}
The only drawback to encapsulating common manipulations into methods is that methods are only available at runtime.
However, such manipulations are generally only cumbersome when performed repeatedly, and that is fairly rare at design time.
For the calendar, add the following four methods for next and previous month and year. Each of these methods uses the
IncMonth function in a slightly different manner to increment or decrement CalendarDate, by increments of a month or a year.
procedure TCalendar.NextMonth;
begin
CalendarDate := IncMonth(CalendarDate, 1);
end;
procedure TCalendar.PrevMonth;
begin
CalendarDate := IncMonth(CalendarDate, -1);
end;
procedure TCalendar.NextYear;
begin
CalendarDate := IncMonth(CalendarDate, 12);
end;
procedure TCalendar.PrevYear; 3
begin
CalendarDate := DecodeDate(IncMonth(CalendarDate, -12);
end;
void __fastcall TSampleCalendar::NextMonth()
{
CalendarDate = IncMonth(CalendarDate, 1);
}
void __fastcall TSampleCalendar::PrevMonth()
{
CalendarDate = IncMonth(CalendarDate, -1);
1269
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
}
void __fastcall TSampleCalendar::NextYear()
{
CalendarDate = IncMonth(CalendarDate, 12);
}
void __fastcall TSampleCalendar::PrevYear()
{
CalendarDate = IncMonth(CalendarDate, -12);
}
Be sure to add the declarations of the new methods to the class declaration.
Now when you create an application that uses the calendar component, you can easily implement browsing through months or
years.
1270
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
3. Add statements calling Change to the end of the SetCalendarDate and SetDateElement methods:
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime);
begin
FDate := Value;
UpdateCalendar;
Change; { this is the only new statement }
end;
procedure TSampleCalendar.SetDateElement(Index: Integer; Value: Integer);
begin
. { many statements setting element values }
.
.
FDate := EncodeDate(AYear, AMonth, ADay);
UpdateCalendar;
Change; { this is new }
end;
end;
void __fastcall TSampleCalendar::SetCalendarDate(TDateTime Value)
{
FDate = Value;
UpdateCalendar();
Change(); // this is the only new statement
}
void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
{
.
.
. // many statements setting element values
FDate = TDateTime(AYear, AMonth, ADay);
UpdateCalendar();
Change(); // this is new
}
Applications using the calendar component can now respond to changes in the date of the component by attaching handlers to
the OnChange event.
To make inherited protected properties available to users of your components, redeclare the properties in the published part of
your component's declaration.
For the calendar control, publish the following properties and events, as shown here:
type
TSampleCalendar = class(TCustomGrid)
published
property Align; { publish properties }
property BorderStyle;
property Color;
property Font;
property GridLineWidth; 3
property ParentColor;
property ParentFont;
property OnClick; { publish events }
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnKeyDown;
property OnKeyPress;
1271
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
property OnKeyUp;
end;
class PACKAGE TSampleCalendar : public TCustomGrid
{
.
.
.
__published:
__property Align ; // publish properties
__property BorderStyle ;
__property Color ;
__property Font ;
__property GridLineWidth ;
__property ParentColor ;
__property ParentFont ;
__property OnClick ; // publish events
__property OnDblClick ;
__property OnDragDrop ;
__property OnDragOver ;
__property OnEndDrag ;
__property OnKeyDown ;
__property OnKeyPress ;
__property OnKeyUp ;
};
There are a number of other properties you could also publish, but which do not apply to a calendar, such as the Options
property that would enable the user to choose which grid lines to draw.
If you install the modified calendar component to the Tool palette and use it in an application, you will find many more properties
and events available in the calendar, all fully functional. You can now start adding new capabilities of your own design.
Creating a message-handling method is described in detail in the section Creating new message handlers. ( see page 1304)
In this case, the calendar control needs a response to WM_SIZE, so add a protected method called WMSize to the control
indexed to the WM_SIZE message, then write the method so that it calculates the proper cell size to allow all cells to be visible in
the new size:
type
TSampleCalendar = class(TCustomGrid)
protected
procedure WMSize(var Message: TWMSize); message WM_SIZE;
.
.
.
end;
3 .
.
.
procedure TSampleCalendar.WMSize(var Message: TWMSize);
var
GridLines: Integer; { temporary local variable }
begin
GridLines := 6 * GridLineWidth; { calculate combined size of all lines }
DefaultColWidth := (Message.Width - GridLines) div 7; { set new default cell width }
DefaultRowHeight := (Message.Height - GridLines) div 7; { and cell height }
end;
1272
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
//header file
class PACKAGE TSampleCalendar : public TCustomGrid
{
.
.
.
protected:
void __fastcall WMSize(TWMSize &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SIZE, TWMSize, WMSize)
END_MESSAGE_MAP(TCustomGrid)
};
//implementation file
void __fastcall TSampleCalendar::WMSize(TWMSize &Message)
{
int GridLines; // temporary local variable
GridLines = 6 * GridLineWidth; // calculated combined size of all lines
DefaultColWidth = (Message.Width - GridLines) / 7; // set new default cell width
DefaultRowHeight = (Message.Height - GridLines) / 7; // and cell height
}
Now when the calendar is resized, it displays all the cells in the largest size that will fit in the control.
In this case, the calendar control needs to override BoundsChanged so that it calculates the proper cell size to allow all cells to
be visible in the new size:
type
TSampleCalendar = class(TCustomGrid)
protected
procedure BoundsChanged; override;
.
.
.
end;
.
.
.
procedure TSampleCalendar.BoundsChanged;
var
GridLines: Integer; { temporary local variable }
begin
GridLines := 6 * GridLineWidth; { calculate combined size of all lines }
DefaultColWidth := (Width - GridLines) div 7; { set new default cell width }
DefaultRowHeight := (Height - GridLines) div 7; { and cell height }
inherited; {now call the inherited method }
end;
//header file
class PACKAGE TSampleCalendar : public TCustomGrid
{
.
.
.
protected:
void __fastcall BoundsChanged(void);
};
//implementation file
void __fastcall TSampleCalendar::BoundsChanged(void) 3
{
int GridLines; // temporary local variable
GridLines = 6 * GridLineWidth; // calculated combined size of all lines
DefaultColWidth = (Width - GridLines) / 7; // set new default cell width
DefaultRowHeight = (Height - GridLines) / 7; // and cell height
TCustomGrid::BoundsChanged(); // now call the inherited method
}
1273
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
To set the selection on the current day, change the UpdateCalendar method to set Row and Column before calling Refresh:
procedure TSampleCalendar.UpdateCalendar;
begin
if FDate <> 0 then
begin
. { existing statements to set FMonthOffset }
.
.
Row := (ADay - FMonthOffset) div 7 + 1;
Col := (ADay - FMonthOffset) mod 7;
end;
Refresh; { this is already here }
end;
void __fastcall TSampleCalendar::UpdateCalendar(void)
{
unsigned short AYear, AMonth, ADay;
TDateTime FirstDate;
if ((int) FDate != 0)
{
.
.
. // existing statements to set FMonthOffset
Row = (ADay - FMonthOffset) / 7 + 1;
Col = (ADay - FMonthOffset) % 7;
}
Refresh(); // this is already here
}
Note that you are now reusing the ADay variable previously set by decoding the date.
1274
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
{
private:
TDateTime FDate;
.
.
.
};
2. Initialize the date field in the constructor:
constructor TSampleCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { this is already here }
. { other initializations here }
.
.
FDate := Date; { get current date from RTL }
end;
__fastcall TSampleCalendar::TSampleCalendar(TComponent *Owner) : TCustomGrid(Owner)
{
.
.
.
FDate = FDate.CurrentDate();
}
3. Declare a runtime property to allow access to the encoded date. You'll need a method for setting the date, because setting the
date requires updating the onscreen image of the control:
type
TSampleCalendar = class(TCustomGrid)
private
procedure SetCalendarDate(Value: TDateTime);
public
property CalendarDate: TDateTime read FDate write SetCalendarDate;
.
.
.
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime);
begin
FDate := Value; { set new date value }
Refresh; { update the onscreen image }
end;
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
void __fastcall SetCalendarDate(TDateTime Value);
.
.
.
};
void __fastcall TSampleCalendar::SetCalendarDate(TDateTime Value)
{
FDate = Value; // Set the new date value
Refresh(); // Update the onscreen image
}
3
3.2.1.5.16 Tracking the Date
For the calendar control to be useful, users and applications must have a mechanism for setting the day, month, and year.
Delphi stores dates and times in variables of type TDateTime. TDateTime is an encoded numeric representation of the date and
time, which is useful for programmatic manipulation, but not convenient for human use.
You can therefore store the date in encoded form, providing runtime access to that value, but also provide Day, Month, and Year
properties that users of the calendar component can set at design time.
1275
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1276
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Installing the Wizard Package ( see page 1288) As with any other design-time package, a wizard package must have a Register
function. (See Registering components ( see page 1352) for details about the
Register function.) In the Register function, you can register any number of
wizards by calling RegisterPackageWizard, and passing a wizard object as the
sole argument, as shown below:
Interface Version Numbers ( see page 1288) If you look closely at the declarations of some of the interfaces, such as
IOTAMessageServices, you will see that they inherit from other interfaces with
similar names, such as IOTAMessageServices50, which inherits from
IOTAMessageServices40. This use of version numbers helps insulate your code
from changes between releases of Delphi.
The Tools API follows the basic principle of COM, namely, that an interface and
its GUID never change. If a new release adds features to an interface, the Tools
API declares a new interface that inherits from the old one. The GUID remains
the same, attached to the... more ( see page 1288)
Notifying a Wizard of IDE Events ( see page 1289) An important aspect of writing a well-behaved wizard is to have the wizard
respond to IDE events. In particular, any wizard that keeps track of module
interfaces must know when the user closes the module, so the wizard can
release the interface. To do this, the wizard needs a notifier, which means you
must write a notifier class.
All notifier classes implement one or more notifier interfaces. The notifier
interfaces define callback methods; the wizard registers a notifier object with the
Tools API, and the IDE calls back to the notifier when something important
happens.
Every notifier interface inherits from... more ( see page 1289)
Obtaining Tools API Services ( see page 1293) To do anything useful, a wizard needs access to the IDE: its editors, windows,
menus, and so on. This is the role of the service interfaces. The Tools API
includes many services, such as action services to perform file actions, editor
services to access the source code editor, debugger services to access the
debugger, and so on. The following table summarizes all the service interfaces.
Tools API service interfaces
Overview of the Tools API ( see page 1294) All of the Tools API declarations reside in a single unit, ToolsAPI. To use the
Tools API, you typically use the designide package, which means you must build
your Tools API add-in as a design-time package or as a DLL that uses runtime
packages. For information about package and library issues, see Installing the
wizard package ( see page 1288).
The main interface for writing a Tools API extension is IOTAWizard, so most IDE
add-ins are called wizards. C++Builder and Delphi wizards are, for the most part,
interoperable. You can write and compile a wizard in Delphi, then use it in
C++Builder,... more ( see page 1294)
Using Editor Interfaces ( see page 1295) Every module has at least one editor interface. Some modules have several
editors, such as a source (.pas) file and form description (.dfm) file. All editors
implement the IOTAEditor interface; cast the editor to a specific type to learn
what kind of editor it is. For example, to obtain the form editor interface for a unit,
you can do the following:
Using Module Interfaces ( see page 1296) To obtain a module interface, start with the module services
(IOTAModuleServices). You can query the module services for all open modules,
look up a module from a file name or form name, or open a file to obtain its
module interface.
There are different kinds of modules for different kinds of files, such as projects,
resources, and type libraries. Cast a module interface to a specific kind of module
interface to learn whether the module is of that type. For example, one way to
obtain the current project group interface is as follows:
Using Native IDE Objects ( see page 1297) Wizards have full access to the main menu, tool bars, action list, and image list of
the IDE. (Note that the IDE's many context menus are not accessible through the
Tools API.)
The starting point for working with native IDE objects is the INTAServices
interface. Use this interface to add an image to the image list, an action to the
action list, a menu item to the main menu, and a button to a tool bar. You can tie
the action to the menu item and tool button. When the wizard is destroyed, it
must clean up the objects it... more ( see page 1297)
Working with Files and Editors ( see page 1297) It is important to understand how the Tools API works with files. The main 3
interface is IOTAModule. A module represents a set of logically related open
files. For example, a single module represents a single unit. The module, in turn,
has one or more editors, where each editor represents one file, such as the unit
source (.pas) or form (.dfm or .xfm) file. The editor interfaces reflect the internal
state of the IDE's editors, so a wizard can see the modified code and forms that
the user sees, even if the user has not saved any changes.
The following... more ( see page 1297)
1277
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Writing a Wizard Class ( see page 1297) There are four kinds of wizards, where the wizard kind depends on the interfaces
that the wizard class implements. The following table describes the four kinds of
wizards.
The four kinds of wizards
1278
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
See Also
Adding an Image to the Image List ( see page 1279)
See Also
Adding an Action to the Action List ( see page 1278)
A creator class implements a creator interface, which inherits from IOTACreator. The wizard passes a creator object to the
module service's CreateModule method, and the IDE calls back to the creator object for the parameters it needs to create the
module.
1279
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
For example, a form wizard that creates a new form typically implements GetExisting to return false and GetUnnamed to return
true. This creates a module that has no name (so the user must pick a name before the file can be saved) and is not backed by
an existing file (so the user must save the file even if the user does not make any changes). Other methods of the creator tell the
IDE what kind of file is being created (e.g., project, unit, or form), provide the contents of the file, or return the form name,
ancestor name, and other important information. Additional callbacks let a wizard add modules to a newly created project, or add
components to a newly created form.
To create a new file, which is often required in a form or project wizard, you usually need to provide the contents of the new file.
To do so, write a new class that implements the IOTAFile interface. If your wizard can make do with the default file contents, you
can return nil from any function that returns IOTAFile.
For example, suppose your organization has a standard comment block that must appear at the top of each source file. You
could do this with a static template in the Object Repository, but the comment block would need to be updated manually to reflect
the author and creation date. Instead, you can use a creator to dynamically fill in the comment block when the file is created.
The first step is to write a wizard that creates new units and forms. Most of the creator's functions return zero, empty strings, or
other default values, which tells the Tools API to use its default behavior for creating a new unit or form. Override
GetCreatorType to inform the Tools API what kind of module to create: a unit or a form. To create a unit, return sUnit. To create
a form, return sForm. To simplify the code, use a single class that takes the creator type as an argument to the constructor. Save
the creator type in a data member, so that GetCreatorType can return its value. Implement NewImplSource and NewIntfSource
to return the desired file contents.
TCreator = class(TInterfacedObject, IOTAModuleCreator)
public
constructor Create(const CreatorType: string);
{ IOTAModuleCreator }
function GetAncestorName: string;
function GetImplFileName: string;
function GetIntfFileName: string;
function GetFormName: string;
function GetMainForm: Boolean;
function GetShowForm: Boolean;
function GetShowSource: Boolean;
function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;
function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
function NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
procedure FormCreated(const FormEditor: IOTAFormEditor);
{ IOTACreator }
function GetCreatorType: string;
function GetExisting: Boolean;
function GetFileSystem: string;
function GetOwner: IOTAModule;
function GetUnnamed: Boolean;
private
FCreatorType: string;
end;
class PACKAGE Creator : public IOTAModuleCreator {
public:
__fastcall Creator(const AnsiString creator_type)
: ref_count(0), creator_type(creator_type) {}
virtual __fastcall ~Creator();
// IOTAModuleCreator
3 virtual AnsiString __fastcall GetAncestorName();
virtual AnsiString __fastcall GetImplFileName();
virtual AnsiString __fastcall GetIntfFileName();
virtual AnsiString __fastcall GetFormName();
virtual bool __fastcall GetMainForm();
virtual bool __fastcall GetShowForm();
virtual bool __fastcall GetShowSource();
virtual _di_IOTAFile __fastcall NewFormFile(
const AnsiString FormIdent, const AnsiString AncestorIdent);
virtual _di_IOTAFile __fastcall NewImplSource(
1280
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1281
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
_di_IOTAProject project;
_di_IOTAProjectGroup group;
if (module->Supports(project)) {
// Remember the first project module.
if (result == 0)
result = project;
} else if (module->Supports(group)) {
// Found the project group, so return its active project.
result = group->ActiveProject;
break;
}
}
return result;
}
The creator returns nil from NewFormSource, to generate a default form file. The interesting methods are NewImplSource and
NewIntfSource, which create an IOTAFile instance that returns the file contents.
The TFile class implements the IOTAFile interface. It returns -1 as the file age (which means the file does not exist), and returns
the file contents as a string. To keep the TFile class simple, the creator generates the string, and the TFile class simply passes it
on.
TFile = class(TInterfacedObject, IOTAFile)
public
constructor Create(const Source: string);
function GetSource: string;
function GetAge: TDateTime;
private
FSource: string;
end;
constructor TFile.Create(const Source: string);
begin
FSource := Source;
end;
function TFile.GetSource: string;
begin
Result := FSource;
end;
function TFile.GetAge: TDateTime;
begin
Result := TDateTime(-1);
end;
class File : public IOTAFile {
public:
__fastcall File(const AnsiString source);
virtual __fastcall ~File();
AnsiString __fastcall GetSource();
System::TDateTime __fastcall GetAge();
protected:
// IInterface
virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
private:
long ref_count;
3 AnsiString source;
};
__fastcall File::File(const AnsiString source)
: ref_count(0), source(source)
{}
AnsiString __fastcall File::GetSource()
{
return source;
}
System::TDateTime __fastcall File::GetAge()
{
1282
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
return -1;
}
You can store the text for the file contents in a resource to make it easier to modify, but for the sake of simplicity, this example
hardcodes the source code in the wizard. The example below generates the source code, assuming there is a form. You can
easily add the simpler case of a plain unit. Test FormIdent, and if it is empty, create a plain unit; otherwise create a form unit.
The basic skeleton for the code is the same as the IDE's default (with the addition of the comments at the top, of course), but you
can modify it any way you desire.
function TCreator.NewImplSource(
const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
var
FormSource: string;
begin
FormSource :=
'{ ----------------------------------------------------------------- ' + #13#10 +
'%s - description'+ #13#10 +
'Copyright © %y Your company, inc.'+ #13#10 +
'Created on %d'+ #13#10 +
'By %u'+ #13#10 +
' ----------------------------------------------------------------- }' + #13#10 + #13#10;
return TFile.Create(Format(FormSource, ModuleIdent, FormIdent,
AncestorIdent));
}
_di_IOTAFile __fastcall Creator::NewImplSource(
const AnsiString ModuleIdent,
const AnsiString FormIdent,
const AnsiString AncestorIdent)
{
const AnsiString form_source =
"/*-----------------------------------------------------------------\n"
" %m - description\n"
" Copyright \xa9 %y Your company, inc.\n"
" Created on %d\n"
" By %u\n"
" ---------------------------------------------------------------*/\n"
"\n"
"#include <vcl.h>\n"
"#pragma hdrstop\n"
"\n"
"#include \"%m.h\"\n"
"//-----------------------------------------------------------------\n"
"#pragma package(smart_init)\n"
"#pragma resource \"*.dfm\"\n"
"T%f *%f;\n"
"//-----------------------------------------------------------------\n"
"__fastcall T%m::T%m(TComponent* Owner)\n"
" : T%a(Owner)\n"
"{\n"
"}\n"
"//----------------------------------------------------------------\n";
return new File(expand(form_source, ModuleIdent, FormIdent,
AncestorIdent));
}
The final step is to create two form wizards: one uses sUnit as the creator type, and the other uses sForm. As an added benefit 3
for the user, you can use INTAServices to add a menu item to the File New menu to invoke each wizard. The menu item's
OnClick event handler can call the wizard's Execute function.
Some wizards need to enable or disable the menu items, depending on what else is happening in the IDE. For example, a
wizard that checks a project into a source code control system should disable its Check In menu item if no files are open in the
IDE. You can add this capability to your wizard by using notifiers ( see page 1289).
1283
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
See Also
Working with Files and Editors ( see page 1297)
When writing wizards that use the native tools API, you can write code that causes the IDE to crash. It is also possible that you
write a wizard that installs but does not act the way you want it to. One of the challenges of working with design-time code is
debugging. It's an easy problem to solve, however. Because the wizard is installed in Delphi itself, you simply need to set the
package's Host Application to the Delphi executable from the Run Parameters... menu item.
When you want (or need) to debug the package, don't install it. Instead, choose Run Run from the menu bar. This starts up a
new instance of Delphi. In the new instance, install the already-compiled package by choosing Components Install
Package... from the menu bar. Back in the original instance of Delphi, you should now see the telltale blue dots that tell you
where you can set breakpoints in the wizard source code. (If not, double-check your compiler options to be sure you enabled
debugging; make sure you loaded the right package; and double-check the process modules to make extra sure that you loaded
the .bpl file you wanted to load.)
You cannot debug into the VCL or RTL code this way, but you have full debug capabilities for the wizard itself, which might be
enough to tell what is going wrong.
See Also
Using Native IDE Objects ( see page 1297)
1284
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
remove_action(NewAction, Services.ToolBar[sDesktopToolBar]);
remove_action(NewAction, Services.ToolBar[sStandardToolBar]);
remove_action(NewAction, Services.ToolBar[sDebugToolBar]);
remove_action(NewAction, Services.ToolBar[sViewToolBar]);
remove_action(NewAction, Services.ToolBar[sInternetToolBar]);
NewItem.Free;
NewAction.Free;
end;
void __fastcall remove_action (TAction* action, TToolBar* toolbar)
{
for (int i = toolbar->ButtonCount; --i >= 0; )
{
TToolButton* button = toolbar->Buttons[i];
if (button->Action == action)
{
// Remove "button" from "toolbar".
toolbar->Perform(CM_CONTROLCHANGE, WPARAM(button), 0);
delete button;
}
}
}
__fastcall MyWizard::~MyWizard()
{
_di_INTAServices services;
BorlandIDEServices->Supports(services);
// Check all the toolbars, and remove any buttons that use
// this action.
remove_action(action, services->ToolBar[sCustomToolBar]);
remove_action(action, services->ToolBar[sDesktopToolBar]);
remove_action(action, services->ToolBar[sStandardToolBar]);
remove_action(action, services->ToolBar[sDebugToolBar]);
remove_action(action, services->ToolBar[sViewToolBar]);
remove_action(action, services->ToolBar[sInternetToolBar]);
delete menu_item;
delete action;
}
See Also
Adding an Image to the Image List ( see page 1279)
Using the Tools API is simply a matter of writing classes that implement certain interfaces, and calling on services provided by
other interfaces. Your Tools API code must be compiled and loaded into the IDE at design-time as a design-time package or in a
DLL. Thus, writing a Tools API extension is somewhat like writing a property or component editor. Before tackling this material, 3
make sure you are familiar with the basics of working with packages ( see page 2211) and registering components ( see page
1350).
Note: To enable the use of the Tools API, you must link with runtime packages and ensure that “designide” is listed as one of
the packages you are linking with. In the IDE, you can do this on the Project->Options->Packages
dialog box. If you are building from the command line, make sure that -LUdesignide is passed to dcc32.exe. The following
topics describe how to use the Tools API:
1285
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
For C++, to use NotifierObject as a base class you must use multiple inheritance. Your wizard class must inherit from
NotifierObject and from the wizard interfaces that you need to implement, such as IOTAWizard. Because IOTAWizard inherits
from IOTANotifier and IInterface, there is an ambiguity in the derived class: functions such as AddRef() are declared in every
branch of the ancestral inheritance graph. To resolve this problem, pick one base class as the primary base class and delegate
all ambiguous functions to that one class. For example, the class declaration might look as follows:
class PACKAGE MyWizard : public NotifierObject, public IOTAMenuWizard {
typedef NotifierObject inherited;
public:
// IOTAWizard
virtual AnsiString __fastcall GetIDString();
virtual AnsiString __fastcall GetName();
virtual TWizardState __fastcall GetState();
virtual void __fastcall Execute();
// IOTAMenuWizard
virtual AnsiString __fastcall GetMenuText();
void __fastcall AfterSave();
void __fastcall BeforeSave();
void __fastcall Destroyed();
void __fastcall Modified();
protected:
// IInterface
virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
};
// implementation
ULONG __stdcall MyWizard::AddRef() { return inherited::AddRef(); }
ULONG __stdcall MyWizard::Release() { return inherited::Release(); }
HRESULT __stdcall MyWizard::QueryInterface(const GUID& iid, void** obj)
{
if (iid == __uuidof(IOTAMenuWizard)) {
3 *obj = static_cast<IOTAMenuWizard*>(this);
static_cast<IOTAMenuWizard*>(*obj)->AddRef();
return S_OK;
}
if (iid == __uuidof(IOTAWizard)) {
*obj = static_cast<IOTAWizard*>(this);
static_cast<IOTAWizard*>(*obj)->AddRef();
return S_OK;
}
return inherited::QueryInterface(iid, obj);
}
1286
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Your implementation of IInterface must follow the normal rules for Delphi interfaces, which are the same as the rules for COM
interfaces. That is, QueryInterface performs type casts, and _AddRef and _Release manage reference counting. You might want
to use a common base class to simplify writing wizard and notifier classes. For this purpose, the ToolsAPI unit defines a class,
TNotifierObject, which implements IOTANotifier interface with empty method bodies.
1287
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Remember that a design-time package is part of the main RAD Studio application, which means any form names must be unique
throughout the entire application and all other design-time packages. This is the main disadvantage to using packages: you
never know what someone else might name their forms.
During development, install the wizard package the way you would any other design-time package: click the Install button in the
package manager. The IDE will compile and link the package and attempt to load it. The IDE displays a dialog box telling you
whether it successfully loaded the package.
See Also
Implementing the Wizard Interfaces ( see page 1286)
The Tools API follows the basic principle of COM, namely, that an interface and its GUID never change. If a new release adds
features to an interface, the Tools API declares a new interface that inherits from the old one. The GUID remains the same,
attached to the old, unchanged interface. The new interface gets a brand new GUID. Old wizards that use the old GUIDs
continue to work.
The Tools API also changes interface names to try to preserve source-code compatibility. To see how this works, it is important
to distinguish between the two kinds of interfaces in the Tools API: Borland-implemented and user-implemented. If the IDE
implements the interface, the name stays with the most recent version of the interface. The new functionality does not affect
existing code. The old interfaces have the old version number appended.
3 For a user-implemented interface, however, new member functions in the base interface require new functions in your code.
Therefore, the name tends to stick with the old interface, and the new interface has a version number tacked onto the end.
For example, consider the message services. Delphi 6 introduced a new feature: message groups. Therefore, the basic
message services interface required new member functions. These functions were declared in a new interface class, which
retained the name IOTAMessageServices. The old message services interface was renamed to IOTAMessageServices50 (for
version 5). The GUID of the old IOTAMessageServices is the same as the GUID of the new IOTAMessageServices50 because
the member functions are the same.
1288
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Consider IOTAIDENotifier as an example of a user-implemented interface. Delphi 5 added new overloaded functions:
AfterCompile and BeforeCompile. Existing code that used IOTAIDENotifier did not need to change, but new code that required
the new functionality had to be modified to override the new functions inherited from IOTAIDENotifier50. Version 6 did not add
any more functions, so the current version to use is IOTAIDENotifier50.
The rule of thumb is to use the most-derived class when writing new code. Leave the source code alone if you are merely
recompiling an existing wizard under a new release of Delphi.
See Also
Obtaining Tools API Services ( see page 1293)
All notifier classes implement one or more notifier interfaces. The notifier interfaces define callback methods; the wizard registers
a notifier object with the Tools API, and the IDE calls back to the notifier when something important happens.
Every notifier interface inherits from IOTANotifier, although not all of its methods are used for a particular notifier. The following
table lists all the notifier interfaces, and gives a brief description of each one.
Notifier interfaces
Interface Description
IOTANotifier Abstract base class for all notifiers
IOTABreakpointNotifier Triggering or changing a breakpoint in the debugger
IOTADebuggerNotifier Running a program in the debugger, or adding or deleting breakpoints
IOTAEditLineNotifier Tracking movements of lines in the source editor
IOTAEditorNotifier Modifying or saving a source file, or switching files in the editor
IOTAFormNotifier Saving a form, or modifying the form or any components on the form (or data module)
IOTAIDENotifier Loading projects, installing packages, and other global IDE events
IOTAMessageNotifier Adding or removing tabs (message groups) in the message view
IOTAModuleNotifier Changing, saving, or renaming a module
IOTAProcessModNotifier Loading a process module in the debugger
IOTAProcessNotifier Creating or destroying threads and processes in the debugger
IOTAThreadNotifier Changing a thread's state in the debugger
IOTAToolsFilterNotifier Invoking a tools filter
To see how to use notifiers, consider the example in Creating forms and projects ( see page 1279). Using module creators, the
example creates a wizard that adds a comment to each source file. The comment includes the unit's initial name, but the user 3
almost always saves the file under a different name. In that case, it would be a courtesy to the user if the wizard updated the
comment to match the file's true name.
To do this, you need a module notifier. The wizard saves the module interface that CreateModule returns, and uses it to register
a module notifier. The module notifier receives notification when the user modifies the file or saves the file, but these events are
not important for this wizard, so the AfterSave and related functions all have empty bodies. The important function is
ModuleRenamed, which the IDE calls when the user saves the file under a new name. The declaration for the module notifier
class is shown below:
1289
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1290
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
end;
FModule := nil;
end;
__fastcall ModuleNotifier::ModuleNotifier(const _di_IOTAModule module)
: index(-1), module(module)
{
// Register this notifier.
index = module->AddNotifier(this);
// Remember the module's old name.
name = ChangeFileExt(ExtractFileName(module->FileName), "");
}
__fastcall ModuleNotifier::~ModuleNotifier()
{
// Unregister the notifier if that hasn't happened already.
if (index >= 0)
module->RemoveNotifier(index);
}
void __fastcall ModuleNotifier::Destroyed()
{
// The module interface is being destroyed, so clean up the notifier.
if (index >= 0)
{
// Unregister the notifier.
module->RemoveNotifier(index);
index = -1;
}
module = 0;
}
The IDE calls back to the notifier's ModuleRenamed function when the user renames the file. The function takes the new name
as a parameter, which the wizard uses to update the comment in the file. To edit the source buffer, the wizard uses an edit
position interface. The wizard finds the right position, double checks that it found the right text, and replaces that text with the
new name.
procedure TModuleNotifier.ModuleRenamed(const NewName: string);
var
ModuleName: string;
I: Integer;
Editor: IOTAEditor;
Buffer: IOTAEditBuffer;
Pos: IOTAEditPosition;
Check: string;
begin
{ Get the module name from the new file name. }
ModuleName := ChangeFileExt(ExtractFileName(NewName), '');
for I := 0 to FModule.GetModuleFileCount - 1 do
begin
{ Update every source editor buffer. }
Editor := FModule.GetModuleFileEditor(I);
if Supports(Editor, IOTAEditBuffer, Buffer) then
begin
Pos := Buffer.GetEditPosition;
{ The module name is on line 2 of the comment.
Skip leading white space and copy the old module name,
to double check we have the right spot. }
Pos.Move(2, 1); 3
Pos.MoveCursor(mmSkipWhite or mmSkipRight);
Check := Pos.RipText('', rfIncludeNumericChars or rfIncludeAlphaChars);
if Check = FName then
begin
Pos.Delete(Length(Check)); // Delete the old name.
Pos.InsertText(ModuleName); // Insert the new name.
FName := ModuleName; // Remember the new name.
end;
end;
end;
1291
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
end;
void __fastcall ModuleNotifier::ModuleRenamed(const AnsiString NewName)
{
// Get the module name from the new file name.
AnsiString ModuleName = ChangeFileExt(ExtractFileName(NewName), "");
for (int i = 0; i < module->GetModuleFileCount(); ++i)
{
// Update every source editor buffer.
_di_IOTAEditor editor = module->GetModuleFileEditor(i);
_di_IOTAEditBuffer buffer;
if (editor->Supports(buffer))
{
_di_IOTAEditPosition pos = buffer->GetEditPosition();
// The module name is on line 2 of the comment.
// Skip leading white space and copy the old module name,
// to double check we have the right spot.
pos->Move(2, 1);
pos->MoveCursor(mmSkipWhite | mmSkipRight);
AnsiString check = pos->RipText("", rfIncludeNumericChars | rfIncludeAlphaChars);
if (check == name)
{
pos->Delete(check.Length()); // Delete the old name.
pos->InsertText(ModuleName); // Insert the new name.
name = ModuleName; // Remember the new name.
}
}
}
}
What if the user inserts additional comments above the module name? In that case, you need to use an edit line notifier to keep
track of the line number where the module name sits. To do this, use the IOTAEditLineNotifier and IOTAEditLineTracker
interfaces.
You need to be cautious when writing notifiers. You must make sure that no notifier outlives its wizard. For example, if the user
were to use the wizard to create a new unit, then unload the wizard, there would still be a notifier attached to the unit. The results
would be unpredictable, but most likely, the IDE would crash. Thus, the wizard needs to keep track of all of its notifiers, and must
unregister every notifier before the wizard is destroyed. On the other hand, if the user closes the file first, the module notifier
receives a Destroyed notification, which means the notifier must unregister itself and release all references to the module. The
notifier must remove itself from the wizard's master notifier list, too.
Below is the final version of the wizard's Execute function. It creates the new module, uses the module interface and creates a
module notifier, then saves the module notifier in an interface list (TInterfaceList).
procedure DocWizard.Execute;
var
Svc: IOTAModuleServices;
Module: IOTAModule;
Notifier: IOTAModuleNotifier;
begin
{ Return the current project. }
Supports(BorlandIDEServices, IOTAModuleServices, Svc);
Module := Svc.CreateModule(TCreator.Create(creator_type));
Notifier := TModuleNotifier.Create(Module);
list.Add(Notifier);
3 end
void __fastcall DocWizard::Execute()
{
_di_IOTAModuleServices svc;
BorlandIDEServices->Supports(svc);
_di_IOTAModule module = svc->CreateModule(new Creator(creator_type));
_di_IOTAModuleNotifier notifier = new ModuleNotifier(module);
list->Add(notifier);
}
The wizard's destructor iterates over the interface list and unregisters every notifier in the list. Simply letting the interface list
1292
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
release the interfaces it holds is not sufficient because the IDE also holds the same interfaces. You must tell the IDE to release
the notifier interfaces in order to free the notifier objects. In this case, the destructor tricks the notifiers into thinking their modules
have been destroyed. In a more complicated situation, you might find it best to write a separate Unregister function for the
notifier class.
destructor DocWizard.Destroy; override;
var
Notifier: IOTAModuleNotifier;
I: Integer;
begin
{ Unregister all the notifiers in the list. }
for I := list.Count - 1 downto 0 do
begin
Supports(list.Items[I], IOTANotifier, Notifier);
{ Pretend the associated object has been destroyed.
That convinces the notifier to clean itself up. }
Notifier.Destroyed;
list.Delete(I);
end;
list.Free;
FItem.Free;
end;
__fastcall DocWizard::~DocWizard()
{
// Unregister all the notifiers in the list.
for (int i = list->Count; --i >= 0; )
{
_di_IOTANotifier notifier;
list->Items[i]->Supports(notifier);
// Pretend the associated object has been destroyed.
// That convinces the notifier to clean itself up.
notifier->Destroyed();
list->Delete(i);
}
delete list;
delete item;
}
The rest of the wizard manages the mundane details of registering the wizard, installing menu items, and the like.
See Also
Obtaining Tools API Services ( see page 1293)
1293
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
To use a service interface, cast the BorlandIDEServices variable to the desired service using the global Supports function, which
is defined in the SysUtils unit. For example,
procedure set_keystroke_debugging(debugging: Boolean);
var
diag: IOTAKeyboardDiagnostics
begin
if Supports(BorlandIDEServices, IOTAKeyboardDiagnostics, diag) then
diag.KeyTracing := debugging;
end;
void set_keystroke_debugging(bool debugging)
{
_di_IOTAKeyboardDiagnostics diag;
if (BorlandIDEServices->Supports(diag))
diag->KeyTracing = debugging;
}
If your wizard needs to use a specific service often, you can keep a pointer to the service as a data member of your wizard class.
The following topics discuss special considerations when working with the Tools API service interfaces:
3
3.2.1.6.12 Overview of the Tools API
All of the Tools API declarations reside in a single unit, ToolsAPI. To use the Tools API, you typically use the designide package,
which means you must build your Tools API add-in as a design-time package or as a DLL that uses runtime packages. For
information about package and library issues, see Installing the wizard package ( see page 1288).
The main interface for writing a Tools API extension is IOTAWizard, so most IDE add-ins are called wizards. C++Builder and
Delphi wizards are, for the most part, interoperable. You can write and compile a wizard in Delphi, then use it in C++Builder, and
1294
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
vice versa. Interoperability works best with the same version number, but it is also possible to write wizards so they can be used
in future versions of both products.
To use the Tools API, you write wizard classes that implement one or more of the interfaces defined in the ToolsAPI unit.
A wizard makes use of services that the Tools API provides. Each service is an interface that presents a set of related functions.
The implementation of the interface is hidden within the IDE. The Tools API publishes only the interface, which you can use to
write your wizards without concerning yourself with the implementation of the interfaces. The various services offer access to the
source editor, form designer, debugger, and so on. See Obtaining Tools API services ( see page 1293) for information about
using the interfaces that expose services to your wizard.
The service and other interfaces fall into two basic categories. You can tell them apart by the prefix used for the type name:
• The NTA (native tools API) grants direct access to actual IDE objects, such as the IDE's TMainMenu object. When using
these interfaces, the wizard must use CodeGear packages, which also means the wizard is tied to a specific version of the
IDE. The wizard can reside in a design-time package or in a DLL that uses runtime packages.
• The OTA (open tools API) does not require packages and accesses the IDE only through interfaces. In theory, you could write
a wizard in any language that supports COM-style interfaces, provided you can also work with the Delphi calling conventions
and Delphi types such as AnsiString. OTA interfaces do not grant full access to the IDE, but almost all the functionality of the
Tools API is available through OTA interfaces. If a wizard uses only OTA interfaces, it is possible to write a DLL that is not
dependent on a specific version of the IDE.
The Tools API has two kinds of interfaces: those that you, the programmer, must implement and those that the IDE implements.
Most of the interfaces are in the latter category: the interfaces define the capability of the IDE but hide the actual
implementation. The kinds of interfaces that you must implement fall into three categories: wizards, notifiers, and creators:
• As mentioned earlier in this topic, a wizard class implements the IOTAWizard interface and possibly derived interfaces.
• A notifier is another kind of interface in the Tools API. The IDE uses notifiers to call back to your wizard when something
interesting happens. You write a class that implements the notifier interface, register the notifier with the Tools API, and the
IDE calls back to your notifier object when the user opens a file, edits source code, modifies a form, starts a debugging
session, and so on. Notifiers are covered in Notifying a wizard of IDE events ( see page 1289) .
• A creator is another kind of interface that you must implement. The Tools API uses creators to create new units, projects, or
other files, or to open existing files. See Creating forms and projects ( see page 1279) for information about creator
interfaces.
Other important interfaces are modules and editors. A module interface represents an open unit, which has one or more files. An
editor interface represents an open file. Different kinds of editor interfaces give you access to different aspects of the IDE: the
source editor for source files, the form designer for form files, and project resources for a resource file. See Working with files
and editors ( see page 1297) for information about module and editor interfaces.
1295
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
// Return the form editor for a module, or 0 if the unit has no form.
_di_IOTAFormEditor __fastcall GetFormEditor(_di_IOTAModule module)
{
for (int i = 0; i < module->ModuleFileCount; ++i)
{
_di_IOTAEditor editor = module->ModuleFileEditors[i];
_di_IOTAFormEditor formEditor;
if (editor->Supports(formEditor))
return formEditor;
}
return 0;
}
The editor interfaces give you access to the editor's internal state. You can examine the source code or components that the
user is editing, make changes to the source code, components, or properties, change the selection in the source and form
editors, and carry out almost any editor action that the end user can perform.
Using a form editor interface, a wizard can access all the components on the form. Each component (including the root form or
data module) has an associated IOTAComponent interface. A wizard can examine or change most of the component's
properties. If you need complete control over the component, you can cast the IOTAComponent interface to INTAComponent.
The native component interface enables your wizard to access the TComponent pointer directly. This is important if you need to
read or modify a class-type property, such as TFont, which is possible only through NTA-style interfaces.
See Also
Using Module Interfaces ( see page 1296)
There are different kinds of modules for different kinds of files, such as projects, resources, and type libraries. Cast a module
interface to a specific kind of module interface to learn whether the module is of that type. For example, one way to obtain the
current project group interface is as follows:
{ Return the current project group, or nil if there is no project group. }
function CurrentProjectGroup: IOTAProjectGroup;
var
I: Integer;
Svc: IOTAModuleServices;
Module: IOTAModule;
begin
Supports(BorlandIDEServices, IOTAModuleServices, Svc);
for I := 0 to Svc.ModuleCount - 1 do
begin
Module := Svc.Modules[I];
if Supports(Module, IOTAProjectGroup, Result) then
Exit;
end;
Result := nil;
end;
3 // Return the current project group, or 0 if there is no project group.
_di_IOTAProjectGroup __fastcall CurrentProjectGroup()
{
_di_IOTAModuleServices svc;
BorlandIDEServices->Supports(svc);
for (int i = 0; i < svc->ModuleCount; ++i)
{
_di_IOTAModule module = svc->Modules[i];
_di_IOTAProjectGroup group;
if (module->Supports(group))
return group;
1296
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
}
return 0;
}
See Also
Using Editor Interfaces ( see page 1295)
The starting point for working with native IDE objects is the INTAServices interface. Use this interface to add an image to the
image list, an action to the action list, a menu item to the main menu, and a button to a tool bar. You can tie the action to the
menu item and tool button. When the wizard is destroyed, it must clean up the objects it creates, but it must not delete the image
it added to the image list. Deleting an image would scramble the indices for all images added after this wizard.
The wizard uses the actual TMainMenu, TActionList, TImageList, and TToolBar objects from the IDE, so you can write code the
way you would any other application. It also means you have a lot of scope for crashing the IDE or otherwise disabling important
features, such as deleting the File menu. Debugging a wizard ( see page 1284) discusses steps you can take to debug your
wizard if you find it has caused problems like these.
The following topics provide information about the module and editor interfaces:
1297
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Interface Description
IOTAFormWizard Typically creates a new unit, form, or other file
IOTAMenuWizard Automatically added to Help menu
IOTAProjectWizard Typically creates a new application or other project
IOTAWizard Miscellaneous wizard that doesn't fit into other categories
The four kinds of wizards differ only in how the user invokes the wizard:
• A menu wizard is added to the IDE's Help menu. When the user picks the menu item, the IDE calls the wizard's Execute
function. Plain wizards offer much more flexibility, so menu wizards are typically used only for prototypes and debugging.
• Form and project wizards are called repository wizards because they reside in the Object Repository. The user invokes these
wizards from the New Items dialog box. The user can also see the wizards in the object repository (by choosing the
Tools Repository menu item). The user can check the New Form check box for a form wizard, which tells the IDE to invoke
the form wizard when the user chooses the File New Form menu item. The user can also check the Main Form check
box. This tells the IDE to use the form wizard as the default form for a new application. The user can check the New Project
check box for a project wizard. When the user chooses File New Application, the IDE invokes the selected project
wizard.
• The fourth kind of wizard is for situations that don't fit into the other categories. A plain wizard does not do anything
automatically or by itself. Instead, you must define how the wizard is invoked.
The Tools API does not enforce any restrictions on wizards, such as requiring a project wizard to create a project. You can just
as easily write a project wizard to create a form and a form wizard to create a project (if that's something you really want to
do).
The following topics provide details on how to implement and install a wizard:
• Implementing the wizard interfaces ( see page 1286)
• Installing the wizard package ( see page 1288)
1298
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Responding to System Events ( see page 1302) When the widget layer receives an event notification from the operating system, it
generates a special event object (QEvent or one of its descendants) to represent
the event. The event object contains read-only information about the event that
occurred. The type of the event object indicates the type of event that occurred.
The widget layer notifies your CLX component of system events using a special
signal of type event. It passes the QEvent object to the signal handler for the
event. The processing of the event signal is a bit more complicated than
processing other signals because it goes... more ( see page 1302)
Sending a Message That Does Not Execute Immediately ( see page 1303) There are times you may want to send a message but you do not know whether it
is safe for the target of the message to execute right away. For example, if the
code that sends a message is called from an event handler on the target control,
you may want to make sure that the event handler has finished executing before
the control executes your message. You can handle this situation as long as you
do not need to know the message result.
Use the Windows API call, PostMessage, to send a message to a control but
allow... more ( see page 1303)
Sending a Message Using the Windows Message Queue ( see page 1303) In a multithreaded application, you can't just call the Perform method because
the target control is in a different thread than the one that is executing. However,
by using the Windows message queue, you can safely communicate with other
threads. Message handling always occurs in the main VCL thread, but you can
send a message using the Windows message queue from any thread in the
application. A call to SendMessage is synchronous. That is, SendMessage does
not return until the target control has handled the message, even if it is in another
thread.
Use the Windows API call, SendMessage,... more ( see page 1303)
Sending Messages ( see page 1303) Typically, an application sends message to send notifications of state changes or
to broadcast information. Your component can broadcast messages to all the
controls in a form, send messages to a particular control (or to the application
itself), or even send messages to itself.
There are several different ways to send a Windows message. Which method
you use depends on why you are sending the message. The following topics
describe the different ways to send Windows messages:
1299
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Example: Message Structure ( see page 1305) For example, here is the message record for all mouse messages, TWMMouse,
which uses a variant record to define two sets of names for the same
parameters.
Declaring a Message-structure Type ( see page 1305) If you want to give useful names to the parameters of your message, you need to
declare a message-record type for that message. The message-record is the
type of the parameter passed to the message-handling method. If you do not use
the message's parameters, or if you want to use the old-style parameter notation
(wParam, lParam, and so on), you can use the default message-record,
TMessage.
Declaring a New Message-handling Method ( see page 1305) There are two sets of circumstances that require you to declare new
message-handling methods:
1300
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
The WndProc Method ( see page 1308) Note: This information is applicable when writing VCL components only.
Here is part of the WndProc method for TControl, for example:
Understanding the message-handling system ( see page 1309) All VCL classes have a built-in mechanism for handling messages, called
message-handling methods or message handlers. The basic idea of message
handlers is that the class receives messages of some sort and dispatches them,
calling one of a set of specified methods depending on the message received. If
no specific method exists for a particular message, there is a default handler.
The following diagram shows the message-dispatch system:
To broadcast a message to all the controls in another control, use the Broadcast method. Before you broadcast a message, you
fill out a message record ( see page 1305) with the information you want to convey.
var
Msg: TMessage;
begin
Msg.Msg := MY_MYCUSTOMMESSAGE;
Msg.WParam := 0;
Msg.LParam := Longint(Self);
Msg.Result := 0;
TMessage Msg;
Msg.Msg = MY_MYCUSTOMMESSAGE;
Msg.WParam = 0;
Msg.LParam = (int)(this);
Msg.Result = 0;
3
Then, pass this message record to the parent of all the controls you want to notify. This can be any control in the application. For
example, it can be the parent of the control you are writing:
Parent.Broadcast(Msg);
Parent->Broadcast(Msg);
It can be the form that contains your control:
GetParentForm(self).Broadcast(Msg);
GetParentForm(this)->Broadcast(Msg);
1301
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Sending a Message Using the Windows Message Queue ( see page 1303)
There are two main reasons why you call a control's Perform method:
• You want to trigger the same response that the control makes to a standard Windows (or other) message. For example, when
a grid control receives a keystroke message, it creates an inline edit control and then sends the keystroke message on to the
edit control.
• You may know what control you want to notify, but not know what type of control it is. Because you don't know the type of the
target control, you cannot use any of its specialized methods, but all controls have message-handling capabilities so you can
always send a message. If the control has a message handler for the message you send, it will respond appropriately.
Otherwise, it will ignore the message you send and return 0.
To call the Perform method, you do not need to create a message record. You need only pass the message identifier, WParam,
and LParam as parameters. Perform returns the message result.
See Also
Sending a Message That Does Not Execute Immediately ( see page 1303)
Sending a Message Using the Windows Message Queue ( see page 1303)
The widget layer notifies your CLX component of system events using a special signal of type event. It passes the QEvent object
to the signal handler for the event. The processing of the event signal is a bit more complicated than processing other signals
3 because it goes first to the application object. This means an application has two opportunities to respond to a system event:
once at the application level (TApplication) and once at the level of the individual component (your TWidgetControl or
THandleComponent descendant.) All of these classes (TApplication, TWidgetControl, and THandleComponent) already assign a
signal handler for the event signal from the widget layer. That is, all system events are automatically directed to the EventFilter
method, which plays a role similar to the WndProc method on VCL controls.
EventFilter handles most of the commonly used system notifications, translating them into the events that are introduced by your
component's base classes. Thus, for example, the EventFilter method of TWidgetControl responds to mouse events
(QMouseEvent) by generating the OnMouseDown, OnMouseMove, and OnMouseUp events, to keyboard events (QKeyEvent)
1302
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
by generating the OnKeyDown, OnKeyPress, OnKeyString, and OnKeyUp events, and so on.
The following topics describe how to customize the way your control works with system events:
Use the Windows API call, PostMessage, to send a message to a control but allow the control to wait until it has finished any
other messages before it handles yours. PostMessage takes exactly the same parameters as SendMessage.
For more information on the PostMessage function, see the Microsoft MSDN documentation.
See Also
Broadcasting a Message to All Controls in a Form ( see page 1301)
Sending a Message Using the Windows Message Queue ( see page 1303)
Use the Windows API call, SendMessage, to send a message to a control using the Windows message queue. SendMessage
takes the same parameters as the Perform method, except that you must identify the target control by passing its Window
handle. Thus, instead of writing
MsgResult := TargetControl.Perform(MY_MYMESSAGE, 0, 0);
MsgResult = TargetControl->Perform(MY_MYMESSAGE, 0, 0);
you would write
MsgResult := SendMessage(TargetControl.Handle, MYMESSAGE, 0, 0);
MsgResult = SendMessage(TargetControl->Handle, MYMESSAGE, 0, 0);
For more information on the SendMessage function, see the Microsoft MSDN documentation. For more information on writing
multiple threads that may be executing simultaneously, see Coordinating threads ( see page 2227).
See Also 3
Sending a Message That Does Not Execute Immediately ( see page 1303)
1303
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
broadcast messages to all the controls in a form, send messages to a particular control (or to the application itself), or even send
messages to itself.
There are several different ways to send a Windows message. Which method you use depends on why you are sending the
message. The following topics describe the different ways to send Windows messages:
To change message handling in VCL components, you override the message-handling method. You can also prevent a
component from handling a message under certain circumstances by trapping the message.
The constant WM_APP represents the starting number for user-defined messages. When defining message identifiers, you
should base them on WM_APP.
Be aware that some standard Windows controls use messages in the user-defined range. These include list boxes, combo
boxes, edit boxes, and command buttons. If you derive a component from one of these and want to define a new message for it,
be sure to check the Messages unit to see which messages Windows already defines for that control.
1304
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
• Your component needs to handle a Windows message that is not already handled by the standard components.
• You have defined your own message for use by your components.
3
To declare a message-handling method, do the following:
1. Declare the method in a protected part of the component's class declaration.
2. Make the method a procedure.
3. Name the method after the message it handles, but without any underline characters.
4. Pass a single var parameter called Message, of the type of the message record.
5. Within the message method implementation, write code for any handling specific to the component.
1305
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1306
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
• You can modify small parts of the message handling and rely on inherited methods for most processing.
The greatest benefit of this message dispatch system is that you can safely send any message to any component at any time. If
the component does not have a handler defined for the message, the default handling takes care of it, usually by ignoring the
message.
Tracing the flow of messages
The VCL registers a method called MainWndProc as the window procedure for each type of component in an application.
MainWndProc contains an exception-handling block, passing the message structure from Windows to a virtual method called
WndProc and handling any exceptions by calling the application class's HandleException method.
MainWndProc is a nonvirtual method that contains no special handling for any particular messages. Customizations take place in
WndProc, since each component type can override the method to suit its particular needs.
WndProc methods check for any special conditions that affect their processing so they can "trap" unwanted messages. For
example, while being dragged, components ignore keyboard events, so the WndProc method of TWinControl passes along
keyboard events only if the component is not being dragged. Ultimately, WndProc calls Dispatch, a nonvirtual method inherited
from TObject, which determines which method to call to handle the message.
Dispatch uses the Msg field of the message structure to determine how to dispatch a particular message. If the component
defines a handler for that particular message, Dispatch calls the method. If the component does not define a handler for that
message, Dispatch calls DefaultHandler.
To override a message-handling method, you declare a new method in your component with the same message index as the
method it overrides. Do not use the override directive; you must use the message directive and a matching message index.
3
Note that the name of the method and the type of the single var parameter do not have to match the overridden method. Only
the message index is significant. For clarity, however, it is best to follow the convention of naming message-handling methods
after the messages they handle.
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(parameter1, parameter2, parameter3)
END_MESSAGE_MAP
1307
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
For VCL applications, notifications arrive in the form of messages. These messages can come from any source, including
Windows, VCL components, and components you have defined. There are three aspects to working with messages:
For VCL components, the WndProc method screens messages before passing them to the Dispatch method, which in turn
determines which method gets to handle the message. By overriding WndProc, your component gets a chance to filter out
messages before dispatching them. An override of WndProc for a control derived from TWinControl looks like this:
procedure TMyControl.WndProc(var Message: TMessage);
begin
{ tests to determine whether to continue processing }
inherited WndProc(Message);
end;
void __fastcall TMyControl::WndProc(TMessage& Message)
{
// tests to determine whether to continue processing
if(Message.Msg != WM_LBUTTONDOWN)
}
The TControl component defines entire ranges of mouse messages that it filters when a user is dragging and dropping controls.
Overriding WndProc helps this in two ways:
• It can filter ranges of messages instead of having to specify handlers for each one.
• It can preclude dispatching the message at all, so the handlers are never called.
1308
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
.
end;
. { otherwise process normally }
.
.
end;
The Visual Component Library defines a message-dispatching system that translates all Windows messages (including
user-defined messages) directed to a particular class into method calls. You should never need to alter this message-dispatch
mechanism. All you will need to do is create message-handling methods. See the section Declaring a new message-handling
method ( see page 1305) for more on this subject.
Because the type of the Message parameter in the message-handling method varies with the message being handled, you
should refer to the documentation on Windows messages for the names and meanings of individual parameters. If for some
reason you need to refer to the message parameters by their old-style names (WParam, LParam, and so on), you can typecast
Message to the generic type TMessage, which uses those parameter names.
One parameter contains 16 bits, the other 32 bits. You often see Windows code that refers to those values as wParam and
lParam, for word parameter and long parameter. Often, each parameter will contain more than one piece of information, and you
see references to names such as lParamHi, which refers to the high-order word in the long parameter.
Originally, Windows programmers had to remember or look up in the Windows APIs what each parameter contained. Now
Microsoft has named the parameters. This so-called message cracking makes it much simpler to understand what information
3
accompanies each message. For example, the parameters to the WM_KEYDOWN message are now called nVirtKey and
lKeyData, which gives much more specific information than wParam and lParam.
For each type of message, Delphi defines a record type that gives a mnemonic name to each parameter. For example, mouse
messages pass the x- and y-coordinates of the mouse event in the long parameter, one in the high-order word, and the other in
the low-order word. Using the mouse-message structure, you do not have to worry about which word is which, because you refer
to the parameters by the names XPos and YPos instead of lParamLo and lParamHi.
void MyKeyDownHandler( HWND hwnd, UINT nVirtKey, BOOL fDown, int CRepeat, UINT flags )
1309
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
{
.
.
.
}
LRESULT MyWndProc( HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam )
{
switch( Message )
{
HANDLE_MSG( hwnd, WM_KEYDOWN, MyKeyDownHandler );
.
.
.
}
When you create a component, you add to the component library by deriving a...
more ( see page 1314)
1310
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Components and Classes ( see page 1315) Because components are classes, component writers work with objects at a
different level from application developers. Creating new components requires
that you derive new classes.
Briefly, there are two main differences between creating components and using
them in applications. When creating components,
1311
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Deriving the Component ( see page 1318) Every component is a class derived from TComponent, from one of its more
specialized descendants (such as TControl or TGraphicControl), or from an
existing component class. The section Creating components ( see page 1315)
describes which class to derive different kinds of components from.
Deriving classes is explained in more detail in The section Defining new classes.
( see page 1370)
To derive a component, add an object type declaration to the interface part of
the unit that will contain the component.
A simple component class is a nonvisual component descended directly from
TComponent.
Creating Nonvisual Components ( see page 1318) Nonvisual components are used as interfaces for elements like databases
(TDataSet or TSQLConnection) and system clocks (TTimer), and as
placeholders for dialog boxes (TCommonDialog and its descendants). Most of
the components you write are likely to be visual controls. Nonvisual components
can be derived directly from TComponent, the abstract base class for all
components.
Creating Graphic Controls ( see page 1318) If your control does not need to receive input focus, you can make it a graphic
control. Graphic controls are similar to windowed controls, but have no window
handles, and therefore consume fewer system resources. Components like
TLabel, which never receive input focus, are graphic controls. Although these
controls cannot receive focus, you can design them to react to mouse messages.
You can create custom controls through the TGraphicControl component.
TGraphicControl is an abstract class derived from TControl. Although you can
derive controls directly from TControl, it is better to start from TGraphicControl,
which provides a... more ( see page 1318)
Encapsulating Graphics ( see page 1319) Delphi simplifies Windows graphics by encapsulating various graphics tools into
a canvas. The canvas represents the drawing surface of a window or control and
contains other classes, such as a pen, a brush, and a font. A canvas is like a
Windows device context, but it takes care of all the bookkeeping for you.
If you have written a graphical Windows application, you are familiar with the
requirements imposed by Windows' graphics device interface (GDI). For
example, GDI limits the number of device contexts available and requires that
you restore graphic objects to their initial state before destroying them.
With... more ( see page 1319)
Setting Properties, Methods, and Events ( see page 1319) Aside from the visible image manipulated in the Form designer, the most obvious
attributes of a component are its properties, events, and methods. Each of these
has a section devoted to it in this file, but the discussion that follows explains
some of the motivation for their use.
Registering the Component ( see page 1320) Registration is a simple process that tells the IDE which components to add to its
component library, and on which pages of the Tool palette they should appear.
For a more detailed discussion of the registration process, see Making
components available at design time ( see page 1352)
Removing Dependencies ( see page 1321) One quality that makes components usable is the absence of restrictions on what
they can do at any point in their code. By their nature, components are
incorporated into applications in varying combinations, orders, and contexts. You
should design components that function in any situation, without preconditions.
An example of removing dependencies is the Handle property of TWinControl. If
you have written Windows applications before, you know that one of the most
difficult and error-prone aspects of getting a program running is making sure that
you do not try to access a windowed control until you have created it... more (
see page 1321)
Registering Components (Introduction) ( see page 1321) Before you can install your components in the IDE, you have to register them.
Registration tells Delphi where to place the component on the Tool palette. You
can also customize the way Delphi stores your components in the form file. For
information on registering a component, see Registering components. ( see
page 1352)
Subclassing Windows Controls ( see page 1321) In traditional Windows programming, you create custom controls by defining a
new window class and registering it with Windows. The window class (which is
similar to the objects or classes in object-oriented programming) contains
information shared among instances of the same sort of control; you can base a
3 new window class on an existing class, which is called subclassing. You then put
your control in a dynamic-link library (DLL), much like the standard Windows
controls, and provide an interface to it.
You can create a component "wrapper" around any existing window class. So if
you already have a library... more ( see page 1321)
1312
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Creating a Component with the Component Wizard ( see page 1321) The Component wizard simplifies the initial stages of creating a component.
When you use the Component wizard, you need to specify:
1313
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
The TComponent class is the shared ancestor of every component in the component library. TComponent provides the minimal
properties and events necessary for a component to work in the IDE. The various branches of the library provide other, more
specialized capabilities.
When you create a component, you add to the component library by deriving a new class from one of the existing class types in
the hierarchy.
See Also
Components and Objects ( see page 1315)
1314
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Briefly, there are two main differences between creating components and using them in applications. When creating components,
• You access parts of the class that are inaccessible to application programmers.
• You add new parts (such as properties) to your components.
Because of these differences, you need to be aware of more conventions and think about how application developers will use
the components you write.
See Also
Components and Classes
You can also derive classes that are not components and cannot be manipulated on a form, such as TRegIniFile and TFont.
1315
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
See Also
The Visual Component Library ( see page 1314)
Some controls, such as list boxes and grids, come in several variations on a basic theme. In these cases, the component library
includes an abstract class (with the word "custom" in its name, such as TCustomGrid) from which to derive customized versions.
For example, you might want to create a special list box that does not have some of the properties of the standard TListBox
class. You cannot remove (hide) a property inherited from an ancestor class, so you need to derive your component from
something above TListBox in the hierarchy. Rather than force you to start from the abstract TWinControlclass and reinvent all
the list box functions, the component library provides TCustomListBox, which implements the properties of a list box but does not
publish all of them. When you derive a component from an abstract class like TCustomListBox, you publish only the properties
you want to make available in your component and leave the rest protected.
The section Creating properties ( see page 1249) explains publishing inherited properties. The section Modifying an existing
component ( see page 1365) and the section Customizing a grid ( see page 1264) show examples of modifying existing
controls.
See Also
Generic Components ( see page 1318)
The section Customizing a grid ( see page 1264) presents an example of creating a windowed control.
1316
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
There are several basic steps that you perform whenever you create a new component. These steps are described below;
other examples in this document assume that you know how to perform them.
1. Create a unit for the new component.
2. Derive your component from an existing component type.
3. Add properties, methods, and events.
4. Register your component with the IDE.
5. Create a bitmap for the component.
6. Create a package (a special dynamic-link library) so that you can install your component in the IDE.
7. Create a Help file for your component and its properties, methods, and events.
Note: Creating a Help file to instruct component users on how to use the component is optional.
When you finish, the complete component includes the following files:
• A package (.BPL) or package collection (.DPC) file
• A compiled package (.DCP) file
• A compiled unit (.DCU) file
• A palette bitmap (.DCR) file
• A Help (.HLP) file
You can also create a bitmap to represent your new component. .
When you create a component, you either create a new unit for the component or add the new component to an existing unit.
1317
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Within the class declaration, declare a virtual constructor in the public section of the class.
For example,
class PACKAGE TNewComponent : public TComponent
{
public:
virtual __fastcall TNewComponent(TComponent* AOwner);
};
In the .CPP file, implement the constructor:
__fastcall TNewComponent::TNewComponent(TComponent* AOwner): TComponent(AOwner)
{
}
Within the constructor, you add the code you want to execute when the component is created.
Deriving classes is explained in more detail in The section Defining new classes. ( see page 1370)
To derive a component, add an object type declaration to the interface part of the unit that will contain the component.
1318
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
messages.
You can create custom controls through the TGraphicControl component. TGraphicControl is an abstract class derived from
TControl. Although you can derive controls directly from TControl, it is better to start from TGraphicControl, which provides a
canvas to paint on and on Windows, handles WM_PAINT messages; all you need to do is override the Paint method.
The section Creating a graphic control ( see page 1220) presents an example of creating a graphic control.
If you have written a graphical Windows application, you are familiar with the requirements imposed by Windows' graphics
device interface (GDI). For example, GDI limits the number of device contexts available and requires that you restore graphic
objects to their initial state before destroying them.
With Delphi, you do not have to worry about these things. To draw on a form or other component, you access the component's
Canvas property. If you want to customize a pen or brush, you set its color or style. When you finish, Delphi disposes of the
resources. Delphi caches resources to avoid recreating them if your application frequently uses the same kinds of resource.
You still have full access to the Windows GDI, but you will often find that your code is simpler and runs faster if you use the
canvas built into Delphi components.
How graphics images work in the component depends on the canvas of the object from which your component descends.
Graphics features are detailed in the section Using graphics in components. ( see page 1380)
Properties
Properties give the application developer the illusion of setting or reading the value of a variable, while allowing the component
writer to hide the underlying data structure or to implement special processing when the value is accessed.
• Properties are available at design time. The application developer can set or change initial values of properties without having
to write code.
• Properties can check values or formats as the application developer assigns them. Validating input at design time prevents
errors.
• The component can construct appropriate values on demand. Perhaps the most common type of error programmers make is
to reference a variable that has not been initialized. By representing data with a property, you can ensure that a value is
always available on demand. 3
• Properties allow you to hide data under a simple, consistent interface. You can alter the way information is structured in a
property without making the change visible to application developers.
The section Overview of component creation ( see page 1249) explains how to add properties to your components.
Methods
Class methods are procedures and functions that operate on a class rather than on specific instances of the class. For example,
every component's constructor method (Create) is a class method. Component methods are procedures and functions that
1319
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
operate on the component instances themselves. Application developers use methods to direct a component to perform a
specific action or return a value not contained by any property.
Because they require execution of code, methods can be called only at runtime. Methods are useful for several reasons:
• Methods encapsulate the functionality of a component in the same object where the data resides.
• Methods can hide complicated procedures under a simple, consistent interface. An application developer can call a
component's AlignControls method without knowing how the method works or how it differs from the AlignControls method in
another component.
• Methods allow updating of several properties with a single call.
The section Creating methods ( see page 1243) explains how to add methods to your components.
Events
An event is a special property that invokes code in response to input or other activity at runtime. Events give the application
developer a way to attach specific blocks of code to specific runtime occurrences, such as mouse actions and keystrokes. The
code that executes when an event occurs is called an event handler.
Events allow application developers to specify responses to different kinds of input without defining new components.
The section Creating events ( see page 1233) explains how to implement standard events and how to define new ones.
To register a component:
1. Add a procedure named Register to the interface part of the component's unit. Register takes no parameters, so the
declaration is very simple:
procedure Register;
namespace Newcomp
{
void __fastcall PACKAGE Register()
{
}
}
TComponentClass classes[1] = {__classid(TNewComponent)};
If you are adding a component to a unit that already contains components, it should already have a Register procedure declared,
so you do not need to change the declaration.
Note: Although Delphi is a case insensitive language, the Register procedure is case sensitive and must be spelled with an
uppercase R.
2. Write the Register procedure in the implementation part of the unit, calling RegisterComponents for each component you
want to register. RegisterComponents is a procedure that takes two parameters: the name of a Tool palette category and a
set of component types. If you are adding a component to an existing registration, you can either add the new component to
3 the set in the existing statement, or add a new statement that calls RegisterComponents.
See Also
Creating a Unit File ( see page 1317)
1320
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
An example of removing dependencies is the Handle property of TWinControl. If you have written Windows applications before,
you know that one of the most difficult and error-prone aspects of getting a program running is making sure that you do not try to
access a windowed control until you have created it by calling the CreateWindow API function. Delphi windowed controls relieve
users from this concern by ensuring that a valid window handle is always available when needed. By using a property to
represent the window handle, the control can check whether the window has been created; if the handle is not valid, the control
creates a window and returns the handle. Thus, whenever an application's code accesses the Handle property, it is assured of
getting a valid handle.
By removing background tasks like creating the window, Delphi components allow developers to focus on what they really want
to do. Before passing a window handle to an API function, you do not need to verify that the handle exists or to create the
window. The application developer can assume that things will work, instead of constantly checking for things that might go
wrong.
Although it can take time to create components that are free of dependencies, it is generally time well spent. It not only spares
application developers from repetition and drudgery, but it reduces your documentation and support burdens.
You can create a component "wrapper" around any existing window class. So if you already have a library of custom controls
that you want to use in Delphi applications, you can create Delphi components that behave like your controls, and derive new
controls from them just as you would with any other component.
For examples of the techniques used in subclassing Windows controls, see the components in the StdCtls unit that represent
standard Windows controls, such as TEdit.
3
3.2.1.8.19 Creating a Component with the Component Wizard
The Component wizard simplifies the initial stages of creating a component. When you use the Component wizard, you need to
specify:
1321
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1322
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
end.
//header file
#ifndef NewComponentH
#define NewComponentH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class PACKAGE TNewComponent : public TComponent
{
private:
protected:
public:
__fastcall TNewComponent(TComponent* Owner);
__published:
};
//---------------------------------------------------------------------------
#endif
//implementation file
#include <vcl.h>
#pragma hdrstop
#include "NewComponent.h"
#pragma package(smart_init);
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TNewComponent *)
{
new TNewComponent(NULL);
}
//---------------------------------------------------------------------------
__fastcall TNewComponent::TNewComponent(TComponent* Owner)
: TComponent(Owner)
{
}
//---------------------------------------------------------------------------
namespace Newcomponent
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TNewComponent)};
RegisterComponents("Samples", classes, 0); //In CLX use a different page than Samples
}
}
1323
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
include source code files (.pas) and additional project files (.dfm/.xfm, .res, .rc, and .dcr).
The process of adding a component results in the creation of a number of files. These files are automatically put in directories
specified in the IDE environment options (use the menu command Tools Options, navigate to the Environment
Options Delphi Options Library page). The .lib files are placed in the DCP output directory. If adding the component entails
creating a new package (as opposed to installing it into an existing package), the .bpl file is put in the BPL output directory.
Testing your components after installing allows you to debug the component that only generates design-time exceptions when
dropped on a form.
You test an uninstalled component by emulating the actions performed by Delphi when the component is selected from the
palette and placed on a form.
1324
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
control.
Warning: If your component is not a control (that is, if TControl is not one of its ancestors), skip this step. If you accidentally
set the form's Parent property (instead of the component's) to Self, you can cause an operating-system problem.
1325
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Creating and registering the data-aware component ( see page 1331) You create every component the same way: create a unit, derive a component
class, register it, compile it, and install it on the Tool palette. This process is
outlined in Creating a new component ( see page 1317).
For this example, follow the general procedure for creating a component, with
these specifics:
1326
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Modifying the Change Method ( see page 1334) The Change method of the TDBCalendar is called whenever a new date value is
set. Change calls the OnChange event handler, if one exists. The component
user can write code in the OnChange event handler to respond to changes in the
date.
When the calendar date changes, the underlying dataset should be notified that a
change has occurred. You can do that by overriding the Change method and
adding one more line of code.
Responding to Data Changes ( see page 1334) Once a control has a data link and properties to specify the data source and data
field, it needs to respond to changes in the data in that field, either because of a
move to a different record or because of a change made to that field.
Data link classes all have events named OnDataChange. When the data source
indicates a change in its data, the data link object calls any event handler
attached to its OnDataChange event.
To update a control in response to data changes, attach a handler to the data
link's OnDataChange event.
In this case,... more ( see page 1334)
Responding to Key-down Messages ( see page 1335) A KeyDown method is a protected method for a control's OnKeyDown event. The
control itself calls KeyDown in response to a Windows key-down message. When
overriding the inherited KeyDown method, you can include code that provides
other responses in addition to calling the OnKeyDown event.
Responding to Mouse-down Messages ( see page 1336) A MouseDown method is a protected method for a control's OnMouseDown
event. The control itself calls MouseDown in response to a Windows
mouse-down message. When you override the inherited MouseDown method,
you can include code that provides other responses in addition to calling the
OnMouseDown event.
To override MouseDown, add the MouseDown method to the TDBCalendar
class:
Updating the Dataset ( see page 1337) So far, a change within the data-aware control has changed values in the field
data link class. The final step in creating a data editing control is to update the
dataset with the new value. This should happen after the person changing the
value in the data-aware control exits the control by clicking outside the control or
pressing the Tab key.
Note: VCL applications define message control IDs for operations on controls.
For example, the CM_EXIT message is sent to the control when the user exits
the control. You can write message handlers that respond to the message. In
this... more ( see page 1337)
Updating the Field Data Link Class ( see page 1338) There are two types of data changes:
A data-aware control owns its data link class. That is, the control has the responsibility for constructing and destroying the data
link. For details on management of owned classes, see Creating a graphic control ( see page 1220)
1327
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
If you now add the calendar to a form, you will find that the component ignores clicks and keystrokes. It also fails to update the
selection position when you change the date.
1328
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
To get around this absolute prohibition on changes, you can add an internal Boolean flag to the calendar, and permit changes
when that flag is set to True:
type
TDBCalendar = class(TSampleCalendar)
private
FUpdating: Boolean; { private flag for internal use }
protected
function SelectCell(ACol, ARow: Longint): Boolean; override;
public
procedure UpdateCalendar; override; { remember the override directive }
end;
.
.
.
function TDBCalendar.SelectCell(ACol, ARow: Longint): Boolean;
begin
if (not FUpdating) and FReadOnly then Result := False { allow select if updating }
else Result := inherited SelectCell(ACol, ARow); { otherwise, use inherited method }
end;
procedure TDBCalendar.UpdateCalendar;
begin
FUpdating := True; { set flag to allow updates }
try
inherited UpdateCalendar; { update as usual }
finally
FUpdating := False; { always clear the flag }
end;
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
private:
.
.
.
bool FUpdating; // private flag for internal use
protected:
virtual bool __fastcall SelectCell(long ACol, long ARow);
public:
.
.
.
virtual void __fastcall UpdateCalendar();
.
.
.
};
bool __fastcall TDBCalendar::SelectCell(long ACol, long ARow) 3
{
if (!FUpdating && FReadOnly) return false; // can't select if read only
return TSampleCalendar::SelectCell(ACol, ARow); // otherwise, use inherited method
}
void __fastcall TDBCalendar::UpdateCalendar()
{
FUpdating=true; // set flag to allow updates
try
{
TSampleCalendar::UpdateCalendar(); // update as usual
1329
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
}
catch(...)
{
FUpdating = false;
throw;
}
FUpdating = false; // always clear the flag
}
The calendar still disallows user changes, but now correctly reflects changes made in the date by changing the date properties.
Now that you have a true read-only calendar control, you are ready to add the data browsing ability.
The data editing control described here is the same calendar control described in Creating a data browsing control ( see page
1330). The control is modified so that it can edit as well as view the data in its linked field.
1330
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
For this example, follow the general procedure for creating a component, with these specifics:
Note: While you can install the sample calendar component you have just compiled, do not try to place it on a form yet. The
TCustomGrid component has an abstract DrawCell method that must be redeclared before instance objects can be created.
Overriding the DrawCell method is described in Filling in the cells ( see page 1265).
Unlike the access properties for the owned classes in the example in Creating a graphic control ( see page 1220) these access
3
properties do not provide access to the owned classes themselves, but rather to corresponding properties in the owned class.
That is, you will create properties that enable the control and its data link to share the same data source and field.
Declare the DataSource and DataField properties and their implementation methods, then write the methods as "pass-through"
methods to the corresponding properties of the data link class.
See Also
Initializing the Data Link ( see page 1332)
1331
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Override the Create and Destroy methods of the calendar to construct and destroy the datalink object, respectively:
type
TDBCalendar = class(TSampleCalendar)
public { constructors and destructors are always public }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
3 .
.
.
end;
.
.
.
constructor TDBCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { always call the inherited constructor first }
FDataLink := TFieldDataLink.Create; { construct the datalink object }
1332
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
See Also
Declaring the Access Properties for a Data-aware Control ( see page 1331)
There are several degrees of data awareness. The simplest is read-only data awareness, or data browsing, the ability to reflect
the current state of a database. More complicated is editable data awareness, or data editing, where the user can edit the values
in the database by manipulating the control. Note also that the degree of involvement with the database can vary, from the
simplest case, a link with a single field, to more complex cases, such as multiple-record controls.
This section first illustrates the simplest case, making a read-only control that links to a single field in a dataset. The specific
control used will be the TSampleCalendar calendar created in Customizing a grid ( see page 1264) You can also use the
standard calendar control on the Samples page of the Tool palette, TCalendar.
The section then continues with an explanation of how to make the new data browsing control a data editing control.
3
3.2.1.9.13 Making the Control Read-only
Because this data calendar will be read-only with respect to the data, it makes sense to make the control itself read-only, so
users will not make changes within the control and expect them to be reflected in the database.
1333
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
When the calendar date changes, the underlying dataset should be notified that a change has occurred. You can do that by
overriding the Change method and adding one more line of code.
To update a control in response to data changes, attach a handler to the data link's OnDataChange event.
In this case, you will add a method to the calendar, then designate it as the handler for the data link's OnDataChange.
Declare and implement the DataChange method, then assign it to the data link's OnDataChange event in the constructor. In the
destructor, detach the OnDataChange handler before destroying the object.
1334
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1335
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1336
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Note: VCL applications define message control IDs for operations on controls. For example, the CM_EXIT message is sent to
the control when the user exits the control. You can write message handlers that respond to the message. In this case, when the
user exits the control, the CMExit method, the message handler for CM_EXIT, responds by updating the record in the dataset
with the changed values in the field data link class. For more information about message handlers, see Handling messages and
system notifications. ( see page 1308)
1337
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
To update the dataset when the user exits the control, follow these steps:
1. Add an override for the DoExit method to the TDBCalendar component:
type
TDBCalendar = class(TSampleCalendar);
private
procedure DoExit; override;
.
.
.
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
private:
DYNAMIC void __fastcall DoExit(void);
.
.
.
};
2. Implement the DoExit method so it looks like this:
procedure TDBCalendar.CMExit(var Message: TWMNoParams);
begin
try
FDataLink.UpdateRecord; { tell data link to update database }
except
on Exception do SetFocus; { if it failed, don't let focus leave }
end;
inherited; { let the inherited method generate an OnExit event }
end;
void __fastcall TDBCalendar::DoExit(void)
{
try
{
FDataLink.UpdateRecord(); // tell data link to update database
}
catch(...)
{
SetFocus(); // if it failed, don't let focus leave
throw;
}
TCustomGrid::DoExit(); // let the inherited method generate an OnExit event
}
To reflect a change made to the value in the calendar in the field value:
1. Add an UpdateData method to the private section of the calendar component:
1338
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
type
TDBCalendar = class(TSampleCalendar);
private
procedure UpdateData(Sender: TObject);
.
.
.
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
private:
void __fastcall UpdateData(TObject *Sender);
};
2. Implement the UpdateData method:
procedure UpdateData(Sender: TObject);
begin
FDataLink.Field.AsDateTime := CalendarDate; { set field link to calendar date }
end;
void __fastcall TDBCalendar::UpdateData( TObject* Sender)
{
FDataLink->Field->AsDateTime = CalendarDate; // set field link to calendar date
}
3. Within the constructor for TDBCalendar, assign the UpdateData method to the OnUpdateData event:
constructor TDBCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FReadOnly := True;
FDataLink := TFieldDataLink.Create;
FDataLink.OnDataChange := DataChange;
FDataLink.OnUpdateData := UpdateData;
end;
__fastcall TDBCalendar::TDBCalendar(TComponent* Owner)
: TSampleCalendar(Owner)
{
FDataLink = new TFieldDataLink(); // this was already here
FDataLink->OnDataChange = DataChange; // this was here too
FDataLink->OnUpdateData = UpdateData; // assign UpdateData to the OnUpdateData event
}
1339
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Adding Items to the Context Menu ( see page 1345) When the user right-clicks the component, the GetVerbCount and GetVerb
methods of the component editor are called to build context menu. You can
override these methods to add commands (verbs) to the context menu.
Adding items to the context menu requires the steps:
1340
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Deriving a Property-editor Class ( see page 1348) Both the component library define several kinds of property editors, all of which
descend from TPropertyEditor. When you create a property editor, your
property-editor class can either descend directly from TPropertyEditor or
indirectly through one of the property-editor classes described in the table below.
The classes in the DesignEditors unit can be used for VCL applications.
Note: All that is absolutely necessary for a property editor is that it descend from
TBasePropertyEditor and that it support the IProperty interface. TPropertyEditor,
however, provides a default implementation of the IProperty interface.
The list in the table below is not... more ( see page 1348)
Editing the Property as a Whole ( see page 1349) You can optionally provide a dialog box in which the user can visually edit a
property. The most common use of property editors is for properties that are
themselves classes. An example is the Font property, for which the user can
open a font dialog box to choose all the attributes of the font at once.
To provide a whole-property editor dialog box, override the property-editor class's
Edit method.
Edit methods use the same Get and Set methods used in writing GetValue and
SetValue methods. In fact, an Edit method calls both a Get method and a Set
method. Because... more ( see page 1349)
Implementing Commands ( see page 1349) When the command provided by GetVerb is selected in the designer, the
ExecuteVerb method is called. For every command you provide in the GetVerb
method, implement an action in the ExecuteVerb method. You can access the
component that is being edited using the Component property of the editor.
For example, the following ExecuteVerb method implements the commands for
the GetVerb method in the previous ( see page 1355) example.
Making Component Help Context-sensitive ( see page 1350) Each component, property, method, and event topic must have an A footnote.
The A footnote is used to display the topic when the user selects a component
and presses F1, or when a property or event is selected in the Object Inspector
and the user presses F1. The A footnotes must follow certain naming
conventions:
If the Help topic is for a component, the A footnote consists of two entries
separated by a semicolon using this syntax:
Making Components Available at Design Time: Overview ( see page 1350) Making your components available at design time requires several steps:
1341
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Providing Help for Your Component ( see page 1351) When you select a standard component on a form, or a property or event in the
Object Inspector, you can press F1 to get Help on that item. You can provide
developers with the same kind of documentation for your components if you
create the appropriate Help files.
You can provide a small Help file to describe your components, and your Help file
becomes part of the user's overall Delphi Help system.
See the section Creating the Help file ( see page 1347) for information on how
to compose the Help file for use with a component.
Registering Components ( see page 1352) Registration works on a compilation unit basis, so if you create several
components in a single compilation unit, you can register them all at once.
To register a component, add a Register procedure to the unit. Within the
Register procedure, you register the components and determine where to install
them on the Tool palette.
Note: If you create your component by choosing Component->New Component
in the IDE, the code required to register your component is added automatically.
The steps for manually registering a component are:
1342
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Specifying Editor Attributes ( see page 1354) The property editor must provide information that the Object Inspector can use to
determine what tools to display. For example, the Object Inspector needs to
know whether the property has subproperties or can display a list of possible
values.
To specify editor attributes, override the property editor's GetAttributes method.
GetAttributes is a method that returns a set of values of type TPropertyAttributes
that can include any or all of the following values:
Property-editor attribute flags
Specifying Menu Items ( see page 1355) Override the GetVerbCount method to return the number of commands you are
adding to the context menu. Override the GetVerb method to return the strings
that should be added for each of these commands. When overriding GetVerb,
add an ampersand (&) to a string to cause the following character to appear
underlined in the context menu and act as a shortcut key for selecting the menu
item. Be sure to add an ellipsis (...) to the end of a command if it brings up a
dialog. GetVerb has a single parameter that indicates the index of the command.
The... more ( see page 1355)
Specifying the Components ( see page 1355) Within the Register procedure, pass the component names in an open array,
which you can construct inside the call to RegisterComponents.
Specifying the Palette Page ( see page 1356) The palette category name is a string. If the name you give for the palette
category does not already exist, Delphi creates a new category with that name.
Delphi stores the names of the standard categories in string-list resources so that
international versions of the product can name the categories in their native
languages. If you want to install a component on one of the standard categories,
you should obtain the string for the category name by calling the LoadStr
function, passing the constant representing the string resource for that category,
such as srSystem for the System category.
Troubleshooting Custom Components (C++) ( see page 1356) A common problem when registering and installing custom components is that
the component does not appear in the list of components after the package is
successfully installed.
The most common causes for components not appearing in the list or on the
palette:
1343
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Writing the Register Procedure ( see page 1357) Inside the Register procedure of a unit containing components, you must register
each component you want to add to the Tool palette. If the unit contains several
components, you can register them at the same time.
To register a component, call the RegisterComponents procedure once for each
category of the Tool palette to which you want to add components.
RegisterComponents involves three important things:
For example, the following Copy method allows a TImage component to copy its picture to the Clipboard. This picture is ignored
by the Delphi IDE, but can be pasted into other applications.
procedure TMyComponent.Copy;
var
MyFormat : Word;
AData,APalette : THandle;
begin
TImage(Component).Picture.Bitmap.SaveToClipBoardFormat(MyFormat, AData, APalette);
ClipBoard.SetAsHandle(MyFormat, AData);
end;
void __fastcall TMyComponentEditor::Copy(void)
{
WORD AFormat;
int AData;
HPALETTE APalette;
((TImage *)Component)->Picture->SaveToClipboardFormat(AFormat, AData, APalette);
TClipboard *pClip = Clipboard(); // don't clear the clipboard!
pClip->SetAsHandle(AFormat, AData);
}
If you do not give your components a component editor, Delphi uses the default component editor. The default component editor
is implemented by the class TDefaultEditor. TDefaultEditor does not add any new items to a component's context menu. When
the component is double-clicked, TDefaultEditor searches the properties of the component and generates (or navigates to) the
first event handler it finds.
3 To add items to the context menu, change the behavior when the component is double-clicked, or add new clipboard formats,
derive a new class from TComponentEditor and register its use with your component. In your overridden methods, you can use
the Component property of TComponentEditor to access the component that is being edited.
1344
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
At the simplest level, a property editor can operate in either or both of two ways: displaying and allowing the user to edit the
current value as a text string, and displaying a dialog box that permits some other kind of editing. Depending on the property
being edited, you might find it useful to provide either or both kinds.
While executing the first command is usually a good idea, you may want to change this default behavior. For example, you can
provide an alternate behavior if
1345
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
end;
void __fastcall TMyEditor::Edit(void)
{
TFontDialog *pFontDlg = new TFontDialog(NULL);
pFontDlg->Execute();
((TMyComponent *)Component)->Font = pFontDlg->Font;
delete pFontDlg;
}
Note: If you want a double-click on the component to display the Code editor for an event handler, use TDefaultEditor as a base
class for your component editor instead of TComponentEditor. Then, instead of overriding the Edit method, override the
protected TDefaultEditor.EditProperty method instead. EditProperty scans through the event handlers of the component, and
brings up the first one it finds. You can change this to look a particular event instead. For example:
To create and compile a package, see Creating and editing packages ( see page 2213) . Put the source-code units for your
custom components in the package's Contains list. If your components depend on other packages, include those packages in
the Requires list.
To install your components in the IDE, see Installing component packages ( see page 2217).
The component topic must have a # footnote with a value unique to the topic. The # footnote uniquely identifies each topic by the
Help system.
The component topic should have a K footnote for keyword searching in the Help system Index that includes the name of the
1346
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
component class. For example, the keyword footnote for the TMemo component is "TMemo."
The component topic should also have a $ footnote that provides the title of the topic. The title appears in the Topics Found
dialog box, the Bookmark dialog box, and the History window.
• A hierarchy topic with links to every ancestor of the component in the component hierarchy.
• A list of all properties available in the component, with links to entries describing those properties.
• A list of all events available in the component, with links to entries describing those events.
• A list of methods available in the component, with links to entries describing those methods.
Links to object classes, properties, methods, or events in the Delphi Help system can be made using Alinks. When linking to an
object class, the Alink uses the class name of the object, followed by an underscore and the string "object". For example, to
link to the TCustomPanel object, use the following:
!AL(TCustomPanel_object,1)
When linking to a property, method, or event, precede the name of the property, method, or event by the name of the object that
implements it and an underscore. For example, to link to the Text property which is implemented by TControl, use the following:
!AL(TControl_Text,1)
To see an example of the secondary navigation topics, display the Help for any component and click on the links labeled
hierarchy, properties, methods, or events.
Each property, method, and event that is declared within the component should have a topic:
A property, event, or method topic should show the declaration of the item and describe its use. Application developers see
these topics either by highlighting the item in the Object Inspector and pressing F1 or by placing the cursor in the Code editor on
the name of the item and pressing F1. To see an example of a property topic, select any item in the Object Inspector and press
F1.
The property, event, and method topics should include a K footnote that lists the name of the property, method, or event, and its
name in combination with the name of the component. Thus, the Text property of TControl has the following K footnote:
Text,TControl;TControl,Text;Text,
The property, method, and event topics should also include a $ footnote that indicates the title of the topic, such as TControl.Text.
All of these topics should have a topic ID that is unique to the topic, entered as a # footnote.
Note: Although Delphi is a case insensitive language, the Register procedure is case sensitive and must be spelled with an
1347
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
uppercase R.
The following code shows the outline of a simple unit that creates and registers new components:
unit MyBtns;
interface
type
... { declare your component types here }
procedure Register; { this must appear in the interface section }
implementation
... { component implementation goes here }
procedure Register;
begin
... { register the components }
end;
end.
namespace Newcomp
{
void __fastcall PACKAGE Register()
{
}
}
Within the Register procedure, call RegisterComponents for each component you want to add to the Tool palette. If the unit
contains several components, you can register them all in one step.
Note: All that is absolutely necessary for a property editor is that it descend from TBasePropertyEditor and that it support the
IProperty interface. TPropertyEditor, however, provides a default implementation of the IProperty interface.
The list in the table below is not complete. The VCLEditors unit also defines some very specialized property editors used by
unique properties such as the component name. The listed property editors are the ones that are the most useful for
user-defined properties.
1348
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
TColorProperty Component colors. Shows color constants if applicable, otherwise displays hexadecimal value. Drop
down list contains the color constants. Double-click opens the color-selection dialog box.
TFontNameProperty Font names. The drop down list displays all currently installed fonts.
TFontProperty Fonts. Allows expansion of individual font properties as well as access to the font dialog box.
To provide a whole-property editor dialog box, override the property-editor class's Edit method.
Edit methods use the same Get and Set methods used in writing GetValue and SetValue methods. In fact, an Edit method calls
both a Get method and a Set method. Because the editor is type-specific, there is usually no need to convert the property values
to strings. The editor generally deals with the value "as retrieved."
When the user clicks the '...' button next to the property or double-clicks the value column, the Object Inspector calls the property
editor's Edit method.
For example, the following ExecuteVerb method implements the commands for the GetVerb method in the previous ( see page
1355) example.
procedure TMyEditor.ExecuteVerb(Index: Integer);
var
MySpecialDialog: TMyDialog;
begin
case Index of
0: begin
MyDialog := TMySpecialDialog.Create(Application); { instantiate the editor }
if MySpecialDialog.Execute then; { if the user OKs the dialog... }
MyComponent.FThisProperty := MySpecialDialog.ReturnValue; { ...use the value }
MySpecialDialog.Free; { destroy the editor } 3
end;
1: That; { call the That method }
end;
end;
void __fastcall TMyEditor::ExecuteVerb(int Index)
{
switch (Index)
{
case 0:
TMyDialog *MySpecialDialog = new TMyDialog();
1349
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
MySpecialDialog->Execute();
((TMyComponent *)Component)->ThisProperty = MySpecialDialog->ReturnValue;
delete MySpecialDialog;
break;
case 1:
That(); // call the "That" method
break;
}
}
If the Help topic is for a component, the A footnote consists of two entries separated by a semicolon using this syntax:
ComponentClass_Object;ComponentClass
where ComponentClass is the name of the component class.
If the Help topic is for a property or event, the A footnote consists of three entries separated by semicolons using this syntax:
ComponentClass_Element;Element_Type;Element
where ComponentClass is the name of the component class, Element is the name of the property, method, or event, and Type is
the either Property, Method, or Event
For example, for a property named BackgroundColor of a component named TMyGrid, the A footnote is
TMyGrid_BackgroundColor;BackgroundColor_Property;BackgroundColor
1350
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Note that it is not mandatory that you register properties or that you register all of the properties of a custom component when
some are registered. Any property not explicitly associated with a category is included in the TMiscellaneousCategory category.
Such properties are displayed or hidden in the Object Inspector based on that default categorization.
In addition to these two functions for registering properties, there is an IsPropertyInCategory function. This function is useful for
creating localization utilities, in which you must determine whether a property is registered in a given property category.
Property categories
Category Purpose
Action Properties related to runtime actions; the Enabled and Hint properties of TEdit are in this category.
Database Properties related to database operations; the DatabaseName and SQL properties of TQuery are in this
category.
Drag, Drop, Properties related to drag-and-drop and docking operations; the DragCursor and DragKind properties of
and Docking TImage are in this category.
Help and Properties related to using online Help or hints; the HelpContext and Hint properties of TMemo are in this
Hints category.
Layout Properties related to the visual display of a control at design-time; the Top and Left properties of TDBEdit are in
this category.
Legacy Properties related to obsolete operations; the Ctl3D and ParentCtl3D properties of TComboBox are in this
category.
Linkage Properties related to associating or linking one component to another; the DataSet property of TDataSource is
in this category.
Locale Properties related to international locales; the BiDiMode and ParentBiDiMode properties of TMainMenu are in
this category.
Localizable Properties that may require modification in localized versions of an application. Many string properties (such as
Caption) are in this category, as are properties that determine the size and position of controls.
Visual Properties related to the visual display of a control at runtime; the Align and Visible properties of TScrollBox are
in this category.
Input Properties related to the input of data (need not be related to database operations); the Enabled and ReadOnly
properties of TEdit are in this category. 3
Miscellaneous Properties that do not fit a category or do not need to be categorized (and properties not explicitly registered to
a specific category); the AllowAllUp and Name properties of TSpeedButton are in this category.
1351
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
on that item. You can provide developers with the same kind of documentation for your components if you create the appropriate
Help files.
You can provide a small Help file to describe your components, and your Help file becomes part of the user's overall Delphi Help
system.
See the section Creating the Help file ( see page 1347) for information on how to compose the Help file for use with a
component.
To register a component, add a Register procedure to the unit. Within the Register procedure, you register the components and
determine where to install them on the Tool palette.
in the IDE, the code required to register your component is added automatically. The steps for manually registering a
component are:
The first variation lets you identify properties based on property name or type. The list is passed as an array of constants. In the
example below, any property that either has the name "Text" or belongs to a class of type TEdit is registered in the category
'Localizable.'
RegisterPropertiesInCategory('Localizable', ['Text', TEdit]);
RegisterPropertiesInCategory("Localizable", ARRAYOFCONST("Text", __typeinfo(TEdit)));
The second variation lets you limit the registered properties to those that belong to a specific component. The list of properties to
register include only names, not types. For example, the following code registers a number of properties into the 'Help and Hints'
category for all components:
RegisterPropertiesInCategory('Help and Hints', TComponent, ['HelpContext', 'Hint',
'ParentShowHint', 'ShowHint']);
RegisterPropertyInCategory("Help and Hints", __classid(TComponent),
ARRAYOFCONST("HelpContext", "Hint", "ParentShowHint"));
The third variation lets you limit the registered properties to those that have a specific type. As with the second variation, the list
of properties to register can include only names:
3
RegisterPropertiesInCategory('Localizable', TypeInfo(String), ['Text', 'Caption']);
RegisterPropertiesInCategory("Localizable", __typeinfo(TStrings), ARRAYOFCONST("Lines",
"Commands"));
See the section Specifying property categories ( see page 1351) for a list of the available property categories and a brief
description of their uses.
1352
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
The first variation lets you identify the property by the property's name. The line below registers a property related to visual
display of the component, identifying the property by its name, "AutoSize".
RegisterPropertyInCategory('Visual', 'AutoSize');
RegisterPropertyInCategory("Visual", "AutoSize");
The second variation is much like the first, except that it limits the category to only those properties of the given name that
appear on components of a given type. The example below registers (into the 'Help and Hints' category) a property named
"HelpContext" of a component of the custom class TMyButton.
RegisterPropertyInCategory('Help and Hints', TMyButton, 'HelpContext');
RegisterPropertyInCategory("Help and Hints", __classid(TMyButton), "HelpContext");
The third variation identifies the property using its type rather than its name. The example below registers a property based on its
type, Integer.
RegisterPropertyInCategory('Visual', TypeInfo(Integer));
RegisterPropertyInCategory("Visual", typeid(TArrangement));
The final variation uses both the property's type and its name to identify the property. The example below registers a property
based on a combination of its type, TBitmap, and its name, "Pattern."
RegisterPropertyInCategory('Visual', TypeInfo(TBitmap), 'Pattern');
RegisterPropertyInCategory("Visual", typeid(TBitmap), "Pattern");
See the section Specifying property categories ( see page 1351) for a list of the available property categories and a brief
description of their uses.
To create the association between a component editor and a component class, call RegisterComponentEditor.
RegisterComponentEditor takes the name of the component class that uses the editor, and the name of the component editor
class that you have defined. For example, the following statement registers a component editor class named TMyEditor to work
with all components of type TMyComponent:
RegisterComponentEditor(TMyComponent, TMyEditor);
RegisterComponentEditor(__classid( TMyComponent), __classid(TMyEditor));
Place the call to RegisterComponentEditor in the Register procedure where you register your component. For example, if a new
component named TMyComponent and its component editor TMyEditor are both implemented in the same unit, the following
code registers the component and its association with the component editor.
3
procedure Register;
begin
RegisterComponents('Miscellaneous', [TMyComponent);
RegisterComponentEditor(classes[0], TMyEditor);
end;
namespace Newcomp
{
void __fastcall PACKAGE Register()
{
1353
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
• A type-information pointer for the type of property to edit—this is always a call to the built-in function TypeInfo, such as
TypeInfo(TMyComponent)__typeinfo(TMyComponent).
• The type of the component to which this editor applies—if this parameter is nil, the editor applies to all properties of the given
type.
• The name of the property—this parameter only has meaning if the previous parameter specifies a particular type of
component. In that case, you can specify the name of a particular property in that component type to which this editor applies.
• The type of property editor to use for editing the specified property.
To read string values into properties, override the property editor's SetValue method.
SetValue should convert the string and validate the value before calling one of the Set methods.
GetAttributes is a method that returns a set of values of type TPropertyAttributes that can include any or all of the following
values:
1354
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
paSortList N/A The Object Inspector should sort the value list.
paReadOnly N/A Users cannot modify the property value.
paRevertable N/A Enables the Revert to Inherited menu item on the Object Inspector's context
menu. The menu item tells the property editor to discard the current property
value and return to some previously established default or standard value.
paFullWidthName N/A The value does not need to be displayed. The Object Inspector uses its full
width for the property name instead.
paVolatileSubProperties GetProperties The Object Inspector re-fetches the values of all subproperties any time the
property value changes.
paReference GetComponentValue The value is a reference to something else. When used in conjunction with
paSubProperties the referenced object should be displayed as sub properties
to this property.
The following code overrides the GetVerbCount and GetVerb methods to add two commands to the context menu.
function TMyEditor.GetVerbCount: Integer;
begin
Result := 2;
end;
function TMyEditor.GetVerb(Index: Integer): String;
begin
case Index of
0: Result := '&DoThis ...';
1: Result := 'Do&That';
end;
end;
int __fastcall TMyEditor::GetVerbCount(void)
{
return 2;
}
System::AnsiStringBase __fastcall TMyEditor::GetVerb(int Index)
{
switch (Index)
{
case 0: return "&DoThis ..."; break;
case 1: return "Do&That"; break;
}
}
Note: Be sure that your GetVerb method returns a value for every possible index indicated by GetVerbCount. 3
1355
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
You could also register several components on the same page at once, or register components on different pages, as shown in
the following code:
procedure Register;
begin
RegisterComponents('Miscellaneous', [TFirst, TSecond]); { two on this page... }
RegisterComponents('Assorted', [TThird]); { ...one on another... }
RegisterComponents(LoadStr(srStandard), [TFourth]); { ...and one on the Standard page }
end;
TMetaClass classes[2] =
{__classid(TNewComponent), __classid(TAnotherComponent)};
//Another way to add a component to the array
TMetaClass classes[2];
classes[0] = __classid(TNewComponent);
classes[1] = __classid(TAnotherComponent);
The most common causes for components not appearing in the list or on the palette:
1356
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
descendant, have the name "Text", and be in the property category 'Localizable'.
IsItThere := IsPropertyInCategory('Localizable', 'TCustomEdit', 'Text');
IsItThere = IsPropertyInCategory("Localizable", "TCustomEdit", "Text");
Set the Page parameter to the name of the category on the Tool palette where the components should appear. If the named
category already exists, the components are added to that category. If the named category does not exist, Delphi creates a new
palette category with that name.
Call RegisterComponents from the implementation of the Register procedure in one of the units that defines the custom
components. The units that define the components must then be compiled into a package and the package must be installed
before the custom components are added to the Tool palette.
procedure Register;
begin
RegisterComponents('System', [TSystem1, TSystem2]); {add to system
category}
RegisterComponents('MyCustomPage',[TCustom1, TCustom2]); { new
category}
end;
namespace Newcomp
{
void __fastcall PACKAGE Register()
{
TMetaClass* classes[1] = {__classid(TMyComponent)};
RegisterComponents("Miscellaneous", classes, 0);
}
}
namespace Mycomps
{
void __fastcall PACKAGE Register()
{
// declares an array that holds two components
TMetaClass classes1[2] = {__classid(TFirst), __classid(TSecond)};
// adds a new palette page with the two components in the classes1 array
RegisterComponents("Miscellaneous", classes1, 1);
// declares a second array
TMetaClass classes2[1];
// assigns a component to be the first element in the array
classes2[0] = __classid(TThird);
// adds the component in the classes2 array to the Samples page
RegisterComponents("Samples", classes2, 0);
}
}
To register a component, call the RegisterComponents procedure once for each category of the Tool palette to which you want
to add components. RegisterComponents involves three important things:
1357
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1358
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Making a Dialog Box a Component: Overview ( see page 1362) You will find it convenient to make a frequently used dialog box into a component
that you add to the Tool palette. Your dialog box components will work just like
the components that represent the standard common dialog boxes. The goal is to
create a simple component that a user can add to a project and set properties for
at design time.
Making a dialog box a component requires these steps:
Properties in wrapper components are somewhat simpler than the properties you would create if you were writing a regular
component. Remember that in this case, you are just creating some persistent data that the wrapper can pass back and forth to
the dialog box. By putting that data in the form of properties, you enable developers to set data at design time so that the
wrapper can pass it to the dialog box at runtime.
Declaring an interface property requires two additions to the component's class declaration:
• A private class field, which is a variable the wrapper uses to store the value of the property
• The published property declaration itself, which specifies the name of the property and tells it which field to use for storage
Interface properties of this sort do not need access methods. They use direct access to their stored data. By convention, the
class field that stores the property's value has the same name as the property, but with the letter F in front. The field and the
property must be of the same type.
The declaration for the Execute method always looks like this:
type
TMyWrapper = class(TComponent)
public 3
function Execute: Boolean;
end;
class PACKAGE TMyWrapper : public TComponent
{
.
.
.
public:
bool __fastcall Execute();
.
1359
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
.
.
};
The minimum implementation for Execute needs to construct the dialog box form, show it as a modal dialog box, and return
either True or False, depending on the return value from ShowModal.
For this example, follow the general procedure for creating a component, with these specifics:
1360
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
protected:
public:
__published:
};
//---------------------------------------------------------------------------
#endif
The new component now has only the capabilities built into TComponent. It is the simplest nonvisual component. In the next
section ( see page 1361), you will create the interface between the component and the dialog box.
For example, look at the properties for the common dialog box components. They enable the developer to set the initial state of
the dialog box, such as the caption and initial control settings, then read back any needed information after the dialog box closes.
There is no direct interaction with the individual controls in the dialog box, just with the properties in the wrapper component.
The interface must therefore contain enough information that the dialog box form can appear in the way the developer specifies
and return any information the application needs. You can think of the properties in the wrapper component as being persistent
data for a transient dialog box.
In the case of the About box, you do not need to return any information, so the wrapper's properties only have to contain the
information needed to display the About box properly. Because there are four separate fields in the About box that the
application might affect, you will provide four string-type properties to provide for them.
1361
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
So by adding About to the uses clause, you make AboutBox available to the wrapper component.
For example, if you created an About dialog box, made it a component, and added it to the Tool palette, you can test it
with the following steps:
1. Create a new project.
2. Place an About box component on the main form.
3. Place a command button on the form.
4. Double-click the command button to create an empty click-event handler.
5. In the click-event handler, type the following line of code:
AboutBoxDlg1.Execute;
AboutBoxDlg1->Execute();
6. Run the application.
When the main form appears, click the command button. The About box appears with the default project icon and the name
Project1. Choose OK to close the dialog box.
3
You can further test the component by setting the various properties of the About box component and again running the
application.
1362
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1363
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
For this example, follow the general procedure for creating a component, with these specifics:
1364
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
//---------------------------------------------------------------------------
#endif
If you compile and install the new component now, it behaves exactly like its ancestor, TMemo. In the next section, you will make
a simple change to your component.
The value of the memo component's WordWrap property is initialized to True. If you frequently use non-wrapping memos, you
can create a new memo component that does not wrap words by default.
Note: To modify published properties or save specific event handlers for an existing component, it is often easier to use a
component template rather than create a new class.
Note: When you override a constructor, the new constructor must call the inherited constructor before doing anything else. For
more information, see Overriding methods ( see page 1374).
For this example, your new component needs to override the constructor inherited from TMemo to set the WordWrap property to
False. To achieve this, add the constructor override to the forward declaration, then write the new constructor in the
implementation part of the unit:
type 3
TWrapMemo = class(TMemo)
public { constructors are always public }
constructor Create(AOwner: TComponent); override; { this syntax is always the same }
end;
.
.
.
constructor TWrapMemo.Create(AOwner: TComponent); { this goes after implementation }
begin
inherited Create(AOwner); { ALWAYS do this first! }
1365
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
If you change an initial property value, you should also designate that value as the default. If you fail to match the value set by
the constructor to the specified default value, Delphi cannot store and restore the proper value.
To change the default value of a property, redeclare the property name, followed by the directive default and the new default
value. You don't need to redeclare the entire property, just the name and the default value.
For the word-wrapping memo component, you redeclare the WordWrap property in the published part of the object declaration,
with a default value of False:
type
TWrapMemo = class(TMemo)
.
.
.
published
property WordWrap default False;
end;
//header file
class PACKAGE TYellowMemo : public TMemo
{
public:
virtual __fastcall TYellowMemo(TComponent* Owner);
__published:
__property Color = {default=clYellow};
};
//implmentation file
3 __fastcall TYellowMemo::TYellowMemo(TComponent* AOwner) : TMemo(AOwner)
{
Color = clYellow;
WordWrap = false;
}
//header file with WordWrap as default value of false:
class PACKAGE TYellowMemo : public TMemo
{
public:
virtual __fastcall TYellowMemo(TComponent* Owner);
__published:
1366
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
1367
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Changing Class Defaults to Avoid Repetition ( see page 1371) Most programmers try to avoid repetition. Thus, if you find yourself rewriting the
same lines of code over and over, you place the code in a subroutine or function,
or build a library of routines that you can use in many programs. The same
reasoning holds for components. If you find yourself changing the same
properties or making the same method calls, you can create a new component
that does these things by default.
For example, suppose that each time you create an application, you add a dialog
box to perform a particular operation. Although it is not difficult to... more ( see
page 1371)
Controlling Access ( see page 1371) There are five levels of access control - also called visibility - on properties,
methods, and fields. Visibility determines which code can access which parts of
the class. By specifying visibility, you define the interface to your components.
The table below shows the levels of visibility, from most restrictive to most
accessible:
Levels of visibility within an object
Declaring a New Component Class ( see page 1372) In addition to standard components, Delphi provides many abstract classes
designed as bases for deriving new components. The Creating components (
see page 1315) topic shows the classes you can start from when you create your
own components.
To declare a new component class, add a class declaration to the component's
unit file.
Defining the Design-time Interface ( see page 1372) Declaring part of a class as published makes that part public and also generates
runtime type information. Among other things, runtime type information allows the
Object Inspector to access properties and events.
Because they show up in the Object Inspector, the published parts of a class
define that class's design-time interface. The design-time interface should include
any aspects of the class that an application developer might want to customize at
design time, but must exclude any properties that depend on specific information
about the runtime environment.
Read-only properties cannot be part of the design-time interface because the
application developer... more ( see page 1372)
Defining the Component Writer's Interface ( see page 1373) Declaring part of a class as protected makes that part visible only to the class
itself and its descendants (and to other classes that share their unit files).
You can use protected declarations to define a component writer's interface to
the class. Application units do not have access to the protected parts, but derived
classes do. This means that component writers can change the way a class
works without making the details visible to application developers.
Note: A common mistake is trying to access protected methods from an event
handler. Event handlers are typically methods of the form, not the... more ( see
page 1373)
Defining the Runtime Interface ( see page 1373) Declaring part of a class as public makes that part visible to any code that has
access to the class as a whole.
Public parts are available at runtime to all code, so the public parts of a class
define its runtime interface. The runtime interface is useful for items that are not
meaningful or appropriate at design time, such as properties that depend on
runtime input or which are read-only. Methods that you intend for application
developers to call must also be public.
Dispatching Methods ( see page 1373) Dispatch refers to the way a program determines where a method should be
invoked when it encounters a method call. The code that calls a method looks
like any other procedure or function call. But classes have different ways of
dispatching methods.
The three types of method dispatch are
• Static
• Virtual
• Dynamic
Dynamic Methods ( see page 1373) Dynamic methods are virtual methods with a slightly different dispatch
3 mechanism. Because dynamic methods don't have entries in the object's virtual
method table, they can reduce the amount of memory that objects consume.
However, dispatching dynamic methods is somewhat slower than dispatching
regular virtual methods. If a method is called frequently, or if its execution is
time-critical, you should probably declare it as virtual rather than dynamic.
Objects must store the addresses of their dynamic methods. But instead of
receiving entries in the virtual method table, dynamic methods are listed
separately. The dynamic method list contains entries only for methods... more (
see page 1373)
Hiding Implementation Details ( see page 1374) Declaring part of a class as private makes that part invisible to code outside the
class's unit file. Within the unit that contains the declaration, code can access the
part as if it were public.
1368
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Virtual Methods ( see page 1374) Virtual methods employ a more complicated, and more flexible, dispatch
mechanism than static methods. A virtual method can be redefined in
descendant classes, but still be called in the ancestor class. The address of a
virtual method isn't determined at compile time; instead, the object where the
method is defined looks up the address at runtime.
To make a method virtual, add the directive virtual after the method declaration.
The virtual directive creates an entry in the object's virtual method table, or VMT,
which holds the addresses of all the virtual methods in an object type.
When you derive... more ( see page 1374)
Classes and Pointers ( see page 1374) Every class (and therefore every component) is really a pointer. The compiler
automatically dereferences class pointers for you, so most of the time you do not
need to think about this. The status of classes as pointers becomes important
when you pass a class as a parameter. In general, you should pass classes by
value rather than by reference. The reason is that classes are already pointers,
which are references; passing a class by reference amounts to passing a
reference to a reference.
Overriding Methods ( see page 1374) Overriding a method means extending or refining it, rather than replacing it. A
descendant class can override any of its inherited virtual methods.
To override a method in a descendant class, add the directive override to the
end of the method declaration.
Overriding a method causes a compilation error if
When you create new components, you deal with classes in ways that application developers never need to. You also try to hide
the inner workings of the component from the developers who will use it. By choosing appropriate ancestors for your
components, designing interfaces that expose only the properties and methods that developers need, and following the other
guidelines in the following topics, you can create versatile, reusable components.
3
Before you start creating components, you should be familiar with these topics, which are related to object-oriented programming
(OOP):
1369
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
A class is essentially a type. As a programmer, you are always working with types and instances, even if you do not use that
terminology. For example, you create variables of a type, such as Integer. Classes are usually more complex than simple data
types, but they work the same way: By assigning different values to instances of the same type, you can perform different tasks.
For example, it is quite common to create a form containing two buttons, one labeled OK and one labeled Cancel. Each is an
instance of the class TButton, but by assigning different values to their Caption properties and different handlers to their OnClick
events, you make the two instances behave differently.
See Also
Deriving New Types ( see page 1370)
Derive your new component from the class that contains the closest subset of the features you want. You can add capabilities to
3 a class, but you cannot take them away; so if an existing component class contains properties that you do not want to include in
yours, you should derive from that component's ancestor.
For example, if you want to add features to a list box, you could derive your component from TListBox. However, if you want to
add new features but exclude some capabilities of the standard list box, you need to derive your component from
TCustomListBox, the ancestor of TListBox. Then you can recreate (or make visible) only the list-box capabilities you want, and
add your new features.
Customizing a grid ( see page 1264) shows an example of customizing an abstract component class.
1370
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
The class from which you derive a component is called its immediate ancestor. Each component inherits from its immediate
ancestor, and from the immediate ancestor of its immediate ancestor, and so forth. All of the classes from which a component
inherits are called its ancestors; the component is a descendant of its ancestors.
Together, all the ancestor-descendant relationships in an application constitute a hierarchy of classes. Each generation in the
hierarchy contains more than its ancestors, since a class inherits everything from its ancestors, then adds new properties and
methods or redefines existing ones.
If you do not specify an immediate ancestor, Delphi derives your component from the default ancestor, TObject. TObject is the
ultimate ancestor of all classes in the object hierarchy.
The general rule for choosing which object to derive from is simple: Pick the object that contains as much as possible of what
you want to include in your new object, but which does not include anything you do not want in the new object. You can always
add things to your objects, but you cannot take things out.
For example, suppose that each time you create an application, you add a dialog box to perform a particular operation. Although
it is not difficult to recreate the dialog each time, it is also not necessary. You can design the dialog once, set its properties, and
install a wrapper component associated with it onto the Tool palette. By making the dialog into a reusable component, you not
only eliminate a repetitive task, but you encourage standardization and reduce the likelihood of errors each time the dialog is
recreated.
Modifying an existing component ( see page 1365) shows an example of changing a component's default properties.
Note: If you want to modify only the published properties of an existing component, or to save specific event handlers for a
component or group of components, you may be able to accomplish this more easily by creating a component template.
The table below shows the levels of visibility, from most restrictive to most accessible: 3
Levels of visibility within an object
1371
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
protected Accessible to code in the unit(s) where the class and Defining the component writer's interface. ( see page
its descendants are defined. 1373)
public Accessible to all code. Defining the runtime interface. ( see page 1373)
automated Accessible to all code. Automation type information is OLE automation only.
generated.
published Accessible to all code and accessible from the Object Defining the design-time interface. ( see page 1372)
Inspector. Saved in a form file.
Declare members as private if you want them to be available only within the class where they are defined; declare them as
protected if you want them to be available only within that class and its descendants. Remember, though, that if a member is
available anywhere within a unit file, it is available everywhere in that file. Thus, if you define two classes in the same unit, the
classes will be able to access each other's private methods. And if you derive a class in a different unit from its ancestor, all the
classes in the new unit will be able to access the ancestor's protected methods.
See Also
Hiding Implementation Details ( see page 1374)
To declare a new component class, add a class declaration to the component's unit file.
See Also
Deriving New Types ( see page 1370)
Because they show up in the Object Inspector, the published parts of a class define that class's design-time interface. The
design-time interface should include any aspects of the class that an application developer might want to customize at design
time, but must exclude any properties that depend on specific information about the runtime environment.
Read-only properties cannot be part of the design-time interface because the application developer cannot assign values to them
directly. Read-only properties should therefore be public, rather than published.
3 See Also
Hiding Implementation Details ( see page 1374)
1372
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
You can use protected declarations to define a component writer's interface to the class. Application units do not have access to
the protected parts, but derived classes do. This means that component writers can change the way a class works without
making the details visible to application developers.
Note: A common mistake is trying to access protected methods from an event handler. Event handlers are typically methods of
the form, not the component that receives the event. As a result, they do not have access to the component's protected methods
(unless the component is declared in the same unit as the form).
See Also
Hiding Implementation Details ( see page 1374)
Public parts are available at runtime to all code, so the public parts of a class define its runtime interface. The runtime interface is
useful for items that are not meaningful or appropriate at design time, such as properties that depend on runtime input or which
are read-only. Methods that you intend for application developers to call must also be public.
See Also
Hiding Implementation Details ( see page 1374)
• Static
• Virtual
• Dynamic
3
3.2.1.13.14 Dynamic Methods
Dynamic methods are virtual methods with a slightly different dispatch mechanism. Because dynamic methods don't have entries
in the object's virtual method table, they can reduce the amount of memory that objects consume. However, dispatching dynamic
methods is somewhat slower than dispatching regular virtual methods. If a method is called frequently, or if its execution is
time-critical, you should probably declare it as virtual rather than dynamic.
Objects must store the addresses of their dynamic methods. But instead of receiving entries in the virtual method table, dynamic
1373
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
methods are listed separately. The dynamic method list contains entries only for methods introduced or overridden by a
particular class. (The virtual method table, in contrast, includes all of the object's virtual methods, both inherited and introduced.)
Inherited dynamic methods are dispatched by searching each ancestor's dynamic method list, working backwards through the
inheritance tree.
To make a method dynamic, add the directive dynamic after the method declaration.
See Also
Defining the Component Writer's Interface ( see page 1373)
To make a method virtual, add the directive virtual after the method declaration. The virtual directive creates an entry in the
object's virtual method table, or VMT, which holds the addresses of all the virtual methods in an object type.
When you derive a new class from an existing one, the new class gets its own VMT, which includes all the entries from the
ancestor's VMT plus any additional virtual methods declared in the new class.
See Also
Regular Methods ( see page 1375)
To override a method in a descendant class, add the directive override to the end of the method declaration.
1374
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
• The declarations are not otherwise identical (number and type of arguments parameters differ).
See Also
Making Methods Virtual ( see page 1245)
A base class regular method is inherited by derived classes. In the following example, an object of type Derived can call the
method Regular() as it were its own method. Declaring a method in a derived class with the same name and parameters as a
regular method in the class's ancestor replaces the ancestor's method. In the following example, when d->AnotherRegular()
is called, it is being dispatched to the Derived class replacement for AnotherRegular().
class Base
{
public:
void Regular();
void AnotherRegular();
virtual void Virtual();
};
class Derived : public Base
{
public:
void AnotherRegular(); // replaces Base::AnotherRegular()
void Virtual(); // overrides Base::Virtual()
};
void FunctionOne()
{
Derived *d;
d = new Derived;
d->Regular(); // Calling Regular() as it were a member of Derived
// The same as calling d->Base::Regular()
d->AnotherRegular(); // Calling the redefined AnotherRegular(), ...
// ... the replacement for Base::AnotherRegular()
delete d;
}
void FunctionTwo(Base *b)
{
b->Virtual();
b->AnotherRegular();
}
The primary advantage of static methods is that dispatching them is very quick. Because the compiler can determine the exact
address of the method, it links the method directly. Virtual and dynamic methods, by contrast, use indirect means to look up the
3
address of their methods at runtime, which takes somewhat longer.
A static method does not change when inherited by a descendant class. If you declare a class that includes a static method, then
derive a new class from it, the derived class shares exactly the same method at the same address. This means that you cannot
override static methods; a static method always does exactly the same thing no matter what class it is called in. If you declare a
method in a derived class with the same name as a static method in the ancestor class, the new method simply replaces the
inherited one in the derived class.
1375
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
1376
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
Using a Picture, Graphic, or Canvas ( see page 1379) There are three kinds of classes in Delphi that deal with graphics:
1377
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
Working with Pictures ( see page 1381) Most of the graphics work you do in Delphi is limited to drawing directly on the
canvases of components and forms. Delphi also provides for handling
stand-alone graphic images, such as bitmaps, metafiles, and icons, including
automatic management of palettes.
There are three important aspects to working with pictures in Delphi:
The most common use of an off-screen bitmap is in the Paint method of a graphic control. As with any temporary object, the
bitmap should be protected with a try..finally block:
type
TFancyControl = class(TGraphicControl)
protected
procedure Paint; override; { override the Paint method }
end;
procedure TFancyControl.Paint;
var
Bitmap: TBitmap; { temporary variable for the off-screen bitmap }
begin
Bitmap := TBitmap.Create; { construct the bitmap object }
try
{ draw on the bitmap }
{ copy the result into the control's canvas }
finally
Bitmap.Free; { destroy the bitmap object }
end;
end;
To load an image into a picture from a file, call the picture's LoadFromFile method. To save an image from a picture into a file,
call the picture's SaveToFile method.
LoadFromFile and SaveToFile each take the name of a file as the only parameter. LoadFromFile uses the extension of the file
name to determine what kind of graphic object it will create and load. SaveToFile saves whatever type of file is appropriate for
the type of graphic object being saved.
1378
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide
The bitmap class in Delphi, which represents bitmapped images in resources and files, can also work as an off-screen image.
Instead of forcing you to deal with graphics at a detailed level, Delphi provides a simple yet complete interface: your component's
Canvas property. The canvas ensures that it has a valid device context, and releases the context when you are not using it.
Similarly, the canvas has its own properties representing the current pen, brush, and font.
The canvas manages all these resources for you, so you need not concern yourself with creating, selecting, and releasing things
like pen handles. You just tell the canvas what kind of pen it should use, and it takes care of the rest.
One of the benefits of letting Delphi manage graphic resources is that it can cache resources for later use, which can speed up
repetitive operations. For example, if you have a program that repeatedly creates, uses, and disposes of a particular kind of pen
tool, you need to repeat those steps each time you use it. Because Delphi caches graphic resources, chances are good that a
tool you use repeatedly is still in the cache, so instead of having to recreate a tool, Delphi uses an existing one.
An example of this is an application that has dozens of forms open, with hundreds of controls. Each of these controls might have
one or more TFont properties. Though this could result in hundreds or thousands of instances of TFont objects, most
applications wind up using only two or three font handles, thanks to a font cache.
3
3.2.1.14.6 Using a Picture, Graphic, or Canvas
There are three kinds of classes in Delphi that deal with graphics:
• A canvas represents a bitmapped drawing surface on a form, graphic control, printer, or bitmap. A canvas is always a property
of something else, never a stand-alone class.
• A graphic represents a graphic image of the sort usually found in a file or resource, such as a bitmap, icon, or metafile. Delphi
defines classes TBitmap, TIcon, and TMetafile, all descended from a generic TGraphic. You can also define your own graphic
1379
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide
classes. By defining a minimal standard interface for all graphics, TGraphic provides a simple mechanism for applications to
use different kinds of graphics easily.
• A picture is a container for a graphic, meaning it could contain any of the graphic classes. That is, an item of type TPicture can
contain a bitmap, an icon, a metafile, or a user-defined graphic type, and an application can access them all in the same way
through the picture class. For example, the image control has a property called Picture, of type TPicture, enabling the control
to display images from many kinds of graphics.
Keep in mind that a picture class always has a graphic, and a graphic might have a canvas. (The only standard graphic that has
a canvas is TBitmap.) Normally, when dealing with a picture, you work only with the parts of the graphic class exposed
through TPicture. If you need access to the specifics of the graphic class itself, you can refer to the picture's Graphic property.
Responding to changes in graphic objects is particularly important if you publish them as part of the design-time interface of your
components. The only way to ensure that the design-time appearance of the component matches the properties set in the Object
Inspector is to respond to changes in the objects.
To respond to changes in a graphic object, assign a method to the class's OnChange event.
The primary role of PaletteChanged is to determine whether to realize the control's palette in the foreground or the background.
Windows handles this realization of palettes by making the topmost window have a foreground palette, with other windows
resolved in background palettes. Delphi goes one step further, in that it also realizes palettes for controls within a window in tab
order. The only time you might need to override this default behavior is if you want a control that is not first in tab order to have
the foreground palette.
Specifying the palette for a control does these things for your application:
As with any part of the Windows API, you can call GDI functions directly from your Delphi application. But you will probably find
that using Delphi's encapsulation of the graphic functions is faster and easier.
1380
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Topics
Name Description
COM basics ( see page 1382)
Creating an Active Server Page ( see page 1400)
Using ActiveX controls ( see page 1406)
Creating COM clients ( see page 1418)
1381
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
For example, every COM object must implement the basic interface, IUnknown
( see page 1387). Through a routine called QueryInterface in IUnknown, clients
can request other interfaces implemented by the server.
Objects can have multiple interfaces, where each interface implements a feature.
An interface provides a way to convey to the client what service it provides,
without... more ( see page 1386)
The Fundamental COM Interface, IUnknown ( see page 1387) All COM objects must support the fundamental interface, called IUnknown, a
typedefto the base interface type IInterface. IUnknown contains the following
routines:
COM Interface Pointers ( see page 1387) An interface pointer is a pointer to an object instance that points, in turn, to the
implementation of each method in the interface. The implementation is accessed
through an array of pointers to these methods, which is called a vtable. Vtables
are similar to the mechanism used to support virtual functions in Delphi. Because
of this similarity, the compiler can resolve calls to methods on the interface the
same way it resolves calls to methods on Delphi classes.
The vtable is shared among all instances of an object class, so for each object
instance, the object code allocates a... more ( see page 1387)
COM Servers ( see page 1388) A COM server is an application or a library that provides services to a client
application or library. A COM server consists of one or more COM objects, where
a COM object is a set of properties and methods.
Clients do not know how a COM object performs its service; the object's
implementation remains encapsulated. An object makes its services available
through its interfaces ( see page 1386).
In addition, clients do not need to know where a COM object resides. COM
provides transparent access regardless of the object's location. ( see page
1389)
When a client requests a service from a COM object, the client passes... more
( see page 1388)
CoClasses and Class Factories ( see page 1388) A COM object is an instance of a CoClass, which is a class that implements one
3 or more COM interfaces. The COM object provides the services as defined by its
interfaces.
CoClasses are instantiated by a special type of object called a class factory.
Whenever an object's services are requested by a client, a class factory creates
an object instance for that particular client. Typically, if another client requests the
object's services, the class factory creates another object instance to service the
second client. (Clients can also bind to running COM objects that register
themselves to support it.)... more ( see page 1388)
1382
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
In-process, Out-of-process, and Remote Servers ( see page 1389) With COM, a client does not need to know where an object resides, it simply
makes a call to an object's interface. COM performs the necessary steps to make
the call. These steps differ depending on whether the object resides in the same
process as the client, in a different process on the client machine, or in a different
machine across the network. The different types of servers are known as:
The Marshaling Mechanism ( see page 1390) Marshaling is the mechanism that allows a client to make interface function calls
to remote objects in another process or on a different machine. Marshaling
1383
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
ActiveX Controls ( see page 1394) ActiveX is a technology that allows COM components, especially controls, to be
more compact and efficient. This is especially necessary for controls that are
intended for Intranet applications that need to be downloaded by a client before
they are used.
ActiveX controls are visual controls that run only as in-process servers, and can
be plugged into an ActiveX control container application. They are not complete
applications in themselves, but can be thought of as prefabricated OLE controls
that are reusable in various applications. ActiveX controls have a visible user
interface, and rely on predefined interfaces to negotiate I/O and display... more
( see page 1394)
Active Documents ( see page 1394) Active Documents (previously referred to as OLE documents) are a set of COM
services that support linking and embedding, drag-and-drop, and visual editing.
Active Documents can seamlessly incorporate data or objects of different
formats, such as sound clips, spreadsheets, text, and bitmaps.
Unlike ActiveX controls, Active Documents are not limited to in-process servers;
they can be used in cross-process applications.
Unlike Automation objects, which are almost never visual, Active Document
objects can be visually active in another application. Thus, Active Document
objects are associated with two types of data: presentation data, used for visually
displaying the object on a display... more ( see page 1394)
Type Libraries ( see page 1395) Type libraries provide a way to get more type information about an object than
can be determined from an object's interface. The type information contained in
type libraries provides needed information about objects and their interfaces,
such as what interfaces exist on what objects (given the CLSID), what member
functions exist on each interface, and what arguments those functions require.
You can obtain type information either by querying a running instance of an
object or by loading and reading type libraries. With this information, you can
implement a client which uses a desired object, knowing specifically what
member functions you... more ( see page 1395)
Implementing COM Objects with Wizards ( see page 1397) Delphi makes it easier to write COM server applications by providing wizards that
handle many of the details involved. Delphi provides separate wizards to create
the following:
1384
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Code Generated by Wizards ( see page 1398) Delphi's wizards generate classes that are derived from the Delphi ActiveX
framework (DAX). Despite its name, the Delphi ActiveX framework supports all
types of COM objects, not just ActiveX controls. The classes in this framework
provide the underlying implementation of the standard COM interfaces for the
objects you create using a wizard. The following figure illustrates the objects in
the Delphi ActiveX framework:
Each wizard generates an implementation unit that implements your COM server
object. The COM server object (the implementation object) descends from one of
the classes in DAX:
DAX Base classes for generated implementation classes... more ( see
page 1398)
COM+ Event And Event Subscriber Objects ( see page 1399) The COM+ Events system introduces a middle layer of software that decouples
applications that generate events (called publishers) from applications that
respond to events (called subscribers). Instead of being tightly bound to each
other, publishers and subscribers can be developed, deployed and activated
independently of each other.
In the COM+ Events model, an event interface is first created using the COM+
Event Object wizard. The event interface has no implementation; it simply defines
the event methods that publishers will generate, and that subscribers will respond
to. The COM+ event object is then installed into a COM+ Application, in the
COM+... more ( see page 1399)
COM is a language-independent software component model that enables interaction between software components and
applications running on a Windows platform. The key aspect of COM is that it enables communication between components,
between applications, and between clients and servers through clearly defined interfaces. Interfaces provide a way for clients to
ask a COM component which features it supports at runtime. To provide additional features for your component, you simply add
an additional interface for those features.
Applications can access the interfaces of COM components that exist on the same computer as the application or that exist on
another computer on the network using a mechanism called Distributed COM (DCOM). For more information on clients, servers,
and interfaces see Parts of a COM Application ( see page 1386).
The COM implementation is built into the Win32 subsystem, which provides a number of core services that support the written
specification. The COM library contains a set of standard interfaces that define the core functionality of a COM object, and a
small set of API functions designed for the purpose of creating and managing COM objects.
When you use Delphi wizards and VCL objects in your application, you are using Delphi’s implementation of the COM
specification. In addition, Delphi provides some wrappers for COM services for those features that it does not implement directly.
You can find these wrappers defined in the ComObj unit and the API definitions in the AxCtrls unit.
1385
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Note: Delphi’s interfaces and language follow the COM specification. Delphi implements objects conforming to the COM spec
using a set of classes called the Delphi ActiveX framework (DAX). These classes are found in the AxCtrls, OleCtrls, and
OleServer units. In addition, the Delphi interface to the COM API is in ActiveX.pas
and ComSvcs.pas.
COM extensions
As COM has evolved, it has been extended beyond the basic COM services. COM serves as the basis for other technologies
such as Automation, ActiveX controls, and Active Directories. For details on COM extensions, see COM Extensions ( see page
1392).
Delphi provides wizards to easily implement applications that incorporate the above technologies in the Delphi environment. For
details, see Implementing COM Objects with Wizards ( see page 1397).
See Also
Creating Simple COM Servers: Overview ( see page 1430)
COM The way in which an object exposes its services externally to clients. A COM object provides an interface for
interface ( each set of related methods and properties. Note that COM properties are not identical to properties on VCL
see page objects. COM properties always use read and write access methods.
1386)
COM server A module, either an EXE, DLL, or OCX, that contains the code for a COM object. Object implementations reside
( see in servers. A COM object implements one or more interfaces.
page 1388)
COM client The code that calls the interfaces to get the requested services from the server. Clients know what they want to
( see get from the server (through the interface); clients do not know the internals of how the server provides the
page 1391) services. Delphi eases the process in creating a client by letting you install COM servers (such as a Word
document or PowerPoint slide) as components on the Tool Palette. This allows you to connect to the server and
hook its events through the Object Inspector.
3 For example, every COM object must implement the basic interface, IUnknown ( see page 1387). Through a routine called
QueryInterface in IUnknown, clients can request other interfaces implemented by the server.
Objects can have multiple interfaces, where each interface implements a feature. An interface provides a way to convey to the
client what service it provides, without providing implementation details of how or where the object provides this service.
• Once published, interfaces are immutable; that is, they do not change. You can rely on an interface to provide a specific set of
functions. Additional functionality is provided by additional interfaces.
1386
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
• By convention, COM interface identifiers begin with a capital I and a symbolic name that defines the interface, such as IMalloc
or IPersist.
• Interfaces are guaranteed to have a unique identification, called a Globally Unique Identifier (GUID), which is a 128-bit
randomly generated number. Interface GUIDs are called Interface Identifiers (IIDs). This eliminates naming conflicts
between different versions of a product or different products.
• Interfaces are language independent. You can use any language to implement a COM interface as long as the language
supports a structure of pointers, and can call a function through a pointer either explicitly or implicitly.
• Interfaces are not objects themselves; they provide a way to access an object. Therefore, clients do not access data directly;
clients access data through an interface pointer ( see page 1387). Windows 2000 adds an additional layer of indirection
known as an interceptor through which it provides COM+ features such as just-in-time activation and object pooling.
• Interfaces are always inherited from the fundamental interface, IUnknown. ( see page 1387)
• Interfaces can be redirected by COM through proxies to enable interface method calls to call between threads, processes,
and networked machines, all without the client or server objects ever being aware of the redirection. For more information, see
In-process ( see page 1389).
See Also
The Fundamental COM Interface ( see page 1387)
Clients obtain pointers to other interfaces through the IUnknown method, QueryInterface. QueryInterface knows about every
interface in the server object and can give a client a pointer to the requested interface. When receiving a pointer to an interface,
the client is assured that it can call any method of the interface.
Objects track their own lifetime through the IUnknown methods, AddRef and Release, which are simple reference counting
methods. As long as an object's reference count is nonzero, the object remains in memory. Once the reference count reaches
zero, the interface implementation can safely dispose of the underlying object(s).
See Also
COM Interfaces ( see page 1386)
The vtable is shared among all instances of an object class, so for each object instance, the object code allocates a second
structure that contains its private data. The client's interface pointer, then, is a pointer to the pointer to the vtable, as shown in the
following diagram.
1387
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
In Windows 2000 and subsequent versions of Windows, when an object is running under COM+, an added level of indirection is
provided between the interface pointer and the vtable pointer. The interface pointer available to the client points at an interceptor,
which in turn points at the vtable. This allows COM+ to provide such services as just-in-time activation, whereby the server can
be deactivated and reactivated dynamically in a way that is opaque to the client. To achieve this, COM+ guarantees that the
interceptor behaves as if it were an ordinary vtable pointer.
See Also
The Fundamental COM Interface ( see page 1387)
Clients do not know how a COM object performs its service; the object's implementation remains encapsulated. An object makes
its services available through its interfaces ( see page 1386).
In addition, clients do not need to know where a COM object resides. COM provides transparent access regardless of the
object's location. ( see page 1389)
When a client requests a service from a COM object, the client passes a class identifier (CLSID) to COM. A CLSID is simply a
GUID that identifies a COM object. COM uses this CLSID, which is registered in the system registry, to locate the appropriate
server implementation. Once the server is located, COM brings the code into memory, and has the server instantiate an object
instance for the client. This process is handled indirectly, through a special object called a class factory (based on interfaces)
that creates instances of objects on demand.
• Register entries in the system registry that associate the server module with the class identifier (CLSID).
• Implement a class factory object ( see page 1388), which manufactures another object of a particular CLSID.
• Expose the class factory to COM.
• Provide an unloading mechanism through which a server that is not servicing clients can be removed from memory.
Note: Delphi wizards automate the creation of COM objects and servers ( see page 1397).
See Also
3 COM Interfaces ( see page 1386)
1388
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
CoClasses are instantiated by a special type of object called a class factory. Whenever an object's services are requested by a
client, a class factory creates an object instance for that particular client. Typically, if another client requests the object's services,
the class factory creates another object instance to service the second client. (Clients can also bind to running COM objects that
register themselves to support it.)
A CoClass must have a class factory and a class identifier (CLSID) so that it can be instantiated externally, that is, from another
module. Using these unique identifiers for CoClasses means that they can be updated whenever new interfaces are
implemented in their class. A new interface can modify or add methods without affecting older versions, which is a common
problem when using DLLs.
Delphi wizards take care of assigning class identifiers and of implementing and instantiating class factories.
See Also
COM Servers ( see page 1388)
In-process A library (DLL) running in the same process space as the client, for example, an ActiveX control embedded in
server a Web page viewed under Internet Explorer or Netscape. Here, the ActiveX control is downloaded to the client
machine and invoked within the same process as the Web browser.
The client communicates with the in-process server using direct calls to the COM interface.
Out-of-process Another application (EXE) running in a different process space but on the same machine as the client. For
server (or local example, an Excel spreadsheet embedded in a Word document are two separate applications running on the
server) same machine.
The local server uses COM to communicate with the client.
Remote server A DLL or another application running on a different machine from that of the client. For example, a Delphi
database application is connected to an application server on another machine in the network.
The remote server uses distributed COM (DCOM) to access interfaces and communicate with the application
server.
As shown in the following figure, for in-process servers, pointers to the object interfaces are in the same process space as the
client, so COM makes direct calls into the object implementation.
Note: This is not always true under COM+. When a client makes a call to an object in a different context, COM+ intercepts the
call so that it behaves like a call to an out-of-process server (see below), even if the server is in-process.
As shown in the following figure, when the process is either in a different process or in a different machine altogether, COM
uses a proxy to initiate remote procedure calls. The proxy resides in the same process as the client, so from the client's
1389
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
perspective, all interface calls look alike. The proxy intercepts the client's call and forwards it to where the real object is running.
The mechanism that enables the client to access objects in a different process space, or even different machine, as if they were
in their own process, is called marshaling ( see page 1390).
The difference between out-of-process and remote servers is the type of interprocess communication used. The proxy uses
COM to communicate with an out-of-process server, it uses distributed COM (DCOM) to communicate with a remote machine.
DCOM transparently transfers a local object request to the remote object running on a different machine.
Note: For remote procedure calls, DCOM uses the RPC protocol provided by Open Group's Distributed Computing Environment
(DCE). For distributed security, DCOM uses the NT LAN Manager (NTLM) security protocol. For directory services, DCOM uses
the Domain Name System (DNS).
See Also
CoClasses and Class Factories ( see page 1388)
• Takes an interface pointer in the server's process and makes a proxy pointer available to code in the client process.
• Transfers the arguments of an interface call as passed from the client and places the arguments into the remote object's
process space.
For any interface call, the client pushes arguments onto a stack and makes a function call through the interface pointer. If the call
to the object is not in-process, the call gets passed to the proxy. The proxy packs the arguments into a marshaling packet and
transmits the structure to the remote object. The object's stub unpacks the packet, pushes the arguments onto the stack, and
calls the object's implementation. In essence, the object recreates the client's call in its own address space.
The type of marshaling that occurs depends on what interface the COM object implements. Objects can use a standard
3 marshaling mechanism provided by the IDispatch interface. This is a generic marshaling mechanism that enables
communication through a system-standard remote procedure call (RPC). For details on the IDispatch interface, see
Automation Interfaces ( see page 1438). Even if the object does not implement IDispatch, if it limits itself to
automation-compatible types and has a registered type library, COM automatically provides marshaling support.
Applications that do not limit themselves to automation-compatible types or register a type library must provide their own
marshaling. Marshaling is provided either through an implementation of the IMarshal interface, or by using a separately
generated proxy/stub DLL. Delphi does not support the automatic generation of proxy/stub DLLs.
1390
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
See Also
In-process ( see page 1389)
To avoid this problem, some COM objects support aggregation. When the inventory management object creates an instance of
the invoice object, it passes it a copy of its own IUnknown interface. The invoice object can then use that IUnknown interface to
handle any QueryInterface calls that request an interface, such as the inventory interface, that it does not support. When this
happens, the two objects together are called an aggregate. The invoice object is called the inner, or contained object of the
aggregate, and the inventory object is called the outer object.
Note: In order to act as the outer object of an aggregate, a COM object must create the inner object using the Windows API
CoCreateInstance or CoCreateInstanceEx, passing its IUnknown pointer as a parameter that the inner object can use for
QueryInterface calls.
In order to create an object that can act as the inner object of an aggregate, it must descend from TContainedObject. When the
object is created, the IUnknown interface of the outer object is passed to the constructor so that it can be used by the
QueryInterface method on calls that the inner object can't handle.
See Also
In-process ( see page 1389)
There are two types of COM clients, controllers and containers. Controllers launch the server and interact with it through its 3
interface. They request services from the COM object or drive it as a separate process. Containers host visual controls or objects
that appear in the container's user interface. They use predefined interfaces to negotiate display issues with server objects. It is
impossible to have a container relationship over DCOM; for example, visual controls that appear in the container's user interface
must be located locally. This is because the controls are expected to paint themselves, which requires that they have access to
local GDI resources.
Delphi makes it easier for you to develop COM clients by letting you import a type library or ActiveX control into a component
wrapper so that server objects look like other VCL components. For details on this process, see Creating COM clients ( see
1391
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
page 1419)
The following lists some of the services COM extensions currently provide.
Automation servers ( Automation refers to the ability of an application to control the objects in another application
see page 1393) programmatically. Automation servers are the objects that can be controlled by other executables at
runtime.
ActiveX controls ( ActiveX controls are specialized in-process servers, typically intended for embedding in a client
see page 1394) application. The controls offer both design and runtime behaviors as well as events.
Active Server Pages Active Server Pages are scripts that generate HTML pages. The scripting language includes
( see page 1393) constructs for creating and running Automation objects. That is, the Active Server Page acts as an
Automation controller.
Active Documents ( Objects that support linking and embedding, drag-and-drop, visual editing, and in-place activation.
see page 1394) Word documents and Excel spreadsheets are examples of Active Documents.
COM+ Event and Objects that support the loosely coupled COM+ Events model. Unlike the tightly coupled model used
event subscription by ActiveX controls, the COM+ Events model allows you to develop event publishers independently of
objects event subscribers.
Type libraries ( see A collection of static data structures, often saved as a resource, that provides detailed type information
page 1395) about an object and its interfaces. Clients of Automation servers, ActiveX controls, and transactional
objects expect type information to be available.
The following diagram illustrates the relationship of the COM extensions and how they are built upon COM:
COM objects can be visual or non-visual. Some must run in the same process space as their clients; others can run in different
3 processes or remote machines, as long as the objects provide marshaling support. The following table summarizes the types of
COM objects that you can create, whether they are visual, process spaces they can run in, how they provide marshaling ( see
page 1390), and whether they require a type library.
1392
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
• The Automation object defines a set of properties and commands, and describes their capabilities through type descriptions.
In order to do this, it must have a way to provide information about its interfaces, the interface methods, and those methods'
arguments. Typically, this information is available in a type library ( see page 1395). The Automation server can also
generate type information dynamically when queried via its IDispatch interface (see following).
• Automation objects make their methods accessible so that other applications can use them. For this, they implement the
IDispatch interface. Through this interface an object can expose all of its methods and properties. Through the primary
method of this interface, the object's methods can be invoked, once having been identified through type information.
Developers often use Automation to create and use non-visual OLE objects that run in any process space because the
Automation IDispatch interface automates the marshaling process. Automation does, however, restrict the types that you can
use.
For a list of types that are valid for type libraries in general, and Automation interfaces in particular, see Valid types ( see page
1454).
See Also
Creating Simple COM Servers: Overview ( see page 1430)
1393
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Active Server Pages are written in Jscript or VB script. The script runs every time the server loads the Web page. That script can
then launch an embedded Automation server (or Enterprise Java Bean). For example, you can write an Automation server, such
as one to create a bitmap or connect to a database, and this server accesses data that gets updated every time a client loads
the Web page.
Active Server Pages rely on the Microsoft Internet Information Server (IIS) environment to serve your Web pages.
Delphi wizards let you Create Active Server Pages ( see page 1400), which is an Automation object specifically designed to
work with an Active Server Page.
See Also
Creating Active Server Pages ( see page 1400)
ActiveX controls are visual controls that run only as in-process servers, and can be plugged into an ActiveX control container
application. They are not complete applications in themselves, but can be thought of as prefabricated OLE controls that are
reusable in various applications. ActiveX controls have a visible user interface, and rely on predefined interfaces to negotiate I/O
and display issues with their host containers.
ActiveX controls make use of Automation to expose their properties, methods, and events. Features of ActiveX controls include
the ability to fire events, bind to data sources, and support licensing.
One use of ActiveX controls is on a Web site as interactive objects in a Web page. As such, ActiveX is a standard that targets
interactive content for the World Wide Web, including the use of ActiveX Documents used for viewing non-HTML documents
through a Web browser. For more information about ActiveX technology, see the Microsoft ActiveX Web site.
See Also
Using ActiveX Controls ( see page 1406)
Unlike ActiveX controls, Active Documents are not limited to in-process servers; they can be used in cross-process applications.
Unlike Automation objects, which are almost never visual, Active Document objects can be visually active in another application.
Thus, Active Document objects are associated with two types of data: presentation data, used for visually displaying the object
3 on a display or output device, and native data, used to edit an object.
Active Document objects can be document containers or document servers. While Delphi does not provide an automatic wizard
for creating Active Documents, you can use the VCL class, TOleContainer, to support linking and embedding of existing Active
Documents.
You can also use TOleContainer as a basis for an Active Document container. To create objects for Active Document servers,
use the COM object wizard and add the appropriate interfaces, depending on the services the object needs to support. For more
information about creating and using Active Document servers, see the Microsoft ActiveX Web site.
1394
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Note: While the specification for Active Documents has built-in support for marshaling in cross-process applications, Active
Documents do not run on remote servers because they use types that are specific to a system on a given machine such as
window handles, menu handles, and so on.
You can obtain type information either by querying a running instance of an object or by loading and reading type libraries. With
this information, you can implement a client which uses a desired object, knowing specifically what member functions you need,
and what to pass those member functions.
Clients of Automation servers, ActiveX controls, and transactional objects expect type information to be available. All of Delphi's
wizards generate a type library automatically, although the COM object wizard makes this optional. You can view or edit this type
information by using the Type Library Editor ( see page 1445). The Type Library Editor displays the type information by way of
an intermediate text-based format (the RIDL file ( see page 1468)) and generates the corresponding .tlb file when you build or
save your project. You can also use the GenTLB.exe ( see page 1468) utility to create a .tlb file from a RIDL file.
You can view and edit the type library using Delphi's Type Library Editor. Delphi automatically updates the corresponding .tlb
file (binary type library file) when the type library is saved. For any changes to Interfaces and CoClasses that were created using
a wizard, the Type Library editor also updates your implementation files. 3
When to use type libraries
It is important to create a type library for each set of objects that is exposed to external users, for example,
• ActiveX controls require a type library, which must be included as a resource in the DLL that contains the ActiveX controls.
• Exposed objects that support vtable binding of custom interfaces must be described in a type library because vtable
references are bound at compile time. Clients import information about the interfaces from the type library and use that
information to compile. For more information about vtable and compile time binding, see Automation interfaces ( see page
1395
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
1438).
• Applications that implement Automation servers should provide a type library so that clients can early bind to it.
• Objects instantiated from classes that support the IProvideClassInfo interface, such as all descendants of the VCL
TTypedComObject class, must have a type library.
• Type libraries are not required, but are useful for identifying the objects used with OLE drag-and-drop.
When defining interfaces for internal use only (within an application) you do not need to create a type library. .
Accessing type libraries
The binary type library is normally a part of a resource file (.res) or a stand-alone file with a .tlb file-name extension. When
included in a resource file, the type library can be bound into a server (.dll, .ocx, or .exe).
Once a type library has been created, object browsers, compilers, and similar tools can access type libraries through special
type interfaces:
Interface Description
ITypeLib Provides methods for accessing a library of type descriptions.
ITypeLib2 Augments ITypeLib to include support for documentation strings, custom data, and statistics about the type
library.
ITypeInfo Provides descriptions of individual objects contained in a type library. For example, a browser uses this
interface to extract information about objects from the type library.
ITypeInfo2 Augments ITypeInfo to access additional type library information, including methods for accessing custom
data elements.
ITypeComp Provides a fast way to access information that compilers need when binding to an interface.
Delphi can import and use type libraries from other applications by choosing Component|Import Component. Most of the VCL
classes used for COM applications support the essential interfaces that are used to store and retrieve type information from type
libraries and from running instances of an object. The VCL class TTypedComObject supports interfaces that provide type
information, and is used as a foundation for the ActiveX object framework.
• The TLIBIMP (Type Library Import) tool, which takes existing type libraries and creates Delphi Interface files (_TLB.pas files),
is incorporated into the Type Library editor. TLIBIMP provides additional configuration options not available inside the Type
Library editor.
1396
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
• TRegSvr is a tool for registering and unregistering servers and type libraries, which comes with Delphi. The source to
TRegSvr is available as an example in the Demos directory.
• The Microsoft IDL compiler (MIDL) compiles IDL scripts to create a type library.
• RegSvr32.exe is a standard Windows utility for registering and unregistering servers and type libraries.
• OLEView is a type library browser tool, found on Microsoft's Web site.
See Also
Working with Type Libraries ( see page 1445)
The COM object wizard also provides an implementation for IDispatch if you specify that you are creating an object that supports
an IDispatch descendant.
For Automation and Active Server objects, the wizard implements IUnknown and IDispatch, which provides automatic
marshaling.
For ActiveX control objects and ActiveX forms, the wizard implements all the required ActiveX control interfaces, from IUnknown,
IDispatch, IOleObject, IOleControl, and so on. For a complete list of interfaces, see the reference page for TActiveXControl
object.
The following table lists the various wizards and the interfaces they implement:
Delphi wizards for implementing COM, Automation, and ActiveX objects
1397
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
You can add additional COM objects or reimplement an existing implementation. To add a new object, it is easiest to use the
wizard a second time. This is because the wizard sets up an association between the type library and an implementation class,
so that changes you make in the type library editor are automatically applied to your implementation object.
3
Each wizard generates an implementation unit that implements your COM server object. The COM server object (the
implementation object) descends from one of the classes in DAX:
1398
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
COM server ( see page 1430) TTypedComObject Support for IUnknown and ISupportErrorInfo interfaces.
Support for aggregation, OLE exception handling, and safecall
calling convention on dual interfaces.
Support for reading type library information.
Automation server ( see page 1432) TAutoObject Everything provided by TTypedComObject, plus:
or Creating Active Server Pages ( Support for the IDispatch interface.
see page 1400)
Auto-marshaling support.
Corresponding to the classes in DAX is a hierarchy of class factory objects that handle the creation of these COM objects. The
wizard adds code to the initialization section of your implementation unit that instantiates the appropriate class factory for your
implementation class.
The wizards also generate a type library and its associated unit, which has a name of the form Project1_TLB. The
Project1_TLB unit includes the definitions your application needs to use the type definitions and interfaces defined in the type
library. For more information on the contents of this file, see Code generated when you import type library information ( see
page 1421).
You can modify the interface generated by the wizard using the type library editor. When you do this, the implementation class is
automatically updated to reflect those changes. You need only fill in the bodies of the generated methods to complete the
implementation.
In the COM+ Events model, an event interface is first created using the COM+ Event Object wizard. The event interface has no
implementation; it simply defines the event methods that publishers will generate, and that subscribers will respond to. The
COM+ event object is then installed into a COM+ Application, in the COM+ Catalog. This can be done programatically using the
TComAdminCatalog object, or by a system administrator using the Component Services tool.
Event subscribers are responsible for providing an implementation for the event interface. You can create event subscriber
components using the COM+ Event Subscription wizard. Using the wizard, you can select the event object you want to
implement, and the IDE will stub out each method of the interface. You can also select a type library if the event object has not
yet been installed in the COM+ Catalog.
Finally, once the subscriber component has been implemented, it too must be installed in the COM+ Catalog. Again, this can be
done with a TComAdminCatalog object, or by using the Component Services administrative tool.
When a publisher wishes to generate an event, it simply creates an instance of the event object (not the subscriber component), 3
and calls the appropriate methods on the event interface. COM+ then steps in and notifies all applications that have subscribed
to that event object, calling them synchronously, one at a time. This way, publishers need not know anything about those
applications that are subscribing to the event. Subscribers don't need anything more than an implementation of the event
interface, and to select those publishers they wish to subscribe to. COM+ handles the rest.
For more information regarding the COM+ Events system, see Generating events under COM+.
1399
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
On the client side, the ASP acts like a standard HTML document and can be viewed by users on any platform using any Web
Browser.
1400
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
ASP applications are analogous to applications you write using Delphi's Web broker technology. For more information about the
Web broker technology, see Creating Internet server applications ( see page 2251). ASP differs, however, in the way it
separates the UI design from the implementation of business rules or complex application logic.
• The UI design is managed by the Active Server Page. This is essentially an HTML document, but it can include embedded
script that calls on Active Server objects to supply it with content that reflects your business rules or application logic.
• The application logic is encapsulated by Active Server objects that expose simple methods to the Active Server Page,
supplying it with the content it needs.
Note: Although ASP provides the advantage of separating UI design from application logic, its performance is limited in
scale. For Web sites that respond to extremely large numbers of clients, an approach based on the Web broker technology is
recommended instead.
The script in your Active Server Pages and the Automation objects you embed in an active server page can make use of the
ASP intrinsics ( see page 1402) (built-in objects that provide information about the current application, HTTP messages from
the browser, and so on).
The following topics show how to create an Active Server Object using the Delphi Active Server Object wizard. This special
Automation control can then be called by an Active Server Page and supply it with content.
Here are the steps for creating an Active Server Object:
• Create an Active Server Object ( see page 1401) for the application.
• Define the Active Server Object's interface. ( see page 1435)
• Register ( see page 1405) the Active Server Object.
• Test and debug ( see page 1406) the application.
See Also
Overview of COM Technologies ( see page 1385)
Your Active Server Object project can be either an executable (exe) or library (dll), depending on your needs. However, you
should be aware of the drawbacks of using an out-of-process server ( see page 1405).
1401
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
• If you are working with IIS5 or later, you use the Object Context type. Under this model, your object fetches an IObjectContext
interface, which it uses to access the ASP intrinsics. Again, these interfaces are surfaced as properties in the inherited base
class (TASPMTSObject). One advantage of this latter approach is that your object has access to all of the other services
available through IObjectContext. To access the IObjectContext interface, simply call GetObjectContext (defined in the mtx
unit) as follows: ObjectContext := GetObjectContext; For more information about the services available through
IObjectContext, see Creating MTS or COM+ objects
You can tell the wizard to generate a simple ASP page to host your new Active Server Object. The generated page provides a
minimal script (written in VBScript) that creates your Active Server Object based on its ProgID, and indicates where you can
call its methods. This script calls Server.CreateObject to launch your Active Server Object.
Note: Although the generated test script uses VBScript, Active Server Pages also can be written using Jscript.
When you exit the wizard, a new unit is added to the current project that contains the definition for the Active Server Object.
In addition, the wizard adds a type library project and opens the Type Library editor. Now you can expose the properties and
methods of the interface through the type library as described in Defining a COM object's interface ( see page 1435) As you
write the implementation of your object's properties and methods, you can take advantage of the ASP intrinsics ( see page
1402) to obtain information about the ASP application and the HTTP messages it uses to communicate with browsers.
The Active Server Object, like any other Automation object, implements a dual interface ( see page 1438), which supports
both early (compile-time) binding through the VTable and late (runtime) binding through the IDispatch interface.
See Also
Implementing COM objects with Wizards ( see page 1397)
To make these objects easy to access, the base class for your Active Server Object surfaces them as properties. For a complete
understanding of these objects, see the Microsoft documentation. However, the following topics provide a brief overview.
Application
The Application object is accessed through an IApplicationObject interface. It represents the entire ASP application, which is
defined as the set of all .asp files in a virtual directory and its subdirectories. The Application object can be shared by multiple
clients, so it includes locking support that you should use to prevent thread conflicts.
1402
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Unlock method Releases the lock that was set using the Lock method.
Application_OnEnd Occurs when the application quits, after the Session_OnEnd event. The only intrinsics available are
event Application and Server. The event handler must be written in VBScript or JScript.
Application_OnStart Occurs before the new session is created (before Session_OnStart). The only intrinsics available are
event Application and Server. The event handler must be written in VBScript or JScript.
Request
The Request object is accessed through an IRequest interface. It provides information about the HTTP request message that
caused the Active Server Page to be opened.
Response
The Request object is accessed through an IResponse interface. It lets you specify information about the HTTP response
message that is returned to the client browser.
1403
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Pics property Set the value for the pics-label field of the response header.
Status property Indicates the status of the response. This is the value of an HTTP status header.
AddHeader method Adds an HTTP header with a specified name and value.
AppendToLog method Adds a string to the end of the Web server log entry for this request.
BinaryWrite method Writes raw (uninterpreted) information to the body of the response message.
Clear method Erases any buffered HTML output.
End method Stops processing the .asp file and returns the current result.
Flush method Sends any buffered output immediately.
Redirect method Sends a redirect response message, redirecting the client browser to a different URL.
Write method Writes a variable to the current HTTP output as a string.
Session
The Session object is accessed through the ISessionObject interface. It allows you to store variables that persist for the duration
of a client's interaction with the ASP application. That is, these variables are not freed when the client moves from page to page
within the ASP application, but only when the client exits the application altogether.
Property, Meaning
Method, or
Event
Contents Lists all the objects that were added to the session using the <OBJECT> tag. You can access any variable
property in the list by name, or call the Contents object's Remove or RemoveAll method to delete values.
StaticObjects Lists all the objects that were added to the session with the <OBJECT> tag.
property
CodePage Specifies the code page to use for symbol mapping. Different locales may use different code pages.
property
LCID property Specifies the locale identifier to use for interpreting string content.
SessionID Indicates the session identifier for the current client.
property
TimeOut Specifies the time, in minutes, that the session persists without a request (or refresh) from the client until the
property application terminates.
Abandon method Destroys the session and releases its resources.
Session_OnEnd Occurs when the session is abandoned or times out. The only intrinsics available are Application, Server,
event and Session. The event handler must be written in VBScript or JScript.
Session_OnStart Occurs when the server creates a new session is created (after Application_OnStart but before running the
event script on the Active Server Page). All intrinsics are available. The event handler must be written in VBScript
3 or JScript.
Server
The Server object is accessed through an IServer interface. It provides various utilities for writing your ASP application.
1404
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
See Also
Creating ASPs for In-process or Out-of-process Servers ( see page 1405)
Unlike most in-process servers, an Active Server Object in an in-process server does not run in the client's process space.
Instead, it runs in the IIS process space. This means that the client does not need to download your application (as, for example,
it does when you use ActiveX objects). In-process component DLLs are faster and more secure than out-of-process servers, so
they are better suited for server-side use.
Because out-of-process servers are less secure, it is common for IIS to be configured to not allow out-of-process executables. In
this case, creating an out-of-process server for your Active Server Object would result in an error similar to the following:
Server object error 'ASP 0196'
Cannot launch out of process component
/path/outofprocess_exe.asp, line 11
Also, out-of-process components often create individual server processes for each object instance, so they are slower than CGI
applications. They do not scale as well as component DLLs.
If performance and scalability are priorities for your site, in-process servers are highly recommended. However, Intranet sites
that receive moderate to low traffic may use an out-of-process component without adversely affecting the site's overall
performance.
See Also
Implementing COM objects with Wizards ( see page 1397) 3
Creating Simple COM Servers: Overview ( see page 1430)
1405
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Note: When you want to remove the Active Server Page object from your system, you should first unregister it, removing its
entries from the Windows registry.
To unregister an out-of-process server, run the server with the /unregserver command-line option.
1406
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Licensing ActiveX Controls ( see page 1410) Licensing an ActiveX control consists of providing a license key at design-time
and supporting the creation of licenses dynamically for controls created at
runtime.
To provide design-time licenses, a key is created for the control , which is stored
in a file with the same name as the project with the LIC extension. This .LIC file
is added to the project. The user of the control must have a copy of the .LIC file
to open the control in a development environment. Each control in the project
that has Make Control Licensed checked has a separate key entry in... more (
see page 1410)
Customizing the ActiveX Control's Interface ( see page 1411) You can add, edit, and remove the properties, methods, and events in an ActiveX
control by editing the type library. You can use the Type Library editor as
described in Using the Type Library Editor ( see page 1453). Remember that
when you add events, they should be added to the Events interface, not the
ActiveX control's default interface.
Note: You can add unpublished properties to your ActiveX control's interface.
Such properties can be set at runtime and will appear in a development
environment, but changes made to them will not persist. That is, when the user of
the control changes the value... more ( see page 1411)
Adding Additional Properties, Methods, and Events ( see page 1412) You can add additional properties, methods, and events to the control using the
type library editor. The declaration is automatically added to the control's
implementation unit, type library (TLB) file, and type library unit. The specifics of
what Delphi supplies depends on whether you have added a property or method
( see page 1412) or whether you have added an event ( see page 1413).
How Delphi Adds Properties ( see page 1412) The ActiveX wrapper class implements properties in its interface using read and
write access methods. That is, the wrapper class has COM properties, which
appear on an interface as getter and/or setter methods. Unlike VCL properties,
you do not see a "property" declaration on the interface for COM properties.
Rather, you see methods that are flagged as property access methods. When
you add a property to the ActiveX control's default interface, the wrapper class
definition (which appears in the _TLB unit that is updated by the Type Library
editor) gains one or two new methods (a getter and/or setter) that... more ( see
page 1412)
How Delphi Adds Events ( see page 1413) The ActiveX control can fire events to its container in the same way that an
automation object fires events to clients. This mechanism is described in
Managing events in your Automation object ( see page 1437).
If the VCL control you are using as the basis of your ActiveX control has any
published events, the wizards automatically add the necessary support for
managing a list of client event sinks to your ActiveX wrapper class and define the
outgoing dispinterface that clients must implement to respond to events.
You add events to this outgoing dispinterface. To add an event in the type library
editor,... more ( see page 1413)
Enabling Simple Data Binding with the Type Library ( see page 1414) With simple data binding, you can bind a property of your ActiveX control to a
field in a database. To do this, the ActiveX control must communicate with its
host application about what value represents field data and when it changes. You
enable this communication by setting the property's binding flags using the Type
Library editor.
By marking a property bindable, when a user modifies the property (such as a
field in a database), the control notifies its container (the client host application)
that the value has changed and requests that the database record be updated.
The container interacts with... more ( see page 1414)
Creating a Property Page for an ActiveX Control ( see page 1415) A property page is a dialog box similar to the Delphi Object Inspector in which
users can change the properties of an ActiveX control. A property page dialog
allows you to group many properties for a control together to be edited at once.
Or, you can provide a dialog box for more complex properties.
Typically, users access the property page by right-clicking the ActiveX control
and choosing Properties.
Creating a New Property Page ( see page 1416) You use the Property Page wizard to create a new property page.
1407
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Adding Controls to a Property Page ( see page 1416) You must add a control to the property page for each property of the ActiveX
control that you want the user to access.
For example, the following illustration shows a property page for setting the
MaskEdit property of an ActiveX control.
The list box allows the user to select from a list of sample masks. The edit
controls allow the user to test the mask before applying it to the ActiveX control.
You add controls to the property page the same as you would to a form.
Associating Property Page Controls with ActiveX Control Properties ( see page After adding the controls you need to the property page, you must associate
1416) each control with its corresponding property. You make this association by
adding code to the property page's UpdatePropertyPage ( see page 1416) and
UpdateObject ( see page 1417) methods.
Updating the Property Page ( see page 1416) Add code to the UpdatePropertyPage method to update the control on the
property page when the properties of the ActiveX control change. You must add
code to the UpdatePropertyPage method to update the property page with the
current values of the ActiveX control's properties.
You can access the ActiveX control using the property page's OleObject
property, which is an OleVariant that contains the ActiveX control's interface.
For example, the following code updates the property page's edit control
(InputMask) with the current value of the ActiveX control's EditMask property:
Updating the Object ( see page 1417) Add code to the UpdateObject method to update the property when the user
changes the controls on the property page. You must add code to the
UpdateObject method in order to set the properties of the ActiveX control to their
new values.
You use the OleObject property to access the ActiveX control.
For example, the following code sets the EditMask property of the ActiveX control
using the value in the property page's edit box control (InputMask):
Connecting a Property Page to an ActiveX Control ( see page 1417) Describes the steps in connecting an ActiveX control to a property page.
To connect a property page to an ActiveX control:
1408
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
VCL control
The underlying implementation of an ActiveX control in Delphi is a VCL control. When you create an ActiveX control, you must
first design or choose the VCL control from which you will make your ActiveX control.
The underlying VCL control must be a descendant of TWinControl, because it must have a window that can be parented by the
host application. When you create an Active form, this object is a descendant of TActiveForm.
Note: The ActiveX control wizard lists the available TWinControl descendants from which you can choose to make an ActiveX
control. This list does not include all TWinControl descendants, however. Some controls, such as THeaderControl, are registered
as incompatible with ActiveX (using the RegisterNonActiveXprocedure procedure) and do not appear in the list.
ActiveX wrapper
The actual COM object is an ActiveX wrapper object for the VCL control. For Active forms, this class is always
TActiveFormControl. For other ActiveX controls, it has a name of the form TVCLClassX, where TVCLClass is the name of the
VCL control class. Thus, for example, the ActiveX wrapper for TButton would be named TButtonX.
The wrapper class is a descendant of TActiveXControl, which provides support for the ActiveX interfaces. The ActiveX wrapper
inherits this support, which allows it to forward Windows messages to the VCL control and parent its window in the host
application.
The ActiveX wrapper exposes the VCL control's properties and methods to clients via its default interface. You must implement
the wrapper class' properties and methods, delegating method calls to the underlying VCL control. You must also provide the
wrapper class with methods that fire the VCL control's events on clients and assign these methods as event handlers on the VCL
control.
Type library
You must generate a type library for your ActiveX control that contains the type definitions for the wrapper class, its default
interface, and any type definitions that these require. This type information provides a way for your control to advertise its
services to host applications. You can view and edit this information using the Type Library editor. Although this information is
stored in a separate, binary type library file (.TLB extension), you may also compile it into the ActiveX control DLL as a resource.
Property page
You can optionally give your ActiveX control a property page. The property page allows the user of a host (client) application to
view and edit your control's properties. You can group several properties on a page, or use a page to provide a dialog-like
interface for a property. For information on how to create property pages, see Creating a property page for an ActiveX control (
see page 1415).
When designing the VCL control, keep in mind that it will be embedded in another application; this control is not an application in
itself. For this reason, you probably do not want to use elaborate dialog boxes or other major user-interface components. Your
goal is typically to make a simple control that works inside of, and follows the rules of the main application.
3
In addition, you should make sure that the types for all properties and methods you want your object to expose to clients are
Automation-compatible ( see page 1454), because the ActiveX control's interface must support IDispatch. The wizards do not
add any methods to the wrapper class's interface that have parameters that are not Automation-compatible.
The wizards implement all the necessary ActiveX interfaces required using the COM wrapper class. They also surface all
Automation-compatible properties, methods, and events through the wrapper class's default interface. Once a wizard has
generated the COM wrapper class and its interface, you can use the Type Library editor ( see page 1446) to modify the default
interface or augment the wrapper class by implementing additional interfaces.
1409
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
See Also
Overview of Component Creation ( see page 1313)
When an ActiveForm is deployed on the Web, Delphi creates an HTML page to contain the reference to the ActiveForm and
specify its location on the page. The ActiveForm can then displayed and run from a Web browser. Inside the browser, the form
behaves just like a stand-alone Delphi form. The form can contain any VCL components or ActiveX controls, including
custom-built VCL controls.
1410
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
To provide design-time licenses, a key is created for the control , which is stored in a file with the same name as the project with
the LIC extension. This .LIC file is added to the project. The user of the control must have a copy of the .LIC file to open the
control in a development environment. Each control in the project that has Make Control Licensed checked has a separate key
entry in the .LIC file.
To support runtime licenses, the wrapper class implements two methods, GetLicenseString and GetLicenseFilename. These
return the license string for the control and the name of the .LIC file, respectively. When a host application tries to create the
ActiveX control, the class factory for the control calls these methods and compares the string returned by GetLicenseString with
the string stored in the .LIC file.
Runtime licenses for the Internet Explorer require an extra level of indirection because users can view HTML source code for any
Web page, and because an ActiveX control is copied to the user's computer before it is displayed. To create runtime licenses for
controls used in Internet Explorer, you must first generate a license package file (LPK file) and embed this file in the HTML page
that contains the control. The LPK file is essentially an array of ActiveX control CLSIDs and license keys.
Note: To generate the LPK file, use the utility, LPK_TOOL.EXE, which you can download from the Microsoft Web site
(www.microsoft.com).
To embed the LPK file in a Web page, use the HTML objects, <OBJECT> and <PARAM> as follows:
<OBJECT CLASSID="clsid:6980CB99-f75D-84cf-B254-55CA55A69452">
<PARAM NAME="LPKPath" VALUE="ctrllic.lpk">
</OBJECT>
The CLSID identifies the object as a license package and PARAM specifies the relative location of the license package file with
respect to the HTML page.
When Internet Explorer tries to display the Web page containing the control, it parses the LPK file, extracts the license key, and if
the license key matches the control's license (returned by GetLicenseString), it renders the control on the page. If more than one
LPK is included in a Web page, Internet Explorer ignores all but the first.
For more information, look for Licensing ActiveX Controls on the Microsoft Web site.
Note: You can add unpublished properties to your ActiveX control's interface. Such properties can be set at runtime and will
appear in a development environment, but changes made to them will not persist. That is, when the user of the control changes
the value of a property at design time, the changes are not reflected when the control is run. If the source is a VCL object and the
property is not already published, you can make properties persistent by creating a descendant of the VCL object and publishing
the property in the descendant.
You may also choose not to expose all of the VCL control's properties, methods, and events to host applications. You can use
the Type Library editor to remove these from the interfaces that the wizard generated. When you remove properties and
methods from an interface using the Type Library editor, the Type Library editor does not remove them from the corresponding
implementation class. Edit the ActiveX wrapper class in the implementation unit to remove these after you have changed the 3
interface in the Type Library editor.
Warning: Any changes you make to the type library will be lost if you regenerate the ActiveX control from the original VCL
control or form.
Tip: It is a good idea to check the methods that the wizard adds to your ActiveX wrapper class. Not only does this give you a
chance to note where the wizard omitted any data-aware properties or methods that were not Automation-compatible, it also lets
you detect methods for which the wizard could not generate an implementation. Such methods appear with a comment in the
1411
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
See Also
Generating an ActiveX Control Based On a VCL Form ( see page 1410)
See Also
Customizing the ActiveX Control's Interface ( see page 1411)
Note: For details on what appears in the generated _TLB unit, see Code generated when you import type library information (
see page 1421).
For example, consider a Caption property, of type TCaption in the underlying VCL object. To Add this property to the object's
interface, you enter the following when you add a property to the interface via the type library editor:
property Caption: TCaption read Get_Caption write Set_Caption;
Delphi adds the following declarations to the wrapper class:
function Get_Caption: WideString; safecall;
procedure Set_Caption(const Value: WideString); safecall;
STDMETHOD(get_Caption(BSTR* Value));
STDMETHOD(set_Caption(BSTR Value));
In addition, it adds skeletal method implementations for you to complete:
function TButtonX.Get_Caption: WideString;
begin
end;
procedure TButtonX.Set_Caption(Value: WideString);
begin
3 end;
STDMETHODIMP TButtonXImpl::get_Caption(BSTR* Value)
{
try
{
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
1412
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
};
STDMETHODIMP TButtonXImpl::set_Caption(BSTR Value)
{
try
{
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
Typically, you can implement these methods by simply delegating to the associated VCL control, which can be accessed using
the FDelphiControl member of the wrapper class:
function TButtonX.Get_Caption: WideString;
begin
Result := WideString(FDelphiControl.Caption);
end;
Note: Because the Automation interface methods are declaredsafecall, you do not have to implement COM exception code
for these methods—the Delphi compiler handles this for you by generating code around the body of safecall methods
to catch Delphi exceptions and to convert them into COM error info structures and return codes. 3
See Also
Code Generated When You Import Type Library Information ( see page 1421)
1413
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
mechanism is described in Managing events in your Automation object ( see page 1437).
If the VCL control you are using as the basis of your ActiveX control has any published events, the wizards automatically add the
necessary support for managing a list of client event sinks to your ActiveX wrapper class and define the outgoing dispinterface
that clients must implement to respond to events.
You add events to this outgoing dispinterface. To add an event in the type library editor, select the event interface and click on
the method icon. Then manually add the list of parameters you want include using the parameter page.
Next, you must declare a method in your wrapper class that is of the same type as the event handler for the event in the
underlying VCL control. This is not generated automatically, because Delphi does not know which event handler you are using:
procedure KeyPressEvent(Sender: TObject; var Key: Char);
Implement this method to use the host application's event sink, which is stored in the wrapper class's FEvents member:
procedure TButtonX.KeyPressEvent(Sender: TObject; var Key: Char);
var
TempKey: Smallint;
begin
TempKey := Smallint(Key); {cast to an OleAutomation compatible type }
if FEvents <> nil then
FEvents.OnKeyPress(TempKey)
Key := Char(TempKey);
end;
void __fastcall TButtonXImpl::KeyPressEvent(TObject *Sender, char &Key)
{
short TempKey;
TempKey = (short)Key;
Fire_OnKeyPress(&TempKey);
Key = (short)TempKey;
};
Note: When firing events in an ActiveX control, you do not need to iterate through a list of event sinks because the control only
has a single host application. This is simpler than the process for most Automation servers.
Finally, you must assign this event handler to the underlying VCL control, so that it is called when the event occurs. You make
this assignment in the InitializeControl method:
procedure TButtonX.InitializeControl;
begin
FDelphiControl := Control as TButton;
FDelphiControl.OnClick := ClickEvent;
FDelphiControl.OnKeyPress := KeyPressEvent;
end;
void InitializeControl()
{
m_VclCtl->OnClick = ClickEvent;
m_VclCtl->OnKeyPress = KeyPressEvent;
}
See Also
Code Generated When You Import Type Library Information ( see page 1421)
3
3.2.2.3.9 Enabling Simple Data Binding with the Type Library
With simple data binding, you can bind a property of your ActiveX control to a field in a database. To do this, the ActiveX control
must communicate with its host application about what value represents field data and when it changes. You enable this
communication by setting the property's binding flags using the Type Library editor.
By marking a property bindable, when a user modifies the property (such as a field in a database), the control notifies its
container (the client host application) that the value has changed and requests that the database record be updated. The
1414
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
container interacts with the database and then notifies the control whether it succeeded or failed to update the record.
Note: The container application that hosts your ActiveX control is responsible for connecting the data-aware properties you
enable in the type library to the database.
Binding Description
attribute
Bindable Indicates that the property supports data binding. If marked bindable, the property notifies its container when the
property value has changed.
Request Indicates that the property supports the OnRequestEdit notification. This allows the control to ask the container if
Edit its value can be edited by the user.
Display Indicates that the container can show users that this property is bindable.
Bindable
Default Indicates the single, bindable property that best represents the object. Properties that have the default bind
Bindable attribute must also have the bindable attribute. Cannot be specified on more than one property in a dispinterface.
Immediate Allows individual bindable properties on a form to specify this behavior. When this bit is set, all changes will be
Bindable notified. The bindable and request edit attribute bits need to be set for this new bit to have an effect.
4. Click the Refresh button on the toolbar to update the type library. To test a data-binding control, you must register it first. For
example, to convert a TEdit control into a data-bound ActiveX control, create the ActiveX control from a TEdit and then
change the Text property flags to Bindable, Display Bindable, Default Bindable, and Immediate Bindable. After the control is
registered and imported, it can be used to display data.
See Also
Working with Type Libraries: Overview ( see page 1445)
Typically, users access the property page by right-clicking the ActiveX control and choosing Properties.
1415
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
For example, the following illustration shows a property page for setting the MaskEdit property of an ActiveX control.
The list box allows the user to select from a list of sample masks. The edit controls allow the user to test the mask before
applying it to the ActiveX control. You add controls to the property page the same as you would to a form.
See Also
Creating a Property Page for an ActiveX Control ( see page 1415)
See Also
Creating a Property Page for an ActiveX Control ( see page 1415)
3
3.2.2.3.14 Updating the Property Page
Add code to the UpdatePropertyPage method to update the control on the property page when the properties of the ActiveX
control change. You must add code to the UpdatePropertyPage method to update the property page with the current values of
the ActiveX control's properties.
You can access the ActiveX control using the property page's OleObject property, which is an OleVariant that contains the
ActiveX control's interface.
1416
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
For example, the following code updates the property page's edit control (InputMask) with the current value of the ActiveX
control's EditMask property:
procedure TPropertyPage1.UpdatePropertyPage;
begin
{ Update your controls from OleObject }
InputMask.Text := OleObject.EditMask;
end;
For example, the following code updates the property page's edit control (InputMask) with tthe current value of the ActiveX
control's EditMask property:
void __fastcall TPropertyPage1::UpdatePropertyPage(void)
{
InputMask->Text = OleObject.OlePropertyGet("EditMask");
}
Note: It is also possible to write a property page that represents more than one ActiveX control. In this case, you don't use the
OleObject property. Instead, you must iterate through a list of interfaces that is maintained by the OleObjects property.
See Also
Creating a Property Page for an ActiveX Control ( see page 1415)
For example, the following code sets the EditMask property of the ActiveX control using the value in the property page's edit box
control (InputMask):
procedure TPropertyPage1.UpdateObject;
begin
{Update OleObject from your control }
OleObject.EditMask := InputMask.Text;
end;
void __fastcall TPropertyPage1::UpdateObject(void)
{
// Update OleObject from your control
OleObject.OlePropertySet<WideString>("EditMask", WideString(InputMast->Text).Copy());
}
See Also
Creating a Property Page for an ActiveX Control ( see page 1415)
1417
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
2. Add the property page unit to the uses clause of the controls implementation unit.
See Also
Creating a Property Page for an ActiveX Control ( see page 1415)
1418
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Using Component Wrappers ( see page 1422) If you generated a component wrapper for your server object, writing your COM
client application is not very different from writing any other application that
contains VCL components. The server object's properties, methods, and events
are already encapsulated in the VCL component. You need only assign event
handlers, set property values, and call methods.
To use the properties, methods, and events of the server object, see the
documentation for your server. The component wrapper automatically provides a
dual interface ( see page 1438) where possible. Delphi determines the VTable
layout from information in the type library.
In addition, your new component inherits certain important... more ( see page
1422)
Writing Client Code Based On Type Library Definitions ( see page 1423) Although you must use a component wrapper for hosting an ActiveX control, you
can write an Automation controller using only the definitions from the type library
that appear in the TypeLibName_TLB unit. This process is a bit more involved
that letting a component do the work, especially if you need to respond to events.
The following topics describe how to implement the various actions your
Automation controller needs to perform:
At first glance these two types of COM client are very different: The typical Automation controller launches an external server
EXE and issues commands to make that server perform tasks on its behalf. The Automation server is usually nonvisual and
out-of-process. The typical ActiveX client, on the other hand, hosts a visual control, using it much the same way you use any
control on the Component palette. ActiveX servers are always in-process servers.
1419
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
However, the task of writing these two types of COM client is remarkably similar: The client application obtains an interface for
the server object and uses its properties and methods. RAD Studio makes this particularly easy by letting you wrap the server
CoClass in a component on the client, which you can even install on the Component palette.
When writing a COM client, you must understand the interface that the server exposes to clients, just as you must understand
the properties and methods of a component from the Component palette to use it in your application. This interface (or set of
interfaces) is determined by the server application, and typically published in a type library ( see page 1445). For specific
information on a particular server application’s published interfaces, you should consult that application’s documentation.
Even if you do not choose to wrap a server object in a component wrapper and install it on the Component palette, you must
make its interface definition available to your application. To do this, you can import the server’s type information ( see page
1420).
Once you have imported the type information, you can write code to control the imported object ( see page 1422).
Note: You can also query the type information directly using COM APIs, but RAD Studio provides no special support for this.
Some older COM technologies, such as object linking and embedding (OLE), do not provide type information in a type library.
Instead, they rely on a standard set of predefined interfaces. These are discussed in Creating Clients for Servers That Do Not
Have a Type Library ( see page 1426).
See Also
Creating Active Server Pages ( see page 1400)
• You can use the Import Component dialog to import all available information about the server types, objects, and interfaces.
This is the most general method, because it lets you import information from any type library and can optionally generate
component wrappers for all creatable CoClasses in the type library that are not flagged as Hidden, Restricted, or PreDeclID.
• You can also use the Import Component dialog if you are importing from the type library of an ActiveX control. This imports
the same type information, but only creates component wrappers for CoClasses that represent ActiveX controls.
• You can use the command line utility tlibimp.exe which provides additional configuration options not available from within the
IDE.
• A type library generated using a wizard is automatically imported using the same mechanism as the import type library menu
item.
Regardless of which method you choose to import type library information, the resulting dialog creates a unit with the name
TypeLibName_TLB, where TypeLibName is the name of the type library. This file contains declarations for the classes, types,
3 and interfaces defined in the type library. By including it in your project, those definitions are available to your application so
that you can create objects and call their interfaces. This file may be recreated by the IDE from time to time; as a result,
making manual changes to the file is not recommended.
In addition to adding type definitions to the TypeLibName_TLB unit, the dialog can also create VCL class wrappers for any
CoClasses defined in the type library. When you use the Import Type Library dialog, these wrappers are optional. When you
use the Import ActiveX dialog, they are always generated for all CoClasses that represent controls.
The generated class wrappers represent the CoClasses to your application, and expose the properties and methods of its
interfaces. If a CoClass supports the interfaces for generating events (IConnectionPointContainer and IConnectionPoint), the
VCL class wrapper creates an event sink so that you can assign event handlers for the events as simply as you can for any
1420
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
other component. If you tell the dialog to install the generated VCL classes on the Tool Palette, you can use the Object
Inspector to assign property values and event handlers.
Note: The Import Component dialog
does not create class wrappers for COM+ event objects. To write a client that responds to events generated by a COM+
event object, you must create the event sink programmatically. This process is described in Handling COM+ events ( see
page 1425). For more details about the code generated when you import a type library, see Code generated when you import
type library information ( see page 1421).
See Also
Working with Type Libraries ( see page 1445)
First, constant declarations giving symbolic names to the GUIDS of the type library and its interfaces and CoClasses. The names
for these constants are generated as follows:
• the GUID for the type library has the form LBID_TypeLibName, where TypeLibName is the name of the type library.
• The GUID for an interface has the form IID_InterfaceName, where InterfaceName is the name of the interface.
• The GUID for a dispinterface has the form DIID_InterfaceName, where InterfaceName is the name of the dispinterface.
• The GUID for a CoClass has the form CLASS_ClassName, where ClassName is the name of the CoClass.
• The compiler directive VARPROPSETTER will be on. This allows the use of the keyword var in the parameter list of property
setter methods. This disables a compiler optimization that would cause parameters to be passed by value instead of by
reference. The VARPROPSETTER directive must be on, when creating TLB units for components written in a language other
than Delphi.
Second, declarations for the CoClasses in the type library. These map each CoClass to its default interface.
Third, declarations for the interfaces and dispinterfaces in the type library.
Fourth, declarations for a creator class for each CoClass whose default interface supports VTable binding. The creator class has
two class methods, Create and CreateRemote, that can be used to instantiate the CoClass locally (Create) or remotely
(CreateRemote).These methods return the default interface for the CoClass.
These declarations provide you with what you need to create instances of the CoClass and access its interface. All you need do
is add the generated TypeLibName_TLB.pas file to the uses clause of the unit where you wish to bind to a CoClass and call
its interfaces.
Note: This portion of the TypeLibName_TLB unit is also generated when you use the Type Library editor or the
command-line utility TLIBIMP.
If you want to use an ActiveX control, you also need the generated VCL wrapper in addition to the declarations described
above. The VCL wrapper handles window management issues for the control. You may also have generated a VCL wrapper
for other CoClasses in the Import Type Library dialog. These VCL wrappers simplify the task of creating server objects and
calling their methods. They are especially recommended if you want your client application to respond to events.
The declarations for generated VCL wrappers appear at the bottom of the interface section. Component wrappers for ActiveX
controls are descendants of TOleControl. Component wrappers for Automation objects descend from TOleServer. The 3
generated component wrapper adds the properties, events, and methods exposed by the CoClass's interface. You can use
this component like any other VCL component.
Warning: You should not edit the generated TypeLibName_TLB unit. It is regenerated each time the type library is refreshed,
so any changes will be overwritten.
Note: For the most up-to-date information about the generated code, refer to the comments in the automatically-generated
TypeLibName_TLB unit.
1421
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
To use the properties, methods, and events of the server object, see the documentation for your server. The component wrapper
automatically provides a dual interface ( see page 1438) where possible. Delphi determines the VTable layout from information
in the type library.
In addition, your new component inherits certain important properties and methods from its base class.
ActiveX wrappers
You should always use a component wrapper when hosting ActiveX controls, because the component wrapper integrates the
control's window into the VCL framework.
The properties and methods an ActiveX control inherits from TOleControl allow you to access the underlying interface or obtain
information about the control. Most applications, however, do not need to use these. Instead, you use the imported control the
same way you would use any other VCL control.
Typically, ActiveX controls provide a property page that lets you set their properties. Property pages are similar to the component
editors some components display when you double-click on them in the form designer. To display an ActiveX control's property
page, right click and choose Properties.
The way you use most imported ActiveX controls is determined by the server application. However, ActiveX controls use a
standard set of notifications when they represent the data from a database field. See TOleControl for information on how to host
such ActiveX controls.
First, the ConnectKind property indicates whether the server is local or remote and whether you want to connect to a server that
is already running or if a new instance should be launched. When connecting to a remote server, you must specify the machine
3 name using the RemoteMachineName property.
Second, once you have specified the ConnectKind, there are three ways you can connect your component to the server:
• you can explicitly connect to the server by calling the component's Connect method.
• You can tell the component to connect automatically when your application starts up by setting the AutoConnect property to
true.
• You do not need to explicitly connect to the server. The component automatically forms a connection when you use one of the
server's properties or methods using the component.
1422
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Calling methods or accessing properties is the same as using any other component:
TServerComponent1.DoSomething;
TServerComponent1->DoSomething();
Handling events is easy, because you can use the Object Inspector to write event handlers. Note, however, that the event
handler on your component may have slightly different parameters than those defined for the event in the type library.
Specifically, pointer types (var parameters and interface pointers) are changed to Variants. You must explicitly cast var
parameters to the underlying type before assigning a value. Interface pointers can be cast to the appropriate interface type using
the as operator.
For example, the following code shows an event handler for the ExcelApplication event, OnNewWorkBook. The event handler
has a parameter that provides the interface of another CoClass (ExcelWorkbook). However, the interface is not passed as an
ExcelWorkbook interface pointer, but rather as an OleVariant.
procedure TForm1.XLappNewWorkbook(Sender: TObject; var Wb:OleVariant);
begin
{ Note how the OleVariant for the interface must be cast to the correct type }
ExcelWorkbook1.ConnectTo((iUnknown(wb) as ExcelWorkbook));
end;
void _fastcall TForm1::XLappNewWorkbook(TObject *Sender, ExcelWorkbookPtr Wb)
{
ExcelWorkbook1->ConnectTo(Wb);
}
In this example, the event handler assigns the workbook to an ExcelWorkbook component (ExcelWorkbook1). This
demonstrates how to connect a component wrapper to an existing interface by using the ConnectTo method. The ConnectTo
method is added to the generated code for the component wrapper.
Servers that have an application object expose a Quit method on that object to let clients terminate the connection. Quit typically
exposes functionality that is equivalent to using the File menu to quit the application. Code to call the Quit method is generated in
your component's Disconnect method. If it is possible to call the Quit method with no parameters, the component wrapper also
has an AutoQuit property. AutoQuit causes your controller to call Quit when the component is freed. If you want to disconnect at
some other time, or if the Quit method requires parameters, you must call it explicitly. Quit appears as a public method on the
generated component.
See Also
Writing Client Code Based On Type Library Definitions ( see page 1423)
Creating Clients for Servers That Do Not Have a Type Library ( see page 1426)
The following topics describe how to implement the various actions your Automation controller needs to perform:
Creating Clients for Servers That Do Not Have a Type Library ( see page 1426)
1423
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
If the main interface is a dual interface ( see page 1438), you can use the creator objects in the TypeLibName_TLB.pas file.
The creator classes have the same name as the CoClass, with the prefix "Co" added. You can connect to a server on the same
machine by calling the Create method, or a server on a remote machine using the CreateRemote method. Because Create and
CreateRemote are class methods, you do not need an instance of the creator class to call them.
MyInterface := CoServerClassName.Create;
MyInterface := CoServerClassName.CreateRemote('Machine1');
pInterface = CoServerClassName.Create();
pInterface = CoServerClassName.CreateRemote("Machine1");
Create and CreateRemote return the default interface for the CoClass.
If the default interface is a dispatch interface, then there is no Creator class generated for the CoClass. Instead, you can call the
global CreateOleObject function, passing in the GUID for the CoClass (there is a constant for this GUID defined at the top of the
_TLB unit). CreateOleObject returns an IDispatch pointer for the default interface.
See Also
Controlling an Automation Server Using a Dispatch Interface ( see page 1424)
See Also
Controlling an Automation Server Using a Dispatch Interface ( see page 1424)
1424
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
3. Control the Automation server by calling methods of the dispinterface. Another way to use dispatch interfaces is to assign
them to a Variant. By assigning the interface returned by CreateOleObject to a Variant, you can take advantage of the Variant
type's built-in support for interfaces. Simply call the methods of the interface, and the Variant automatically handles all
IDispatch calls, fetching the dispatch ID and invoking the appropriate method. The Variant type includes built-in support for
calling dispatch interfaces, through its var.
V: Variant;
begin
V:= CreateOleObject("TheServerObject");
V.MethodName; { calls the specified method }
...
An advantage of using Variants is that you do not need to import the type library, because Variants use only the standard
IDispatch methods to call the server. The trade-off is that Variants are slower, because they use dynamic binding at runtime.
See Also
Controlling an Automation Server Using a Dual Interface ( see page 1424)
To write the event sink, create an object that implements the event dispatch interface:
TServerEventsSink = class(TObject, _TheServerEvents)
...{ declare the methods of _TheServerEvents here }
end;
class MyEventSinkClass: TEventDispatcher<MyEventSinkClass, DIID_TheServerEvents>
{
...// declare the methods of DIID_TheServerEvents here
}
Once you have an instance of your event sink, you must inform the server object of its existence so that the server can call it. To
do this, you call the global InterfaceConnect procedure, passing it
You must terminate the connection before you free your event sink. To do this, call the global InterfaceDisconnect procedure,
passing it all the same parameters except for the interface to your event sink (and the final parameter is ingoing rather than
outgoing):
InterfaceDisconnect(MyInterface, DIID_TheServerEvents, cookievar);
ES.DisconnectEvents(pInterface);
1425
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Note: You must be certain that the server has released its connection to your event sink before you free it. Because you don't
know how the server responds to the disconnect notification initiated by InterfaceDisconnect, this may lead to a race condition if
you free your event sink immediately after the call. The easiest way to guard against problems is to have your event sink
maintain its own reference count that is not decremented until the server releases the event sink's interface.
Instead of defining an event sink, your client application defines a subscriber object. Subscriber objects, like event sinks, provide
the implementation of the event interface. They differ from event sinks in that they subscribe to a particular event object rather
than connecting to a server's connection point.
To define a subscriber object, use the COM Object wizard ( see page 1431), selecting the event object's interface as the one
you want to implement. The wizard generates an implementation unit with skeletal methods that you can fill in to create your
event handlers.
Note: You may need to add the event object's interface to the registry using the wizard if it does not appear in the list of
interfaces you can implement.
Once you create the subscriber object, you must subscribe to the event object's interface or to individual methods (events) on
that interface. There are three types of subscriptions from which you can choose:
• Transient subscriptions. Like traditional event sinks, transient subscriptions are tied to the lifetime of an object instance.
When the subscriber object is freed, the subscription ends and COM+ no longer forwards events to it.
• Persistent subscriptions. These are tied to the object class rather than a specific object instance. When the event occurs,
COM locates or launches an instance of the subscriber object and calls its event handler. In-process objects (DLLs) use this
type of subscription.
• Per-user subscriptions. These subscriptions provide a more secure version of transient subscriptions. Both the subscriber
object and the server object that fires events must be running under the same user account on the same machine.
Note: Objects that subscribe to COM+ events must be installed in a COM+ application.
See Also
Controlling an Automation Server Using a Dispatch Interface ( see page 1424)
3.2.2.4.11 Creating Clients for Servers That Do Not Have a Type Library
Some older COM technologies, such as object linking and embedding (OLE), do not provide type information in a type library.
Instead, they rely on a standard set of predefined interfaces. To write clients that host such objects, you can use the
TOleContainer component. This component appears on the System category of the Tool Palette.
TOleContainer acts as a host site for an Ole2 object. It implements the IOleClientSite interface and, optionally,
IOleDocumentSite. Communication is handled using OLE verbs.
3
To use TOleContainer
1. Place a TOleContainer component on your form.
2. Set the AllowActiveDoc property to true if you want to host an Active document.
3. Set the AllowInPlace property to indicate whether the hosted object should appear in the TOleContainer, or in a separate
window.
4. Write event handlers to respond when the object is activated, deactivated, moved, or resized.
1426
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
5. To bind the TOleContainer object at design time, right click and choose Insert Object. In the Insert Object dialog, choose a
server object to host.
6. To bind the TOleContainer object at runtime, you have several methods to choose from, depending on how you want to
identify the server object. These include CreateObject, which takes a program id, CreateObjectFromFile, which takes the
name of a file to which the object has been saved, CreateObjectFromInfo, which takes a record containing information on how
to create the object, or CreateLinkToFile, which takes the name of a file to which the object was saved and links to it rather
than embeds it.
7. Once the object is bound, you can access its interface using the OleObjectInterface property. However, because
communication with Ole2 objects was based on OLE verbs, you will most likely want to send commands to the server using
the DoVerb method.
8. When you want to release the server object, call the DestroyObject method.
See Also
Using Component Wrappers ( see page 1422)
Writing Client Code Based On Type Library Definitions ( see page 1423)
1427
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Using the COM Object Wizard ( see page 1431) The COM object wizard performs the following tasks:
1428
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Automation Interfaces ( see page 1438) The Automation Object wizard implements a dual interface ( see page 1438)
by default, which means that the Automation object supports both
1429
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Registering a COM Object ( see page 1440) You can register your server object as an in-process or an out-of-process server.
For more information on the server types, see In-process ( see page 1389).
Note: Before you remove a COM object from your system, you should unregister
it.
Testing and Debugging the Application ( see page 1440) Once you have created a COM server application, you will want to test it before
you deploy it.
Two wizards, in particular, ease the process of creating simple COM objects:
• The COM Object wizard ( see page 1431) builds a lightweight COM object whose default interface descends from IUnknown
( see page 1387) or that implements an interface already registered on your system. This wizard provides the most flexibility
in the types of COM objects you can create.
• The Automation Object wizard ( see page 1432) creates a simple Automation object whose default interface descends from
IDispatch ( see page 1438). IDispatch introduces a standard marshaling mechanism and support for late binding of interface
calls.
Note: COM defines many standard interfaces and mechanisms for handling specific situations. The Delphi wizards automate
the most common tasks. However, some tasks, such as custom marshaling, are not supported by any Delphi wizards. For
information on that and other technologies not explicitly supported by Delphi, refer to the Microsoft Developer's Network
(MSDN) documentation. The Microsoft Web site also provides current information on COM support.
Overview of creating a COM object
Whether you use the Automation Object wizard to create a new Automation server or the COM object wizard to create some
other type of COM object, the process you follow is the same.
• To create a COM object that implements an existing interface, use the COM Object wizard ( see page 1431).
• To create a COM object that implements a new interface that you define, use either the COM Object wizard ( see page
1431) or the Automation Object wizard ( see page 1432). The COM object wizard can generate a new default interface that
descends from IUnknown ( see page 1387), and the Automation object gives your object a default interface that descends
from IDispatch ( see page 1438). No matter which wizard you use, you can always use the Type Library editor later to
1430
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
change the parent interface of the default interface that the wizard generates.
In addition to deciding what interfaces to support, you must decide whether the COM object is an in-process server ( see page
1389). For in-process servers and for out-of-process and remote servers that use a type library, COM marshals the data for
you. Otherwise, you must consider how to marshal the data to out-of-process servers.
1431
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
specified in its type library. If your object's interface is not marked as OleAutomation, you must either create an in-process
server or write your own marshaling code.
You can optionally add a description of your COM object. This description appears in the type library for your object if you create
one.
See Also
Implementing COM objects with Wizards ( see page 1397)
1432
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Note: Instancing is ignored when your COM object is used only as an in-process server.
When the wizard creates a new COM object, it can have any of the following instancing types:
Instancing Meaning
Internal The object can only be created internally. An external application cannot create an instance of the object directly,
although your application can create the object and pass an interface for it to clients.
Single Allows clients to create only a single instance of the object for each executable (application), so creating multiple
Instance instances results in launching multiple instances of the application. Each client has its own dedicated instance of
the server application.
Multiple Specifies that multiple clients can create instances of the object in the same process space.
Instances
The following table lists the different threading models you can specify.
1433
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Both This is the same as the Free-threaded Maximum performance and flexibility.
model except that outgoing calls (for Does not require the application to provide thread support for
example, callbacks) are guaranteed to parameters supplied to outgoing calls.
execute in the same thread.
Neutral Multiple clients can call the object on You must guard against thread conflicts involving global data and
different threads at the same time, but any instance data that is accessed by multiple methods.
COM ensures that no two calls conflict. This model should not be used with objects that have a user
interface (visual controls).
This model is only available under COM+. Under COM, it is
mapped to the Apartment model.
Note: Local variables (except those in callbacks) are always safe, regardless of the threading model. This is because local
variables are stored on the stack and each thread has its own stack. Local variables may not be safe in callbacks when using
free-threading.
The threading model you choose in the wizard determines how the object is registered in the system Registry. You must make
sure that your object implementation adheres to the threading model you have chosen. For general information on writing
thread-safe code, see Writing multi-threaded applications.
For in-process servers, setting the threading model in the wizard sets the threading model key in the CLSID registry entry.
Out-of-process servers are registered as EXE, and Delphi initializes COM for the highest threading model required. For example,
if an EXE includes a free-threaded object, it is initialized for free threading, which means that it can provide the expected support
for any free-threaded or apartment-threaded objects contained in the EXE. To manually override threading behavior in EXEs,
use the CoInitFlags variable.
If the object supported the apartment threading model instead, the call would have to be transferred to the thread on which the
object was created, and the result would have to be transferred back into the receiving thread before returning to the client. This
approach requires extra marshaling.
To support free threading, you must consider how instance data can be accessed for each method. If the method is writing to
instance data, you must use critical sections or some other form of serialization, to protect the instance data. Likely, the
overhead of serializing critical calls is less than executing COM's marshaling code.
Free-threaded in-process servers can improve performance by acting as the outer object in an aggregation ( see page 1391)
with the free-threaded marshaler. The free-threaded marshaler provides a shortcut for COM's standard thread handling when a
free-threaded DLL is called by a host (client) that is not free-threaded.
3 To aggregate with the free threaded marshaler, you must
• Call CoCreateFreeThreadedMarshaler, passing your object's IUnknown interface for the resulting free-threaded marshaler to
use: CoCreateFreeThreadedMarshaler(self as IUnknown, FMarshaler);
CoCreateFreeThreadedMarshaler(static_cast<IUnknown *>(this), &FMarshaler);. This line assigns the
interface for the free-threaded marshaler to a class member, FMarshaler.
• Using the Type Library Editor, add the IMarshal interface to the set of interfaces your CoClass implements.
• In your object's QueryInterface method, delegate calls for IDD_IMarshal to the free-threaded marshaler (stored as FMarshaler
above).
1434
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Warning: The free-threaded marshaler violates the normal rules of COM marshaling to provide additional efficiency. It should
be used with care. In particular, it should only be aggregated with free-threaded objects in an in-process server, and should
only be instantiated by the object that uses it (not another thread).
Writing an object that supports the apartment threading model
To implement the (single-threaded) apartment threading model, you must follow a few rules:
• The first thread in the application that gets created is COM's main thread. This is typically the thread on which WinMain was
called. This must also be the last thread to uninitialize COM.
• Each thread in the apartment threading model must have a message loop, and the message queue must be checked
frequently.
• When a thread gets a pointer to a COM interface, that pointer may only be used in that thread.
The single-threaded apartment model is the middle ground between providing no threading support and full, multi-threading
support of the free threading model. A server committing to the apartment model promises that the server has serialized
access to all of its global data (such as its object count). This is because different objects may try to access the global data
from different threads. However, the object's instance data is safe because the methods are always called on the same thread.
Typically, controls for use in Web browsers use the apartment threading model because browser applications always initialize
their threads as apartment.
Writing an object that supports the neutral threading model
Under COM+, you can use another threading model that is in between free threading and apartment threading: the neutral
model. Like the free-threading model, this model allows multiple threads to access your object at the same time. There is no
extra marshaling to transfer to the thread on which the object was created. However, your object is guaranteed to receive no
conflicting calls.
Writing an object that uses the neutral threading model follows much the same rules as writing an apartment-threaded object,
except that you do need to guard instance data against thread conflicts if it can be accessed by different methods in the object's
interface. Any instance data that is only accessed by a single interface method is automatically thread-safe.
Note: If you selected an existing interface in the COM object wizard, you do not need to add properties and methods. The
definition of the interface is imported from the type library in which it was defined. Instead, simply locate the methods of the
imported interface in the implementation unit and fill in their bodies.
1435
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
3. In the Attributes pane, specify the name and type of the property.
4. On the Type Library Editor toolbar, click the Refresh Implementation button. A definition and skeletal implementations for
the property access methods are inserted into the object's implementation unit.
5. In the implementation unit, locate the access methods for the property. These have names of the form Get_PropertyName
and Set_PropertyName. Add code that gets or sets the property value of your object. This code may simply call an existing
function inside the application, access a data member that you add to the object definition, or otherwise implement the
property.
Adding a method to the object's interface
When you add a method ( see page 1462) to your object's interface using the Type Library Editor, the Type Library Editor
can, in turn, add the methods to your implementation class, and in your implementation unit create empty implementation for you
to complete.
• COM+ events require that you create a separate event object using the event object wizard and add code to call that event
object from your server object.
• You can use the wizard to handle much of the work in generating traditional events. This process is described below.
Note: The COM object wizard does not generate event support code. If you want your object to generate traditional events,
you should use the Automation object wizard
.
1436
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
5. On the Type Library Editor toolbar, click the Refresh Implementation button. Your object implementation now has
everything it needs to accept client event sinks and maintain a list of interfaces to call when the event occurs. To call these
interfaces, you can create a method to generate each event on clients.
6. In the Code Editor, add a method to your object for firing each event. For example,
unit ev;
interface
uses
ComObj, AxCtrls, ActiveX, Project1_TLB;
type
TMyAutoObject = class (TAutoObject,IConnectionPointContainer, IMyAutoObject)
private
.
.
.
public
procedure Initialize; override;
procedure Fire_MyEvent; { Add a method to fire the event}
7. Implement the method you added in the last step so that it iterates through all the event sinks maintained by your object's
FConnectionPoint member:
procedure TMyAutoObject.Fire_MyEvent;
var
I: Integer;
EventSinkList: TList;
EventSink: IMyAutoObjectEvents;
begin
if FConnectionPoint <> nil then
begin
EventSinkList :=FConnectionPoint.SinkList; {get the list of client sinks }
for I := 0 to EventSinkList.Count - 1 do
begin
EventSink := IUnknown(FEvents[I]) as IMyAutoObjectEvents;
EventSink.MyEvent;
end;
end;
end;
8. Whenever you need to fire the event so that clients are informed of its occurrence, call the method that dispatches the event
to all event sinks:
if EventOccurs then Fire_MyEvent; { Call method you created to fire events.}
if (EventOccurs) Fire_MyEvent; // Call method you created to fire events.
See Also
Working with Type Libraries: Overview ( see page 1445)
For a server to support traditional COM events, it must provide the definition of an outgoing interface which is implemented by a
client. This outgoing interface includes all the event handlers the client must implement to respond to server events.
3
When a client has implemented the outgoing event interface, it registers its interest in receiving event notification by querying the
server's IConnectionPointContainer interface. The IConnectionPointContainer interface returns the server's IConnectionPoint
interface, which the client then uses to pass the server a pointer to its implementation of the event handlers (known as a sink).
The server maintains a list of all client sinks and calls methods on them when an event occurs.
When you select Generate Event Support Code, Delphi automatically generates the code necessary to support IConnectionPoint
1437
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
and IConnectionPointContainer. This support, and the way you can use it to generate events is described in Exposing events to
clients ( see page 1435).
See Also
Using the Automation Object Wizard ( see page 1432)
• Late binding at runtime, which is through the IDispatch interface. This is implemented as a dispatch interface, or dispinterface
( see page 1438).
• Early binding at compile-time, which is accomplished through directly calling one of the member functions in the object's
virtual function table (VTable). This is referred to as a custom interface ( see page 1439).
Note: Any interfaces generated by the COM Object
wizard that do not descend from IDispatch only support VTable calls.
Dual interfaces offer the following combined advantages of VTable interfaces and dispinterfaces:
• For VTable interfaces, the compiler performs type checking and provides more informative error messages.
• For Automation controllers that cannot obtain type information, the dispinterface provides runtime access to the object.
• For in-process servers, you have the benefit of fast access through VTable interfaces.
• For out-of-process servers, COM marshals data ( see page 1439) for both VTable interfaces and dispinterfaces. COM
provides a generic proxy/stub implementation that can marshal the interface based on the information contained in a type
library.
The first three entries of the VTable for a dual interface refer to the IUnknown interface, the next four entries refer to the
IDispatch interface, and the remaining entries are COM entries for direct access to members of the custom interface.
Once it has the dispID, the controller can then call the IDispatch method, Invoke, to execute the appropriate code (property or
method), packaging the parameters for the property or method into one of the Invoke parameters. Invoke has a fixed
compile-time signature that allows it to accept any number of arguments when calling an interface method.
The Automation object's implementation of Invoke must then unpackage the parameters, call the property or method, and be
prepared to handle any errors that occur. When the property or method returns, the object passes its return value back to the
controller.
1438
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
This is called late binding because the controller binds to the property or method at runtime rather than at compile time.
If the object has a type library, you can access the custom interface through its VTable layout, which you can get using the Type
Library Editor. If the object has a type library and also supports IDispatch, a client can also get the dispIDs of the IDispatch
interface and bind directly to a VTable offset. Delphi's type library importer (TLIBIMP) retrieves dispIDs at import time, so clients
that use dispinterfaces can avoid calls to GetIDsOfNames; this information is already in the _TLB unit. However, clients still need
to call Invoke.
First, the predefined valid types such as Smallint, Integer, Single, Double, WideString. For a complete list, see Valid types ( see
page 1454).
Second, enumeration types defined in a type library. OLE Automation-compatible enumeration types are stored as 32-bit values
and are treated as values of type Integer for purposes of parameter passing.
Third, interface types defined in a type library that are OLE Automation safe, that is, derived from IDispatch and containing only
OLE Automation compatible types.
Fifth, any custom record type defined within the type library.
Sixth, IFont, IStrings, and IPicture. Helper objects must be instantiated to map
3
• an IFont to a TFont
• an IStrings to a TStrings
• an IPicture to a TPicture
The ActiveX control and ActiveForm wizards create these helper objects automatically when needed. To use the helper objects,
call the global routines, GetOleFont, GetOleStrings, GetOlePicture, respectively.
1439
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
• String data types must be transferred as wide strings (BSTR). PChar, UnicodeString and AnsiString cannot be marshaled
safely.
• All members of a dual interface must pass an HRESULT as the function's return value. If the method is declared using the
safecall calling convention, this condition is imposed automatically, with the declared return type converted to an output
parameter.
• Members of a dual interface that need to return other values should specify these parameters as var or out, indicating an
output parameter that returns the value of the function.
Note: One way to bypass the Automation types restrictions is to implement a separate IDispatch interface and a custom
interface. By doing so, you can use the full range of possible argument types. This means that COM clients have the option of
using the custom interface, which Automation controllers can still access. In this case, though, you must implement the
marshaling code manually.
Custom marshaling
Typically, you use automatic marshaling in out-of-process and remote servers because it is easier—COM does the work for you.
However, you may decide to provide custom marshaling if you think you can improve marshaling performance. When
implementing your own custom marshaling, you must support the IMarshal interface. For more information, on this approach,
see the Microsoft documentation.
See Also
Working with Type Libraries: Overview ( see page 1445)
Note: Before you remove a COM object from your system, you should unregister it.
To unregister an out-of-process server, run the server with the /unregserver command-line option.
As an alternative, you can use the tregsvr command from the command line or run the regsvr32 command from the
3
operating system.
Note: If the COM server is intended for use under COM+, you should install it in a COM+ application rather than register it.
(Installing the object in a COM+ application automatically takes care of registration.)
1440
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
1441
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Object List Pane ( see page 1448) The Object list pane displays all the elements of the current type library in a tree
view. The root of the tree represents the type library itself, and appears as the
following icon:
Descending from the type library node are the elements ( see page 1451) in
the type library:
When you select any of these elements (including the type library itself), the
pages of type information ( see page 1449) to the right change to reflect only
the relevant information for that element. You can use these pages to edit the
definition and properties of the selected element.
You can manipulate the elements in the object... more ( see page 1448)
Status Bar ( see page 1449) When editing or saving a type library, syntax, translation errors, and warnings are
listed in the Message pane.
For example, if you specify a type that the Type Library Editor does not support,
you will get a syntax error. For a complete list of types supported by the Type
Library Editor, see Valid types ( see page 1454).
Pages of Type Information ( see page 1449) When you select an element ( see page 1451) in the object list pane, pages of
type information appear in the Type Library Editor that are valid for the selected
element. Which pages appear depends on the element selected in the object list
panel, as follows:
Type Library Elements ( see page 1451) The Type Library interface as represented in the Type Library Editor can seem
overwhelmingly complicated at first. This is because it represents information
about a great number of elements, each of which has its own characteristics.
However, many of these characteristics are common to all elements. For
example, every element (including the type library itself) has the following:
1442
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Using Object Pascal or IDL Syntax ( see page 1455) The Code page of the Type Library editor displays your type information in RIDL
format (Restricted Interface Definition Language). The format resembles
Microsoft's IDL sytnax. However, RIDL supports only a subset of IDL. Like Delphi
applications in general, identifiers in type libraries are case insensitive. Identifiers
can be as many as 255 characters long, and for maximum portability should
begin with a letter or an underscore (_).
Creating a New Type Library ( see page 1460) Use the Type Library Wizard to create a type library that is independent of a
particular COM object. For example, you might want to define a type library that
contains type definitions that you use in several other type libraries. You can then
create a type library of basic definitions and add it to the uses page of other type
libraries.
You can also use the wizard to create a type library for an object that is not yet
implemented. Once the type library contains the interface definition, you can use
the COM object wizard ( see page 1431) to generate a CoClass and... more (
see page 1460)
Opening an Existing Type Library ( see page 1460) When you use the wizards to create an Automation object, COM object,
transactional object, or a remote data module, a type library is automatically
created with an implementation unit. Starting with the 2009 product, the wizards
create type libraries in a text-based format (RIDL files). However, you can still
open type libraries in .tlb format that are associated with previous versions or
other products (servers) that are available on your system. The Type Library
Explorer enables you to examine .tlb files.
Adding an Interface to the Type Library ( see page 1461)
Modifying an Interface Using the Type Library ( see page 1461) There are several ways to modify an interface or dispinterface once it is created.
1443
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Saving and Registering Type Library Information ( see page 1465) After modifying your type library, you'll want to save and register the type library
information.
Saving the type library automatically updates:
1444
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Registering the Type Library ( see page 1467) To register the type library, click the Register Type Library button on the Type
Library Editor toolbar.
Typically, you do not need to explicitly register a type library because it is
registered automatically when you register your COM server application (see
Registering a COM object ( see page 1440)). However, when you create a type
library using the Type Library wizard, the type library is not associated with a
server object. In this case, you can register the type library directly using the
toolbar.
Registering the type library adds an entry to the Windows registry for the type
library.
Deploying Type Libraries ( see page 1467) By default, when you have a type library that was created as part of an
Automation server project, the type library is automatically linked into the .DLL,
.OCX, or EXE as a resource.
You can, however, deploy your application with the type library as a separate
.TLB, as Delphi maintains the type library, if you prefer.
Historically, type libraries for Automation applications were stored as a separate
file with the .TLB extension. Now, typical Automation applications compile the
type libraries into the .OCX or .EXE file directly. The operating system expects
the type library to be the first resource in... more ( see page 1467)
GenTLB.exe ( see page 1468) A new type library generator (GenTLB.exe) has been added to RAD Studio.
When you compile or build a project that contains a type library, the type library
generator compiles the text-based RIDL file into the binary .tlb file.
You can use GenTLB.exe in your custom builds. If you use MSBuild from the
command line, then MSBuild automatically uses GenTLB.exe.
Examples
To create AppName.tlb from the contents of AppName.ridl:
RIDL File ( see page 1468) A new file type has been added to the COM architecture for 2009 – the RIDL file
(Restricted Interface Definition Language). The RIDL file is the storage
mechanism that the project uses to persist the type library data to disk. RAD
Studio now uses the .tlb file as an intermediate file (like a .res, .dcu, .obj,
and so forth). This means that you can rebuild the .tlb file from the command
line (outside the IDE), that .tlb files can be edited with a text editor, and the
history is stored by the IDE.
The Type Library Editor... more ( see page 1468)
• Information about custom data types such as aliases, enumerations, structures, and unions.
• Descriptions of one or more COM elements, such as an interface, dispinterface, or CoClass. Each of these descriptions is
commonly referred to as type information ( see page 1449).
• Descriptions of constants and methods defined in external units.
• References to type descriptions from other type libraries.
By including a type library with your COM application or ActiveX library, you make information about the objects in your
application available to other applications and programming tools through COM's type library tools and interfaces.
With traditional development tools, you create type libraries by writing scripts in the Interface Definition Language (IDL) or the
Object Description Language (ODL), then run that script through a compiler. The Type Library editor automates some of this
process, easing the burden of creating and modifying your own type libraries. 3
In addition, the Type Library Editor now uses an intermediate text file known as a RIDL file ( see page 1468). The Code page of
the Type Library Editor displays the RIDL code, and you use the Design page to view and change the type library fields
(coClass, Methods, Properties, and so forth). When you save or build your project, the RIDL file is converted to a standard
binary .tlb file. Both the RIDL file and the .tlb file are saved in your project.
When you create a COM server of any type (Automation object, remote data module, and so on) using Delphi wizards, the
wizard automatically generates a type library for you (although in the case of the COM object wizard, this is optional). Most of
the work you do in customizing the generated object starts with the type library, because that is where you define the
properties and methods it exposes to clients: you change the interface of the CoClass generated by the wizard, using the
1445
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Type Library Editor. The Type Library editor automatically updates the implementation unit for your object, so that all you
need do is fill in the bodies of the generated methods.
See Also
Creating Simple COM Servers: Overview ( see page 1430)
The Type Library Editor outputs two types of file that represent the contents of the type library:
File Description
.ridl The text-based RIDL (Restricted Interface Definition Language) file, introduced for 2009.
file
.tlb The binary type library file. By default, you do not need to use this file, because the type library is automatically
file compiled into the application as a resource. However, you can use this file to explicitly compile the type library into
another project or to deploy the type library separately from the .exe or .ocx. For more information, see Opening an
existing type library ( see page 1460) and Deploying type libraries ( see page 1467).
_TLB This unit reflects the contents of the type library for use by your application. It contains all the declarations your
unit application needs to use the elements defined in the type library. Although you can open this file in the code editor,
you should never edit it—it is maintained by the Type Library Editor, so any changes you make will be overwritten by
the Type Library Editor. For more details on the contents of this file, see Code generated when you import type
library information ( see page 1421)
The following topics describe the Type Library Editor in greater detail:
1446
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Part Description
Toolbar ( see page Includes buttons to add new types, CoClasses, interfaces, and interface members to your type
1447) library. The toolbar also includes buttons for refreshing your implementation unit, registering the type
library, and saving an IDL file with the information in your type library.
Object list pane ( see Displays all the existing elements in the type library. When you click on an item in the object list
page 1448) pane, it displays pages valid for that object.
Status bar ( see page Displays syntax errors if you try to add invalid types to your type library.
1449)
Pages ( see page Display information about the selected object. Which pages appear here depends on the type of
1449) object selected.
See Also
Using the Type Library Editor ( see page 1453)
3.2.2.6.4 Toolbar
The Type Library Editor's toolbar, located at the top of the Type Library Editor, contains buttons that you click to add new
objects into your type library.
The first group of buttons let you add elements to the type library. When you click a toolbar button, the icon for that element
appears in the object list pane. You can then customize its attributes in the right pane. Depending on the type of icon you select,
different pages of information appear to the right.
The following table lists the elements ( see page 1451) you can add to your type library:
Icon Meaning
An interface description.
A dispinterface description.
A CoClass.
An enumeration.
An alias.
A record.
A union.
A module.
When you select one of the elements listed above in the object list pane, the second group of buttons displays members that are
valid for that element. For example, when you select Interface, the Method and Property icons in the second box become
enabled because you can add methods and properties to your interface definition. When you select Enum, the second group of 3
buttons changes to display the Const member, which is the only valid member for Enum type information.
The following table lists the members that can be added to elements in the object list pane:
Icon Meaning
A method of the interface, dispinterface, or an entry point in a module.
1447
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
The third group of buttons let you refresh, register, or save a type library as a TLB file, as described in Saving and registering
type library information ( see page 1465).
Icon Meaning
Refresh implementation.
See Also
Object List Pane ( see page 1448)
Descending from the type library node are the elements ( see page 1451) in the type library:
3 When you select any of these elements (including the type library itself), the pages of type information ( see page 1449) to the
right change to reflect only the relevant information for that element. You can use these pages to edit the definition and
properties of the selected element.
You can manipulate the elements in the object list pane by right clicking to get the object list pane context menu. This menu
includes commands that let you use the Windows clipboard to move or copy existing elements as well as commands to add new
elements or customize the appearance of the Type Library Editor.
1448
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
See Also
Toolbar ( see page 1447)
For example, if you specify a type that the Type Library Editor does not support, you will get a syntax error. For a complete list
of types supported by the Type Library Editor, see Valid types ( see page 1454).
See Also
Object List Pane ( see page 1448)
Uses List of other type libraries that contain definitions on which this one depends.
Flags Flags that determine how other applications can use the type library.
Text All definitions and declarations defining the type library itself (see discussion below).
Interface Attributes Name, version, and GUID for the interface, the name of the interface from which it descends, and
information linking the interface to help.
Flags Flags that indicate whether the interface is hidden, dual, Automation-compatible, and/or
extensible.
Text The definitions and declarations for the Interface (see discussion below).
Dispinterface Attributes Name, version, and GUID for the interface, and information linking it to help.
Flags Flags that indicate whether the Dispinterface is hidden, dual, and/or extensible.
Text The definitions and declarations for the Dispinterface. (see discussion below).
CoClass Attributes Name, version, and GUID for the CoClass, and information linking it to help. 3
Implements A List of interfaces that the CoClass implements, as well as their attributes.
COM+ The attributes of transactional objects, such as the transaction model, call synchronization,
just-in-time activation, object pooling, and so on. Also includes the attributes of COM+ event
objects.
Flags Flags that indicate various attributes of the CoClass, including how clients can create and use
instances, whether it is visible to users in a browser, whether it is an ActiveX control, and whether
it can be aggregated (act as part of a composite).
1449
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Text The definitions and declarations for the CoClass (see discussion below).
Enumeration Attributes Name, version, and GUID for the enumeration, and information linking it to help.
Text The definitions and declarations for the enumerated type (see discussion below).
Alias Attributes Name, version, and GUID for the enumeration, the type the alias represents, and information
linking it to help.
Text The definitions and declarations for the alias (see discussion below).
Record Attributes Name, version, and GUID for the record, and information linking it to help.
Text The definitions and declarations for the record (see discussion below).
Union Attributes Name, version, and GUID for the union, and information linking it to help.
Text The definitions and declarations for the union (see discussion below).
Module Attributes Name, version, GUID, and associated DLL for the module, and information linking it to help.
Text The definitions and declarations for the module (see discussion below).
Method Attributes Name, dispatch ID or DLL entry point, and information linking it to help.
Parameters Method return type, and a list of all parameters with their types and any modifiers.
Flags Flags to indicate how clients can view and use the method, whether this is a default method for
the interface, and whether it is replaceable.
Text The definitions and declarations for the method (see discussion below).
Property Attributes Name, dispatch ID, type of property access method (getter vs. setter), and information linking it to
help.
Parameters Property access method return type, and a list of all parameters with their types and any
modifiers.
Flags Flags to indicate how clients can view and use the property, whether this is a default for the
interface, whether the property is replaceable, bindable, and so on.
Text The definitions and declarations for the property access method (see discussion below).
Const Attributes Name, value, type (for module consts), and information linking it to help.
Flags Flags to indicate how clients can view and use the constant, whether this represents a default
value, whether the constant is bindable, and so on.
Text The definitions and declarations for the constant (see discussion below).
Field Attributes Name, type, and information linking it to help.
Flags Flags to indicate how clients can view and use the field, whether this represents a default value,
whether the field is bindable, and so on.
Text The definitions and declarations for the field (see discussion below).
You can use each of the pages of type information to view or edit the values it displays. Most of the pages organize the
information into a set of controls so that you can type in values or select them from a list without requiring that you know the
syntax of the corresponding declarations. This can prevent many small mistakes such as typographic errors when specifying
3 values from a limited set. However, you may find it faster to type in the declarations directly. To do this, use the Text page.
All type library elements have a text page that displays the syntax for the element. This syntax appears in an IDL subset of
Microsoft Interface Definition Language, or Delphi. See Using Delphi or IDL syntax ( see page 1455) for details. Any changes
you make in other pages of the element are reflected on the text page. If you add code directly in the text page, changes are
reflected in the other pages of the Type Library editor.
The Type Library Editor generates syntax errors if you add identifiers that are currently not supported by the editor; the editor
currently supports only those identifiers that relate to type library support (not RPC support or constructs used by the Microsoft
1450
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
See Also
Object List Pane ( see page 1448)
• Name, which is used to describe the element and which is used when referring to the element in code.
• GUID (globally unique identifier), which is a unique 128-bit value that COM uses to identify the element. This should always
be supplied for the type library itself and for CoClasses and interfaces. It is optional otherwise.
• Version number, which distinguishes between multiple versions of the element. This is always optional, but should be
provided for CoClasses and interfaces, because some tools can't use them without a version number.
• Help properties that link the element to a Help topic. These include a Help String, and Help Context or Help String Context
value. The Help Context is used for a traditional Windows Help system where the type library has a stand-alone Help file. The
Help String Context is used when help is supplied by a separate DLL instead. The Help Context or Help String Context refers
to a Help file or DLL that is specified on the type library's Attributes page. This is always optional.
Interfaces
An interface describes the methods (and any properties expressed as get and set functions) for an object that must be
accessed through a virtual function table (vtable). If an interface is flagged as dual, it will inherit from IDispatch, and your object
can provide both early-bound, vtable access, and runtime binding through OLE automation. By default, the type library flags all
interfaces you add as dual.
Interfaces can be assigned members: methods and properties. These appear in the object list pane as children of the interface
node. Properties for interfaces are represented by the get and set methods used to read and write the property's underlying
data. They are represented in the tree view using special icons that indicate their purpose.
Note: Write by Reference: When a property is specified as Write By Reference, it is passed as a pointer rather than by value.
Some applications, such as Visual Basic, use Write By Reference, if it is present, to optimize performance. To pass the property 3
only by reference rather than by value, use the property type By Reference Only. To pass the property by reference as well as by
value, select Read->Write->Write By Ref
. To invoke this menu, go to the toolbar and select the down-arrow next to the property icon. After you add the properties or
methods using the toolbar button or the object list pane context menu, you describe their syntax and attributes by selecting the
property or method and using the pages of type information.
The Attributes page lets you give the property or method a name and dispatch ID (so that it can be called using IDispatch). For
properties, you also assign a type. The function signature is created using the Parameters page, where you can add, remove,
1451
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
and rearrange parameters, set their type and any modifiers, and specify function return types.
Note: Members of interfaces that need to raise exceptions should return an HRESULT and specify a return value parameter
(PARAM_RETVAL) for the actual return value. Declare these methods using the safecall calling convention.
Note that when you assign properties and methods to an interface, they are implicitly assigned to its associated CoClass. This is
why the Type Library editor does not let you add properties and methods directly to a CoClass.
Dispinterfaces
Interfaces are more commonly used than dispinterfaces to describe the properties and methods of an object. Dispinterfaces are
only accessible through dynamic binding, while interfaces can have static binding through a vtable.
You can add methods and properties to dispinterfaces in the same way you add them to interfaces. However, when you create a
property for a dispinterface, you can't specify a function kind or parameter types.
CoClasses
A CoClass describes a unique COM object that implements one or more interfaces. When defining a CoClass, you must specify
which implemented interface is the default for the object, and optionally, which dispinterface is the default source for events.
Note that you do not add properties or methods to a CoClass in the Type Library editor. Properties and methods are exposed to
clients by interfaces, which are associated with the CoClass using the Implements page.
Type definitions
Enumerations, aliases, records, and unions all declare types that can then be used elsewhere in the type library.
Enums consist of a list of constants, each of which must be numeric. Numeric input is usually an integer in decimal or
hexadecimal format. The base value is zero by default. You can add constants to your enumeration by selecting the enumeration
in the object list pane and clicking the Const button on the toolbar or selecting New Const command from the object list pane
context menu.
Note: It is strongly recommended that you provide help strings for your enumerations to make their meaning clearer. The
following is a sample entry of an enumeration type for a mouse button and includes a help string for each enumeration element.
Add the fields to a record or union by selecting it in the object list pane and clicking the field button in the toolbar or right clicking
and choosing field from the object list pane context menu. Each field has a name and a type, which you assign by selecting the
field and assigning values using the Attributes page. Records and unions can be defined with an optional tag.
Members can be of any built-in type, or you can specify a type using alias before you define the record.
1452
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Modules
A module defines a group of functions, typically a set of DLL entry points. You define a module by
However, even if you are not using a wizard to define the objects, you can use the Type Library editor to define a new type
library. In this case, you must create any implementation classes yourself, because the Type Library editor does not generate
code for CoClasses that were not associated with a type library by a wizard.
The editor supports a subset of valid types ( see page 1454) in a type library
1453
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
See Also
Type Libraries ( see page 1395)
The following types are valid in a type library for COM development. The Automation compatible column specifies whether the
type can be used by an interface that has its Automation or Dispinterface flag checked. These are the types that COM can
marshal via the type library automatically.
1454
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
• Word, LongWord, SYSINT, and SYSUINT may be Automation-compatible with some applications.
See safe arrays ( see page 1455) for more information about the SAFEARRAY Variant type.
Note: The Byte (VT_UI1) is Automation-compatible, but is not allowed in a Variant or OleVariant since many Automation
servers do not handle this value correctly.
Besides these IDL types, any interfaces and types defined in the library or defined in referenced libraries can be used in a
type library definition.
The Type Library editor stores type information in the generated type library (.TLB) file in binary form.
If a parameter type is specified as a Pointer type, the Type Library editor usually translates that type into a variable parameter.
When the type library is saved, the variable parameter's associated ElemDesc's IDL flags are marked IDL_FIN or IDL_FOUT.
Often, ElemDesc IDL flags are not marked by IDL_FIN or IDL_FOUT when the type is preceded with a Pointer. Or, in the case
of dispinterfaces, IDL flags are not typically used. In these cases, you may see a comment next to the variable identifier such
as {IDL_None} or {IDL_In}. These comments are used when saving a type library to correctly mark the IDL flags.
3.2.2.6.11 SafeArrays
COM requires that arrays be passed via a special data type known as a SafeArray. You can create and destroy SafeArrays by
calling special COM functions to do so, and all elements within a SafeArray must be valid automation-compatible types ( see
page 1454). The Delphi compiler has built-in knowledge of COM SafeArrays and automatically calls the COM API to create,
copy, and destroy SafeArrays.
In the Type Library Editor, a SafeArray must specify the type of its elements. For example, the following line from the text page
declares a method with a parameter that is a SafeArray with an element type of Integer:
procedure HighLightLines(Lines: SafeArray of Integer);
HRESULT _stdcall HighlightLines(SAFEARRAY(long) Lines);
Note: Although you must specify the element type when declaring a SafeArray type in the Type Library Editor
, the declaration in the generated _TLB unit does not indicate the element type.
See Also
Valid Types ( see page 1454)
Attribute specifications
Types declared in a RIDL file may contain attributes. Attribute specifications appear enclosed in square brackets and separated
by commas. Each attribute specification consists of an attribute name followed (if appropriate) by a value.
The following table lists the attribute names and their corresponding values. 3
Attribute syntax
1455
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
1456
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
Interface syntax
The Delphi syntax for declaring interface type information has the form
interfacename = interface[(baseinterface)] [attributes]
functionlist
[propertymethodlist]
end;
For example, the following text declares an interface with two methods and one property:
Interface1 = interface (IDispatch)
[uuid '{7B5687A1-F4E9-11D1-92A8-00C04F8C8FC4}', version 1.0]
function Calculate(optional seed:Integer=0): Integer;
procedure Reset;
procedure PutRange(Range: Integer) [propput, dispid $00000005]; stdcall;
function GetRange: Integer;[propget, dispid $00000005]; stdcall;
end;
The corresponding syntax in Microsoft IDL is
[uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',version 1.0]
interface Interface1 :IDispatch
{
long Calculate([in, optional, defaultvalue(0)] long seed);
void Reset(void);
[propput, id(0x00000005)] void _stdcall PutRange([in] long Value);
[propput, id(0x00000005)] void _stdcall getRange([out, retval] long *Value);
};
Dispatch interface syntax
The Delphi syntax for declaring dispinterface type information has the form
dispinterfacename = dispinterface [attributes]
functionlist
[propertylist]
end;
For example, the following text declares a dispinterface with the same methods and property as the previous interface:
MyDispObj = dispinterface
[uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',
version 1.0,
helpstring 'dispatch interface for MyObj'
function Calculate(seed:Integer): Integer [dispid 1];
procedure Reset [dispid 2];
property Range: Integer [dispid 3];
end;
The corresponding syntax in Microsoft IDL is
[uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',
version 1.0,
helpstring "dispatch interface for MyObj" 3
dispinterface Interface1
{
methods:
[id(1)] int Calculate([in] int seed);
[id(2)] void Reset(void);
properties:
[id(3)] int Value;
};
1457
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
CoClass syntax
The Delphi syntax for declaring CoClass type information has the form
classname = coclass(interfacename[interfaceattributes], ...); [attributes];
For example, the following text declares a coclass for the interface IMyInt and dispinterface DmyInt:
myapp = coclass(IMyInt [source], DMyInt);
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
version 1.0,
helpstring 'A class',
appobject]
The corresponding syntax in Microsoft IDL is
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
version 1.0,
helpstring "A class",
appobject]
coclass myapp
{
methods:
[source] interface IMyInt);
dispinterface DMyInt;
};
Enum syntax
The Delphi syntax for declaring Enum type information has the form
enumname = ([attributes] enumlist);
For example, the following text declares an enumerated type with three values:
location = ([uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring 'location of booth']
Inside = 1 [helpstring 'Inside the pavillion'];
Outside = 2 [helpstring 'Outside the pavillion'];
Offsite = 3 [helpstring 'Not near the pavillion'];);
The corresponding syntax in Microsoft IDL is
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring "location of booth"]
typedef enum
{
[helpstring "Inside the pavillion"] Inside = 1,
[helpstring "Outside the pavillion"] Outside = 2,
[helpstring "Not near the pavillion"] Offsite = 3
} location;
Alias syntax
The Delphi syntax for declaring Alias type information has the form
aliasname = basetype[attributes];
For example, the following text declares DWORD as an alias for integer:
3 DWORD = Integer [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}'];
The corresponding syntax in Microsoft IDL is
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}'] typedef long DWORD;
Record syntax
The Delphi syntax for declaring Record type information has the form
recordname = record [attributes] fieldlist end;
1458
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
1459
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
You can also use the wizard to create a type library for an object that is not yet implemented. Once the type library contains the
interface definition, you can use the COM object wizard ( see page 1431) to generate a CoClass and implementation.
1460
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
2. In the Open dialog box, set the File Type to type library.
3. Navigate to the desired .tlb file and choose Open.
The Type Library Exploreropens in the Code Editor. You can view the type library but you cannot edit it in the Explorer.
To open a type library created with a COM wizard in the 2009 product
1. In the Project Manager, locate the .ridl file associated with your project.
2. Double-click the .ridl file.
The Type Library Editor opens in the Code Editor window.
Alternatively, you can choose View Type Library. On the Design page of the Type Library Editor, you can add interfaces,
CoClasses, and other elements of the type library such as enumerations, properties, and methods.
Note: Changes you make to any type library information with the Type Library Editor
can be automatically reflected in the associated implementation class. If you want to review the changes before they are
added, be sure that the Apply Updates ( see page 1466) dialog is checked on. It is on by default and can be changed in the
setting "Display updates before refreshing" on theTools Options Delphi Options Type Library page.
Tip: When writing client applications, you typically do not need to open the type library. You only need the Project_TLB unit
that was generated by the Import Component wizard or by TLIBIMP, not the type library itself. You can add this file directly to
a client project, or, if the type library is registered on your system, you can use the Import Type Library dialog (Component
->Import Type Library
).
See Also
Creating a New Type Library ( see page 1460)
Adding Properties and Methods to the Type Library ( see page 1462)
1461
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
• You can modify the properties and methods already in your interface by changing their type information.
• You can associate it with a CoClass by selecting the CoClass in the object list pane, right-clicking on the Implements page,
and choosing Insert Interface.
If the interface is associated with a CoClass that was generated by a wizard, you can tell the Type Library Editor to apply your
changes to the implementation file by clicking the Refresh button on the toolbar. If you have the Apply Updates ( see page
1466) dialog enabled, the Type Library Editor notifies you before updating the sources and warns you of potential problems.
For example, if you rename an event interface by mistake, you may get a warning in your source file that looks like this:
Because of the presence of instance variables in your implementation file,
Delphi was not able to update the file to reflect the change in your event
interface name. As Delphi has updated the type library for you, however, you
must update the implementation file by hand.
You also get a TODO comment in your source file immediately above it.
Warning: If you ignore this warning and TODO comment, the code will not compile.
See Also
Adding an Interface to the Type Library ( see page 1461)
Adding Properties and Methods to the Type Library ( see page 1462)
3 [
uuid(5FD36EEF-70E5-11D1-AA62-00C04FB16F42),
version(1.0),
dual,
oleautomation
]
interface Interface1: IDispatch
{ // Add everything between the curly braces
[propget, id(0x00000002)]
HRESULT _stdcall AutoSelect([out, retval] long Value );
[propget, id(0x00000003)]
1462
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
If the interface is associated with a CoClass that was generated by a wizard, you can tell the Type Library Editor to apply your
changes to the implementation file by clicking the Refresh button on the toolbar. The Type Library Editor adds new methods to
your implementation class to reflect the new members. You can then locate the new methods in implementation unit's source
code and fill in their bodies to complete the implementation.
If you have the Apply Updates ( see page 1466) dialog enabled, the Type Library Editor notifies you of all changes before
updating the sources and warns you of potential problems.
See Also
Modifying an Interface Using the Type Library ( see page 1461)
If you are not using a wizard, however, you can create a CoClass by clicking the CoClass icon on the toolbar and then specifying
its attributes. You will probably want to give the new CoClass a name (on the Attributes page), and may want to use the Flags
page to indicate information such as whether the CoClass is an application object, whether it represents an ActiveX control, and
so on.
Note: When you add a CoClass to a type library using the toolbar instead of a wizard, you must generate the implementation for
the CoClass yourself and update it by hand every time you change an element on one of the CoClass' interfaces.
You can't add members directly to a CoClass. Instead, you implicitly add members when you add an interface to the CoClass (
see page 1463).
See Also
Adding an Interface to the Type Library ( see page 1461)
To associate an interface with a CoClass, right-click in the Implements page for the class and choose Insert Interface to display
a list of interfaces from which you can choose. The list includes interfaces that are defined in the current type library and those
defined in any type libraries that the current type library references. Choose an interface you want the class to implement. The
1463
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
interface is added to the page with its GUID and other attributes.
If the CoClass was generated by a wizard, the Type Library Editor automatically updates the implementation class to include
skeletal methods for the methods (including property access methods) of any interfaces you add this way.If you have the Apply
Updates ( see page 1466) dialog enabled, the Type Library Editor notifies you before updating the sources and warns you of
potential problems.
See Also
Adding an Interface to the Type Library ( see page 1461)
1464
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
3. With the record or union selected in the object list pane, click on the field icon in the toolbar. Specify the field's name and type,
using the Attributes page.
4. Repeat step 3 for as many fields as you need.
Once you have defined the record or union, the new type is available for use by the type library or any other type library that
references it from its uses page. For example, you can use the record or union as the type for a property or parameter.
See Also
Adding an Enumeration to the Type Library ( see page 1464)
• Both the text-based type library file (.ridl extension) and the binary type library file (.tlb extension).
• The Project_TLB unit that represents its contents
• The implementation code for any CoClasses that were generated by a wizard.
Note: The type library is stored as separate text (.RIDL) and binary (.TLB) files, but is also linked into the server (.EXE, DLL,
or .OCX).
The Type Library Editor gives you toolbar buttons for storing your type library information:
• Refresh ( see page 1467) updates the type library units in memory only.
• Register ( see page 1467) adds an entry for the type library in your system's Windows registry. This is done automatically 3
when the associated server is itself registered.
• Save as TLB ( see page 1466) saves the type library as a .tlb file.
All the above methods perform syntax checking. When you refresh, register, or save the type library, Delphi automatically
updates the implementation unit of any CoClasses that were created using a wizard.
See Also
Type Library Editor Window
1465
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Without this option, the Type Library Editor automatically updates the sources of the associated object when you make
changes in the editor. With this option, you have a chance to veto the proposed changes when you attempt to refresh, save, or
register the type library.
The Apply Updates dialog will warn you about potential errors, and will insert TODO comments in your source file. For example,
if you rename an event by mistake, you will get a warning in your source file that looks like this:
Because of the presence of instance variables in your implementation file,
Delphi was not able to update the file to reflect the change in your event
interface name. As Delphi has updated the type library for you, however, you
must update the implementation file by hand.
You will also get a TODO comment in your source file immediately above it.
Note: If you ignore this warning and TODO comment, the code will not compile.
See Also
Refreshing the Type Library ( see page 1467)
• File>Save Command: To save the project and the type library, choose File Save. Saving a type library saves type
information to a .ridl file.
• Save TLB Button in Type Library Editor: To save the type library as a .tlb file, click Save as TLB in the toolbar ( see
page 1447) of the Type Library Editor. Saving as a TLB creates a binary type library file (.tlb extension) derived from the
.ridl file in your type library.
• Build Your Project or Run GenTLB: Both building your project and running GenTLB.exe also save the type library as a
.tlb file.
You might encounter unexpected messages from COM when you save a type library as a TLB file (such as when you perform a
3 project build). No syntax or validity checks are performed while you are working with the .ridl file or when you merely save
the project.
See Also
Apply Updates Dialog ( see page 1466)
1466
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications
• Updates the xxxx_TLB units that contain a Delphi or C++ representation of the Type Library.
• Notifies the IDE's module manager to update the implementation files that contain the implementation for the CoClasses, if
the type library is associated with a CoClass that was generated by a wizard.
On the Tools Options Environment Options Delphi Options Type Library or the Tools Options Environment
Options C++ Options Type Library dialog box, you can designate specific instances when the Type Library Editor is to
refresh the type library implementation. You can select from the following instances:
• When renaming the type library.
• When .ridl file is saved.
Note: If you have renamed items in the type library, refreshing the implementation may create duplicate entries. In this case,
you must move your code to the correct entry and delete any duplicates. Similarly, if you delete items in the type library,
refreshing the implementation does not remove them from CoClasses (under the assumption that you are merely removing
them from visibility to clients). You must delete these items manually in the implementation unit if they are no longer needed.
See Also
Apply Updates Dialog ( see page 1466)
Typically, you do not need to explicitly register a type library because it is registered automatically when you register your COM
server application (see Registering a COM object ( see page 1440)). However, when you create a type library using the Type
Library wizard, the type library is not associated with a server object. In this case, you can register the type library directly using
the toolbar.
Registering the type library adds an entry to the Windows registry for the type library.
See Also
Apply Updates Dialog ( see page 1466)
You can, however, deploy your application with the type library as a separate .TLB, as Delphi maintains the type library, if you
prefer.
1467
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide
Historically, type libraries for Automation applications were stored as a separate file with the .TLB extension. Now, typical
Automation applications compile the type libraries into the .OCX or .EXE file directly. The operating system expects the type
library to be the first resource in the executable (.DLL, .OCX, or .EXE) file.
When you make type libraries other than the primary project type library available to application developers, the type libraries
can be in any of the following forms:
• Stand-alone binary files. The .TLB file output by the Type Library editor is a binary file.
• A resource. This resource should have the type TYPELIB and an integer ID. If you choose to build type libraries with a
resource compiler, it must be declared in the resource (.RC) file as follows:
1 typelib mylib1.tlb
2 typelib mylib2.tlb
See Also
Deploying Applications ( see page 1947)
3.2.2.6.30 GenTLB.exe
A new type library generator (GenTLB.exe) has been added to RAD Studio. When you compile or build a project that contains a
type library, the type library generator compiles the text-based RIDL file into the binary .tlb file.
You can use GenTLB.exe in your custom builds. If you use MSBuild from the command line, then MSBuild automatically uses
GenTLB.exe.
Examples
The Type Library Editor now works on top of a .text file (the RIDL file) instead of the binary .tlb.
1468
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
• You no longer have to check in the binary .tlb file, because the build-system can generate it from the latest .RIDL file.
• Multiple programmers can work on the type library at the same time and then simply merge their changes to the text RIDL file.
[Binary files cannot be merged, requiring that the last person always overwrites previous changes.]
The RIDL format offers more flexibility for certain constructs than the Type Library Editor. For example, with a RIDL file you can
add and edit custom data on any type, function, or member. You can describe complex types such as safe arrays of safe
arrays. You can easily perform diff's of RIDL files and gain insight into the evolution of the model exposed by a server over
time.
During a build, the RIDL file is compiled using the new type library generator, GenTLB.exe, to generate the binary .tlb file.
See Also
Type Library Editor
Topics
Name Description
Working with ADO components ( see page 1470)
Connecting to databases ( see page 1495)
Creating multi-tiered applications ( see page 1510)
Creating reports with Rave Reports ( see page 1551)
Designing database applications ( see page 1556)
Understanding datasets ( see page 1573)
Using the Borland Database Engine ( see page 1637) The Borland Database Engine (BDE) has been deprecated, so it will not be
enhanced. For instance, BDE will never have Unicode support. You should not
undertake new development with BDE. Consider migrating your existing
database applications from BDE to dbExpress.
Using client datasets ( see page 1700)
Using data controls ( see page 1743)
Using decision support components ( see page 1779)
Using provider components ( see page 1805)
Using dbExpress Components ( see page 1821)
3
Using XML in database applications ( see page 1840)
Working with field components ( see page 1849)
1469
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
1470
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Controlling Timeouts ( see page 1480) You can control the amount of time that can elapse before attempted commands
and connections are considered failed and are aborted using the
ConnectionTimeout and CommandTimeout properties.
ConnectionTimeout specifies the amount of time, in seconds, before an attempt
to connect to the data store times out. If the connection does not successfully
compile prior to expiration of the time specified in ConnectionTimeout, the
connection attempt is canceled:
Fetching Records Asynchronously ( see page 1481) Unlike other datasets, ADO datasets can fetch their data asynchronously. This
allows your application to continue performing other tasks while the dataset
populates itself with data from the data store.
To control whether the dataset fetches data asynchronously, if it fetches data at
all, use the ExecuteOptions property. ExecuteOptions governs how the dataset
fetches its records when you call Open or set Active to True. If the dataset
represents a query or stored procedure that does not return any records,
ExecuteOptions governs how the query or stored procedure is executed when
you call ExecSQL or ExecProc.
ExecuteOptions is... more ( see page 1481)
Filtering Multiple Rows Based On Update Status ( see page 1481) Filter a recordset to show only those rows that belong to a group of rows with the
same update status using the FilterGroup property. Set FilterGroup to the
TFilterGroup constant that represents the update status of rows to display. A
value of fgNone (the default value for this property) specifies that no filtering is
applied and all rows are visible regardless of update status (except rows marked
for deletion). The example below causes only pending batch update rows to be
visible.
Filtering Records Based On Bookmarks ( see page 1482) ADO datasets support the common dataset feature of using bookmarks to mark
and return to specific records ( see page 1599). Also like other datasets, ADO
datasets let you use filters to limit the available records in the dataset ( see
page 1631). ADO datasets provide an additional feature that combines these two
common dataset features: the ability to filter on a set of records identified by
bookmarks.
Fine-tuning a Connection ( see page 1483) One advantage of using TADOConnection for establishing the connection to a
data store instead of simply supplying a connection string for your ADO
command and dataset components, is that it provides a greater degree of control
over the conditions and attributes of the connection.
The following topics describe the properties you can use to fine-tune the
connection:
1471
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Handling Command Parameters ( see page 1484) There are two ways in which a TADOCommand object may use parameters:
1472
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Retrieving Result Sets with Commands ( see page 1488) Unlike TADOQuery components, which use different methods to execute
depending on whether they return a result set, TADOCommand always uses the
Execute command to execute the command, regardless of whether it returns a
result set. When the command returns a result set, Execute returns an interface
to the ADO _RecordSet interface.
The most convenient way to work with this interface is to assign it to the
RecordSet property of an ADO dataset.
For example, the following code uses TADOCommand (ADOCommand1) to
execute a SELECT query, which returns a result set. This result set is then
assigned to the... more ( see page 1488)
Specifying the Command ( see page 1489) Specify commands for a TADOCommand component using the CommandText
property. Like TADODataSet, TADOCommand lets you specify the command in
different ways, depending on the CommandType property. Possible values for
CommandType include: cmdText (used if the command is an SQL statement),
cmdTable (if it is a table name), and cmdStoredProc (if the command is the name
of a stored procedure). At design-time, select the appropriate command type
from the list in the Object Inspector. At runtime, assign a value of type
TCommandType to the CommandType property.
Specifying Whether the Connection Automatically Initiates Transactions ( see Use the Attributes property to control the connection component's use of
page 1489) retaining commits and retaining aborts. When the connection component uses
retaining commits, then every time your application commits a transaction, a new
transaction is automatically started. When the connection component uses
retaining aborts, then every time your application rolls back a transaction, a new
transaction is automatically started.
Attributes is a set that can contain one, both, or neither of the constants
xaCommitRetaining and xaAbortRetaining. When Attributes contains
xaCommitRetaining, the connection uses retaining commits. When Attributes
contains xaAbortRetaining, it uses retaining aborts.
Check whether either retaining... more ( see page 1489)
Using ADO datasets ( see page 1490) ADO dataset components encapsulate the ADO Recordset object. They inherit
the common dataset capabilities described in Understanding Datasets ( see
page 1632), using ADO to provide the implementation. In order to use an ADO
dataset, you must familiarize yourself with these common features.
In addition to the common dataset features, all ADO datasets add properties,
events, and methods for the following:
1473
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Using TADODataSet ( see page 1492) TADODataSet is a general-purpose dataset ( see page 1632) for working with
data from an ADO data store. Unlike the other ADO dataset components,
TADODataSet is not a table-type ( see page 1620), query-type ( see page
1618), or stored procedure-type ( see page 1618) dataset. Instead, it can
function as any of these types:
• OnWillConnect occurs before the ADO provider establishes a connection. It lets you make last minute changes to the
3 connection string, provide a user name and password if you are handling your own login support, force an asynchronous
connection, or even cancel the connection before it is opened.
• OnConnectComplete occurs after the connection is opened. Because TADOConnection can represent asynchronous
connections, you should use OnConnectComplete, which occurs after the connection is opened or has failed due to an error
condition, instead of the AfterConnect event, which occurs after the connection component instructs the ADO provider to open
a connection, but not necessarily after the connection is opened.
Events when disconnecting
In addition to the BeforeDisconnect and AfterDisconnect events common to all database connection components,
1474
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
TADOConnection also generates an OnDisconnect event after closing a connection. OnDisconnect occurs after the connection
is closed but before any associated datasets are closed and before the AfterDisconnect event.
• The OnBeginTransComplete event occurs when the data store has successfully started a transaction after a call to the
BeginTrans method.
• The OnCommitTransComplete event occurs after a transaction is successfully committed due to a call to CommitTrans.
• The OnRollbackTransComplete event occurs after a transaction is successfully aborted due to a call to RollbackTrans.
Other events
ADO connection components introduce two additional events you can use to respond to notifications from the underlying ADO
connection object:
• The OnExecuteComplete event occurs after the connection component executes a command on the data store (for example,
after calling the Execute method). OnExecuteComplete indicates whether the execution was successful.
• The OnInfoMessage event occurs when the underlying connection object provides detailed information after an operation is
completed. The OnInfoMessage event handler receives the interface to an ADO Error object that contains the detailed
information and a status code indicating whether the operation was successful.
See Also
Connecting to Databases ( see page 1506)
Using the underlying ADO Connection object requires a good working knowledge of ADO objects in general and the ADO
Connection object in particular. It is not recommended that you use the Connection object unless you are familiar with
Connection object operations. Consult the Microsoft Data Access SDK help for specific information on using ADO Connection
objects.
Commands is a zero-based array of references to ADO command components. CommandCount provides a total count of all of
the commands listed in Commands. You can use these properties together to iterate through all the commands that use a
1475
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Used alone with no parameter, UpdateBatch applies all pending updates. A TAffectRecords value can optionally be passed as
the parameter for UpdateBatch. If any value except arAll is passed, only a subset of the pending changes are applied. Passing
arAll is the same as passing no parameter at all and causes all pending updates to be applied. The example below applies only
the currently active row to be applied:
ADODataSet1.UpdateBatch(arCurrent);
ADODataSet1->UpdateBatch(arCurrent);
See Also
Opening the Dataset in Batch Update Mode ( see page 1487)
Used alone with no parameter, CancelBatch cancels all pending updates. A TAffectRecords value can optionally be passed as
the parameter for CancelBatch. If any value except arAll is passed, only a subset of the pending changes are canceled. Passing
arAll is the same as passing no parameter at all and causes all pending updates to be canceled. The example below cancels all
pending changes:
ADODataSet1.CancelBatch;
ADODataSet1->CancelBatch(arAll);
1476
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
See Also
Opening the Dataset in Batch Update Mode ( see page 1487)
A command times out if it is not completed or canceled before the number of seconds specified in the CommandTimeout
property expire. By default, commands time out after 30 seconds.
See Also
Specifying the Command ( see page 1489)
An ADO provider represents one of a number of types of access, from native OLE DB drivers to ODBC drivers. These drivers
must be installed on the client computer. OLE DB drivers for various database systems are supplied by the database vendor or
by a third-party. If the application uses an SQL database, such as Microsoft SQL Server or Oracle, the client software for that
database system must also be installed on the client computer. Client software is supplied by the database vendor and installed
from the database systems CD (or disk).
1477
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
To connect your application with the data store ( see page 1478), use an ADO connection component (TADOConnection).
Configure the ADO connection component to use one of the available ADO providers. Although TADOConnection is not strictly
required, because ADO command and dataset components can establish connections directly using their ConnectionString
property, you can use TADOConnection to share a single connection among several ADO components. This can reduce
resource consumption, and allows you to create transactions that span multiple datasets.
Like other database connection components ( see page 1506), TADOConnection provides support for
Parameter Description
Provider The name of a local ADO provider to use for the connection.
Data Source The name of the data store.
File name The name of a file containing connection information.
1478
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Remote Provider The name of an ADO provider that resides on a remote machine.
Remote Server The name of the remote server when using a remote provider.
In addition, to the parameters listed above, ConnectionString can include any connection parameters peculiar to the specific
ADO provider you are using. These additional connection parameters can include user ID and password if you want to hardcode
the login information.
At design-time, you can use the Connection String Editor to build a connection string by selecting connection elements (like the
provider and server) from lists. Click the ellipsis button for the ConnectionString property in the Object Inspector to launch the
Connection String Editor, which is an ActiveX property editor supplied by ADO.
Once you have specified the ConnectionString property (and, optionally, the Provider property), you can use the ADO connection
component to connect to ( see page 1509) or disconnect from ( see page 1497) the ADO data store, although you may first
want to use other properties to fine-tune the connection ( see page 1483). When connecting to or disconnecting from the data
store, TADOConnection lets you respond to a few additional events ( see page 1474) beyond those common to all database
connection components..
Note: If you do not explicitly activate the connection by setting the connection component's Connected property to True, it
automatically establishes the connection when the first dataset component is opened or the first time you use an ADO command
component to execute a command.
See Also
Connection
Connection
Connection
Connection
Connection
When connecting datasets collectively, set the Connection property of each dataset to a TADOConnection component. Each
dataset then uses the ADO connection component's connection.
ADODataSet1.Connection := ADOConnection1;
ADODataSet2.Connection := ADOConnection1;
...
ADODataSet1->Connection = ADOConnection1;
1479
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
ADODataSet2->Connection = ADOConnection1;
...
Among the advantages of connecting datasets collectively are:
See Also
Filtering Records Based On Bookmarks ( see page 1482)
Loading Data from and Saving Data to Files ( see page 1486)
ConnectionTimeout specifies the amount of time, in seconds, before an attempt to connect to the data store times out. If the
connection does not successfully compile prior to expiration of the time specified in ConnectionTimeout, the connection attempt
is canceled:
with ADOConnection1 do begin
ConnectionTimeout := 10 {seconds};
Open;
end;
3 ADOConnection1->ConnectionTimeout = 10; // seconds
ADOConnection1->Open();
CommandTimeout specifies the amount of time, in seconds, before an attempted command times out. If a command initiated by
a call to the Execute method does not successfully complete prior to expiration of the time specified in CommandTimeout, the
command is canceled and ADO generates an exception:
with ADOConnection1 do begin
CommandTimeout := 10 {seconds};
Execute("DROP TABLE Employee1997", cmdText, []);
1480
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
end;
ADOConnection1->ConnectionTimeout = 10;
ADOConnection1->Execute("DROP TABLE Employee1997", cmdText, TExecuteOptions());
See Also
Specifying Whether the Connection Automatically Initiates Transactions ( see page 1489)
Indicating the Types of Operations the Connection Supports ( see page 1485)
To control whether the dataset fetches data asynchronously, if it fetches data at all, use the ExecuteOptions property.
ExecuteOptions governs how the dataset fetches its records when you call Open or set Active to True. If the dataset represents
a query or stored procedure that does not return any records, ExecuteOptions governs how the query or stored procedure is
executed when you call ExecSQL or ExecProc.
See Also
Connecting an ADO Dataset to a Data Store ( see page 1479)
Loading Data from and Saving Data to Files ( see page 1486)
1481
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
See Also
Opening the Dataset in Batch Update Mode ( see page 1487)
See Also
3
Connecting an ADO Dataset to a Data Store ( see page 1479)
Loading Data from and Saving Data to Files ( see page 1486)
1482
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
The following topics describe the properties you can use to fine-tune the connection:
By default, ConnectionOptions is set to coConnectUnspecified which allows the server to decide the best type of connection. To
explicitly make the connection asynchronous, set ConnectOptions to coAsyncConnect.
The example routines below enable and disable asynchronous connections in the specified connection component:
procedure TForm1.AsyncConnectButtonClick(Sender: TObject);
begin
with ADOConnection1 do begin
Close;
ConnectOptions := coAsyncConnect;
Open;
end;
end;
procedure TForm1.ServerChoiceConnectButtonClick(Sender: TObject);
begin
with ADOConnection1 do begin
Close;
ConnectOptions := coConnectUnspecified;
Open;
end;
end;
void __fastcall TForm1::AsyncConnectButtonClick(TObject *Sender)
{ 3
ADOConnection1->Close();
ADOConnection1->ConnectOptions = coAsyncConnect;
ADOConnection1->Open();
}
void __fastcall TForm1::ServerChoiceConnectButtonClick(TObject *Sender)
{
ADOConnection1->Close();
ADOConnection1->ConnectOptions = coConnectUnspecified;
ADOConnection1->Open();
}
1483
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
See Also
Controlling Timeouts ( see page 1480)
Specifying Whether the Connection Automatically Initiates Transactions ( see page 1489)
Indicating the Types of Operations the Connection Supports ( see page 1485)
• The CommandText property can specify a query that includes parameters. Working with parameterized queries in
TADOCommand works like using a parameterized query ( see page 1617) in an ADO dataset.
• The CommandText property can specify a stored procedure that uses parameters. Stored procedure parameters ( see page
1625) work much the same using TADOCommand as with an ADO dataset.
There are two ways to supply parameter values when working with TADOCommand: you can supply them when you call the
Execute method, or you can specify them ahead of time using the Parameters property.
The Execute method is overloaded to include versions that take a set of parameter values as a Variant array. This is useful when
you want to supply parameter values quickly without the overhead of setting up the Parameters property:
ADOCommand1.Execute(VarArrayOf([Edit1.Text, Date]));
Variant Values[2];
Values[0] = Edit1->Text;
Values[1] = Date();
ADOCommand1.Execute(VarArrayOf(Values,1));
When working with stored procedures that return output parameters, you must use the Parameters property instead. Even if you
do not need to read output parameters, you may prefer to use the Parameters property, which lets you supply parameters at
design time and lets you work with TADOCommand properties in the same way you work with the parameters on datasets.
When you set the CommandText property, the Parameters property is automatically updated to reflect the parameters in the
query or those used by the stored procedure. At design-time, you can use the Parameter Editor to access parameters, by
clicking the ellipsis button for the Parameters property in the Object Inspector. At runtime, use properties and methods of
TParameter to set (or get) the values of each parameter.
with ADOCommand1 do begin
CommandText := 'INSERT INTO Talley ' +
'(Counter) ' +
'VALUES (:NewValueParam)';
CommandType := cmdText;
Parameters.ParamByName("NewValueParam").Value := 57;
Execute
end;
ADOCommand1->CommandText = "INSERT INTO Talley ";
ADOCommand1->CommandText += "(Counter) ";
ADOCommand1->CommandText += "VALUES (:NewValueParam)";
ADOCommand1->CommandType = cmdText;
ADOCommand1->Parameters->ParamByName("NewValueParam")->Value = 57;
ADOCommand1->Execute()
3 See Also
Specifying the Command ( see page 1489)
1484
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Use the Mode property to indicate the connection mode. The possible values are listed in the following table:
The possible values for Mode correspond to the ConnectModeEnum values of the Mode property on the underlying ADO
connection object. See the Microsoft Data Access SDK help for more information on these values.
See Also
Specifying Whether the Connection Automatically Initiates Transactions ( see page 1489)
1485
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
break;
}
See Also
Opening the Dataset in Batch Update Mode ( see page 1487)
Save the data to a file using the SaveToFile method. SaveToFile takes two parameters, the name of the file to which data is
saved, and, optionally, the format (ADTG or XML) in which to save the data. Indicate the format for the saved file by setting the
Format parameter to pfADTG or pfXML. If the file specified by the FileName parameter already exists, SaveToFile raises an
EOleException.
Retrieve the data from file using the LoadFromFile method. LoadFromFile takes a single parameter, the name of the file to load.
If the specified file does not exist, LoadFromFile raises an EOleException exception. On calling the LoadFromFile method, the
dataset component is automatically activated.
In the example below, the first procedure saves the dataset retrieved by the TADODataSet component ADODataSet1 to a file.
The target file is an ADTG file named SaveFile, saved to a local drive. The second procedure loads this saved file into the
TADODataSet component ADODataSet2.
procedure TForm1.SaveBtnClick(Sender: TObject);
begin
if (FileExists("c:\SaveFile")) then
begin
DeleteFile("c:\SaveFile");
StatusBar1.Panels[0].Text := "Save file deleted!";
end;
ADODataSet1.SaveToFile("c:\SaveFile", pfADTG);
end;
procedure TForm1.LoadBtnClick(Sender: TObject);
begin
if (FileExists("c:\SaveFile")) then
ADODataSet2.LoadFromFile("c:\SaveFile")
else
StatusBar1.Panels[0].Text := "Save file does not exist!";
end;
void __fastcall TForm1::SaveBtnClick(TObject *Sender)
{
if (FileExists("c:\\SaveFile"))
3 {
DeleteFile("c:\\SaveFile");
Statusbar1->Panels->Items[0]->Text = "Save file deleted!";
}
ADODataSet1->SaveToFile("c:\\SaveFile");
}
void __fastcall TForm1::LoadBtnClick(TObject *Sender)
{
if (FileExists("c:\\SaveFile"))
ADODataSet1->LoadFromFile("c:\\SaveFile");
else
1486
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
See Also
Connecting an ADO Dataset to a Data Store ( see page 1479)
1. The component's CursorType property must be ctKeySet (the default property value) or ctStatic.
2. The LockType property must be ltBatchOptimistic.
3. The command must be a SELECT query.
Before activating the dataset component, set the CursorType and LockType properties as indicated above. Assign a SELECT
statement to the component's CommandText property (for TADODataSet) or the SQL property (for TADOQuery). For
TADOStoredProc components, set the ProcedureName to the name of a stored procedure that returns a result set. These
properties can be set at design-time through the Object Inspector or programmatically at runtime. The example below shows
the preparation of a TADODataSet component for batch update mode.
with ADODataSet1 do begin
CursorLocation := clUseClient;
CursorType := ctStatic;
LockType := ltBatchOptimistic;
CommandType := cmdText;
CommandText := 'SELECT * FROM Employee';
Open;
end;
ADODataSet1->CursorLocation = clUseClient;
ADODataSet1->CursorType = ctStatic;
ADODataSet1->LockType = ltBatchOptimistic;
ADODataSet1->CommandType = cmdText;
ADODataSet1->CommandText = "SELECT * FROM Employee";
After a dataset has been opened in batch update mode, all changes to the data are cached rather than applied directly to the
base tables.
See Also
Inspecting the Update Status of Individual Rows ( see page 1485)
1487
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
be installed on the host computer. Additionally, client software for the target database system (such as Microsoft SQL Server)
must be installed, as well as an OLE DB driver or ODBC driver specific to the particular database system.
Most dbGo components have direct counterparts in the components available for other data access mechanisms: a database
connection component (TADOConnection) and various types of datasets. In addition, dbGo includes TADOCommand, a simple
component that is not a dataset but which represents an SQL command to be executed on the ADO data store.
ADO components
Component Use
TADOConnection A database connection component ( see page 1506) that establishes a connection with an ADO data
store; multiple ADO dataset and command components can share this connection to execute commands,
retrieve data, and operate on metadata.
TADODataSet The primary dataset ( see page 1632) for retrieving and operating on data; TADODataSet can retrieve
data from a single or multiple tables; can connect directly to a data store or use a TADOConnection
component.
TADOTable A table-type dataset ( see page 1620) for retrieving and operating on a recordset produced by a single
database table; TADOTable can connect directly to a data store or use a TADOConnection component.
TADOQuery A query-type dataset ( see page 1618) for retrieving and operating on a recordset produced by a valid
SQL statement; TADOQuery can also execute data definition language (DDL) SQL statements. It can
connect directly to a data store or use a TADOConnection component
TADOStoredProc A stored procedure-type dataset ( see page 1618) for executing stored procedures; TADOStoredProc
executes stored procedures that may or may not retrieve data. It can connect directly to a data store or use
a TADOConnection component.
TADOCommand A simple component for executing commands (SQL statements that do not return result sets);
TADOCommand can be used with a supporting dataset component, or retrieve a dataset from a table; It
can connect directly to a data store or use a TADOConnection component.
The most convenient way to work with this interface is to assign it to the RecordSet property of an ADO dataset.
For example, the following code uses TADOCommand (ADOCommand1) to execute a SELECT query, which returns a result
set. This result set is then assigned to the RecordSet property of a TADODataSet component (ADODataSet1).
with ADOCommand1 do begin
CommandText := 'SELECT Company, State ' +
'FROM customer ' +
'WHERE State = :StateParam';
CommandType := cmdText;
3 Parameters.ParamByName('StateParam').Value := 'HI';
ADODataSet1.Recordset := Execute;
end;
ADOCommand1->CommandText = "SELECT Company, State ";
ADOCommand1->CommandText += "FROM customer ";
ADOCommand1->CommandText += "WHERE State = :StateParam";
ADOCommand1->CommandType = cmdText;
ADOCommand1->Parameters->ParamByName("StateParam")->Value = "HI";
ADOCommand1->Recordset = ADOCommand1->Execute();
As soon as the result set is assigned to the ADO dataset's Recordset property, the dataset is automatically activated and the
1488
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
data is available.
See Also
Specifying the Command ( see page 1489)
CommandText can contain the text of an SQL query that includes parameters or the name of a stored procedure that uses
parameters. You must then supply parameter values, which are bound to the parameters before executing the command. See
Handling command parameters ( see page 1484) for details.
See Also
Using the Execute Method ( see page 1493)
Attributes is a set that can contain one, both, or neither of the constants xaCommitRetaining and xaAbortRetaining. When
Attributes contains xaCommitRetaining, the connection uses retaining commits. When Attributes contains xaAbortRetaining, it
uses retaining aborts.
Check whether either retaining commits or retaining aborts is enabled using the in operator. Enable retaining commits or aborts
by adding the appropriate value to the attributes property; disable them by subtracting the value. The example routines below
respectively enable and disable retaining commits in an ADO connection component.
1489
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Indicating the Types of Operations the Connection Supports ( see page 1485)
Indicating the Types of Operations the Connection Supports ( see page 1485)
In addition to the common dataset features, all ADO datasets add properties, events, and methods for the following:
1490
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
• TADOStoredProc, a stored procedure-type dataset ( see page 1618) that executes a stored procedure defined on a
database server.
• TADODataSet, a general-purpose dataset that includes the capabilities of the other three types. See Using TADODataSet (
see page 1492) for a description of features unique to TADODataSet.
Note: When using ADO to access database information, you do not need to use a dataset such as TADOQuery to represent
SQL commands that do not return a cursor. Instead, you can use TADOCommand, a simple component that is not a dataset.
For details on TADOCommand, see Using Command Objects ( see page 1492).
See Also
Using Command Objects ( see page 1492)
However, ADO dataset components provide their own support for cached updates, which they call batch updates. The following
table lists the correspondences between caching updates using a client dataset and using the batch updates features:
LockType Not used: client Specifies whether the dataset is opened in batch update mode.
datasets always
cache updates
CursorType Not used: client Specifies how isolated the ADO dataset is from changes on the server.
datasets always work
with an in-memory
snapshot of data
RecordStatus UpdateStatus Indicates what update, if any, has occurred on the current row. RecordStatus provides
more information than UpdateStatus.
FilterGroup StatusFilter Specifies which type of records are available. FilterGroup provides a wider variety of
information.
UpdateBatch ApplyUpdates Applies the cached updates back to the database server. Unlike ApplyUpdates,
UpdateBatch lets you limit the types of updates to be applied.
CancelBatch CancelUpdates Discards pending updates, reverting to the original values. Unlike CancelUpdates,
CancelBatch lets you limit the types of updates to be canceled.
Using the batch updates features of ADO dataset components is a matter of:
1491
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Loading Data from and Saving Data to Files ( see page 1486)
Although you can always execute commands using TADOQuery, you may not want the overhead of using a dataset component,
especially if the command does not return a result set. As an alternative, you can use the TADOCommand component, which is
a lighter-weight object designed to execute commands, one command at a time. TADOCommand is intended primarily for
executing those commands that do not return result sets, such as Data Definition Language (DDL) SQL statements. Through an
overloaded version of its Execute method, however, it is capable of returning a result set that can be assigned to the RecordSet
property of an ADO dataset component.
In general, working with TADOCommand is very similar to working with TADODataSet, except that you can't use the standard
dataset methods to fetch data, navigate records, edit data, and so on. TADOCommand objects connect to a data store in the
same way as ADO datasets. See Connecting an ADO dataset to a data store ( see page 1479) for details.
The following topics provide details on how to specify and execute commands using TADOCommand:
• Like a table-type dataset, TADODataSet lets you represent all of the rows and columns of a single database table. To use it in
this way, set the CommandType property to cmdTable and the CommandText property to the name of the table.
3 TADODataSet supports table-type tasks such as
• Assigning indexes ( see page 1609) to sort records or form the basis of record-based searches. In addition to the standard
index properties and methods, TADODataSet lets you sort using temporary indexes by setting the Sort property.
Indexed-based searches performed using the Seek method use the current index.
• Emptying the dataset ( see page 1592). The DeleteRecordsDeleteRecords method provides greater control than related
methods in other table-type datasets, because it lets you specify what records to delete.
The table-type tasks supported by TADODataSet are available even when you are not using a CommandType of cmdTable.
• Like a query-type dataset, TADODataSet lets you specify a single SQL command that is executed when you open the
1492
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
dataset. To use it in this way, set the CommandType property to cmdText and the CommandText property to the SQL
command you want to execute. At design time, you can double-click on the CommandText property in the Object Inspector
to use the Command Text editor for help in constructing the SQL command. TADODataSet supports query-type tasks such as
• Using parameters in the query text ( see page 1617).
• Setting up master/detail relationships using parameters ( see page 1593).
• Preparing the query in advance to improve performance by setting the Prepared property to True.
• Like a stored procedure-type dataset, TADODataSet lets you specify a stored procedure that is executed when you open the
dataset. To use it in this way, set the CommandType property to cmdStoredProc and the CommandText property to the name
of the stored procedure. TADODataSet supports stored procedure-type tasks such as
• Working with stored procedure parameters ( see page 1625).
• Fetching multiple result sets ( see page 1597).
• Preparing the stored procedure in advance to improve performance by setting the Prepared property to True.
In addition, TADODataSet lets you work with data stored in files by setting the CommandType property to cmdFile and the
CommandText property to the file name.
Before you set the CommandText and CommandType properties, you should link the TADODataSet to a data store by setting
the Connection or ConnectionString property. This process is described in Connecting an ADO dataset to a data store ( see
page 1479). As an alternative, you can use an RDS DataSpace object to connect the TADODataSet to an ADO-based
application server. To use an RDS DataSpace object, set the RDSConnection property to a TRDSConnection object.
See Also
Understanding Datasets ( see page 1632)
Using TADODataSet
To execute the command, call the Execute method. Execute is an overloaded method that lets you choose the most appropriate
way to execute the command.
For commands that do not require any parameters and for which you do not need to know how many records were affected, call
Execute without any parameters:
with ADOCommand1 do begin
CommandText := "UpdateInventory";
CommandType := cmdStoredProc;
Execute;
end;
ADOCommand1->CommandText = "UpdateInventory";
ADOCommand1->CommandType = cmdStoredProc;
ADOCommand1->Execute();
Other versions of Execute let you provide parameter values using a Variant array, and to obtain the number of records affected
by the command.
3
For information on executing commands that return a result set, see Retrieving result sets with commands ( see page 1488).
See Also
Specifying the Command ( see page 1489)
1493
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
The ADO layer of an ADO-based application consists of Microsoft ADO 2.1, an OLE DB provider or ODBC driver for the data
store access, client software for the specific database system used (in the case of SQL databases), a database back-end system
accessible to the application (for SQL database systems), and a database. All of these must be accessible to the ADO-based
application for it to be fully functional.
The ADO objects that figure most prominently are the Connection, Command, and Recordset objects. These ADO objects are
wrapped by the TADOConnection, TADOCommand, and ADO dataset components. The ADO framework includes other "helper"
objects, like the Field and Properties objects, but these are typically not used directly in dbGo applications and are not wrapped
by dedicated components.
Before reading about the features peculiar to the dbGo components, you should familiarize yourself with the common features of
database connection components ( see page 1506) and datasets ( see page 1632).
The following topics describe the unique features of dbGo components and how to work with them:
1494
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
access the underlying ADO recordset object requires a good working knowledge of ADO objects in general and the ADO
recordset object in specific. Using the recordset object directly is not recommended unless you are familiar with recordset object
operations. Consult the Microsoft Data Access SDK help for specific information on using ADO recordset objects.
The RecordSetState property indicates the current state of the underlying recordset object. RecordsetState corresponds to the
State property of the ADO recordset object. The value of RecordsetState is either stOpen, stExecuting, or stFetching.
(TObjectState, the type of the RecordsetState property, defines other values, but only stOpen, stExecuting, and stFetching
pertain to recordsets.) A value of stOpen indicates that the recordset is currently idle. A value of stExecuting indicates that it is
executing a command. A value of stFetching indicates that it is fetching rows from the associated table (or tables).
Use RecordsetState values to perform actions dependent on the current state of the dataset. For example, a routine that updates
data might check the RecordsetState property to see whether the dataset is active and not in the process of other activities such
as connecting or fetching data.
See Also
Connecting an ADO Dataset to a Data Store ( see page 1479)
Loading Data from and Saving Data to Files ( see page 1486)
1495
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Managing Transactions ( see page 1498) A transaction is a group of actions that must all be carried out successfully on
one or more tables in a database before they are committed (made permanent).
If one of the actions in the group fails, then all actions are rolled back (undone).
By using transactions, you ensure that the database is not left in an inconsistent
state when a problem occurs completing one of the actions that make up the
transaction.
For example, in a banking application, transferring funds from one account to
another is an operation you would want to protect with a transaction. If, after
decrementing... more ( see page 1498)
Obtaining Metadata ( see page 1501) All database connection components can retrieve lists of metadata on the
database server, although they vary in the types of metadata they retrieve. The
methods that retrieve metadata fill a string list with the names of various entities
available on the server. You can then use this information, for example, to let
your users dynamically select a table at runtime.
You can use a TADOConnection component to retrieve metadata about the
tables and stored procedures available on the ADO data store. You can then use
this information, for example, to let your users dynamically select a table or
stored procedure... more ( see page 1501)
Sending Commands to the Server ( see page 1502) All database connection components except TIBDatabase let you execute SQL
statements on the associated server by calling the Execute method. Although
Execute can return a cursor when the statement is a SELECT statement, this use
is not recommended. The preferred method for executing statements that return
data is to use a dataset.
The Execute method is very convenient for executing simple SQL statements
that do not return any records. Such statements include Data Definition
Language (DDL) statements, which operate on or create a database's metadata,
such as CREATE INDEX, ALTER TABLE, and DROP DOMAIN. Some Data
Manipulation Language (DML) SQL... more ( see page 1502)
Specifying the Transaction Isolation Level ( see page 1504) Transaction isolation level determines how a transaction interacts with other
simultaneous transactions when they work with the same tables. In particular, it
affects how much a transaction "sees" of other transactions' changes to a table.
Each server type supports a different set of possible transaction isolation levels.
There are three possible transaction isolation levels:
1496
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Controlling Server Login ( see page 1507) Most remote database servers include security features to prohibit unauthorized
access. Usually, the server requires a user name and password login before
permitting database access.
At design time, if a server requires a login, a standard login dialog box prompts
for a user name and password when you first attempt to connect to the database.
At runtime, there are three ways you can handle a server's request for a login:
The first way is to let the default login dialog and processes handle the login. This
is the default approach. Set the LoginPrompt property of the connection
component to True... more ( see page 1507)
Connecting to a Database Server ( see page 1509) There are two ways to connect to a database server using a connection
component:
Once you have identified the desired server and any connection parameters, you can use the connection component to explicitly
open or close a connection. The connection component generates events when it opens or closes a connection that you can use
to customize the response of your application to changes in the database connection.
The following topics provide details about opening and closing database connections:
1497
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
For example, in a banking application, transferring funds from one account to another is an operation you would want to protect
with a transaction. If, after decrementing the balance in one account, an error occurred incrementing the balance in the other,
you want to roll back the transaction so that the database still reflects the correct total balance.
It is always possible to manage transactions by sending SQL commands directly to the database ( see page 1502). Most
databases provide their own transaction management model, although some have no transaction support at all. For servers that
support it, you may want to code your own transaction management directly, taking advantage of advanced transaction
management capabilities on a particular database server, such as schema caching.
If you do not need to use any advanced transaction management capabilities, connection components provide a set of methods
and properties you can use to manage transactions without explicitly sending any SQL commands. Using these properties and
methods has the advantage that you do not need to customize your application for each type of database server you use, as
long as the server supports transactions. (The BDE also provides limited transaction support for local tables with no server
transaction support. When not using the BDE, trying to start transactions on a database that does not support them causes
connection components to raise an exception.)
Warning: When a dataset provider component applies updates, it implicitly generates transactions for any updates. Be careful
that any transactions you explicitly start do not conflict with those generated by the provider.
Starting a transaction
When you start a transaction, all subsequent statements that read from or write to the database occur in the context of that
transaction, until the transaction is explicitly terminated or (in the case of overlapping transactions) until another transaction is
3 started. Each statement is considered part of a group. Changes must be successfully committed to the database, or every
change made in the group must be undone.
While the transaction is in process, your view of the data in database tables is determined by your transaction isolation level (
see page 1504).
1498
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
BeginTrans returns the level of nesting for the transaction that started. A nested transaction is one that is nested within another,
parent, transaction. After the server starts the transaction, the ADO connection receives an OnBeginTransComplete event.
For TDatabase, use the StartTransaction method instead. TDataBase does not support nested or overlapped transactions: If you
call a TDatabase component's StartTransaction method while another transaction is underway, it raises an exception. To avoid
calling StartTransaction, you can check the InTransaction property:
if not Database1.InTransaction then
Database1.StartTransaction;
if (!Database1->InTransaction)
Database1->StartTransaction();
TSQLConnection also uses the StartTransaction method, but it uses a version that gives you a lot more control. Specifically,
StartTransaction takes a transaction descriptor, which lets you manage multiple simultaneous transactions and specify the
transaction isolation level ( see page 1504) on a per-transaction basis. In order to manage multiple simultaneous transactions,
set the TransactionID field of the transaction descriptor to a unique value. TransactionID can be any value you choose, as long
as it is unique (does not conflict with any other transaction currently underway). Depending on the server, transactions started by
TSQLConnection can be nested (as they can be when using ADO) or they can be overlapped.
var
TD: TTransactionDesc;
begin
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
SQLConnection1.StartTransaction(TD);
TTransactionDesc TD;
TD.TransactionID = 1;
TD.IsolationLevel = xilREADCOMMITTED;
SQLConnection1->StartTransaction(TD);
By default, with overlapped transactions, the first transaction becomes inactive when the second transaction starts, although you
can postpone committing or rolling back the first transaction until later. If you are using TSQLConnection with an InterBase
database, you can identify each dataset in your application with a particular active transaction, by setting its TransactionLevel
property. That is, after starting a second transaction, you can continue to work with both transactions simultaneously, simply by
associating a dataset with the transaction you want.
Note: Unlike TADOConnection, TSQLConnection and TDatabase do not receive any events when the transactions starts.
InterBase express offers you even more control than TSQLConnection by using a separate transaction component rather than
starting transactions using the connection component. You can, however, use TIBDatabase to start a default transaction:
if not IBDatabase1.DefaultTransaction.InTransaction then
IBDatabase1.DefaultTransaction.StartTransaction;
if (!IBDatabase1->DefaultTransaction->InTransaction)
IBDatabase1->DefaultTransaction->StartTransaction();
You can have overlapped transactions by using two separate transaction components. Each transaction component has a set of
parameters that let you configure the transaction. These let you specify the transaction isolation level, as well as other properties
of the transaction.
Ending a transaction
Ideally, a transaction should only last as long as necessary. The longer a transaction is active, the more simultaneous users that
access the database, and the more concurrent, simultaneous transactions that start and end during the lifetime of your 3
transaction, the greater the likelihood that your transaction will conflict with another when you attempt to commit any changes.
When the actions that make up the transaction have all succeeded, you can make the database changes permanent by
committing the transaction. For TDatabase, you commit a transaction using the Commitmethod:
MyOracleConnection.Commit;
MyOracleConnection->Commit();
For TSQLConnection, you also use the Commitmethod, but you must specify which transaction you are committing by supplying
1499
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
After the transaction is successfully committed, an ADO connection component receives an OnCommitTransComplete event.
Other connection components do not receive any similar events.
A call to commit the current transaction is usually attempted in a try...except statement. That way, if the transaction cannot
commit successfully, you can use the except block to handle the error and retry the operation or to roll back the transaction.
If an error occurs when making the changes that are part of the transaction or when trying to commit the transaction, you will
want to discard all changes that make up the transaction. Discarding these changes is called rolling back the transaction.
For TDatabase, you roll back a transaction by calling the Rollback method:
MyOracleConnection.Rollback;
MyOracleConnection->Rollback();
For TSQLConnection, you also use the Rollback method, but you must specify which transaction you are rolling back by
supplying the transaction descriptor you gave to the StartTransaction method:
MyOracleConnection.Rollback(TD);
MyOracleConnection->Rollback(TD);
For TIBDatabase, you roll back a transaction object by calling its Rollback method:
IBDatabase1.DefaultTransaction.Rollback;
IBDatabase1->DefaultTransaction->Rollback();
For TADOConnection, you roll back a transaction by calling the RollbackTrans method:
ADOConnection1.RollbackTrans;
ADOConnection1->RollbackTrans();
After the transaction is successfully rolled back, an ADO connection component receives an OnRollbackTransComplete event.
Other connection components do not receive any similar events.
• Exception handling code when you can't recover from a database error.
• Button or menu event code, such as when a user clicks a Cancel button.
See Also
3 Controlling Server Login ( see page 1507)
1500
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
You can use a TADOConnection component to retrieve metadata about the tables and stored procedures available on the ADO
data store. You can then use this information, for example, to let your users dynamically select a table or stored procedure at
runtime.
Note: For most database connection components, GetTableNames returns a list of all available non-system tables when the
second parameter is False. For TSQLConnection, however, you have more control over what type is added to the list when you
are not fetching only the names of system tables. When using TSQLConnection, the types of names added to the list are
controlled by the TableScope property. TableScope indicates whether the list should contain any or all of the following: ordinary
tables, system tables, synonyms, and views.
1501
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
GetProcedureParams takes two parameters: the name of the stored procedure, and an already-existing TList object to fill:
SQLConnection1.GetProcedureParams('GetInterestRate', List1);
MyDBConnection1->GetIndexNames("GetInterestRate", List1);
To convert the parameter descriptions that are added to the list into the more familiar TParams object, call the global
LoadParamListItems procedure. Because GetProcedureParams dynamically allocates the individual records, your application
must free them when it is finished with the information. The global FreeProcParams routine can do this for you.
See Also
Controlling Server Login ( see page 1507)
The Execute method is very convenient for executing simple SQL statements that do not return any records. Such statements
include Data Definition Language (DDL) statements, which operate on or create a database's metadata, such as CREATE
INDEX, ALTER TABLE, and DROP DOMAIN. Some Data Manipulation Language (DML) SQL statements also do not return a
result set. The DML statements that perform an action on data but do not return a result set are: INSERT, DELETE, and
UPDATE.
The syntax for the Execute method varies with the connection type:
• For TDatabase, Execute takes four parameters: a string that specifies a single SQL statement that you want to execute, a
TParams object that supplies any parameter values for that statement, a boolean that indicates whether the statement should
be cached because you will call it again, and a pointer to a BDE cursor that can be returned (It is recommended that you pass
nil).
3 • For TADOConnection, there are two versions of Execute. The first takes a WideString that specifies the SQL statement and a
second parameter that specifies a set of options that control whether the statement is executed asynchronously and whether it
returns any records. This first syntax returns an interface for the returned records. The second syntax takes a WideString that
specifies the SQL statement, a second parameter that returns the number of records affected when the statement executes,
and a third that specifies options such as whether the statement executes asynchronously. Note that neither syntax provides
for passing parameters.
• For TSQLConnection, Execute takes three parameters: a string that specifies a single SQL statement that you want to
execute, a TParams object that supplies any parameter values for that statement, and a pointer that can receive a
TCustomSQLDataSet that is created to return records.
1502
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Note: Execute can only execute one SQL statement at a time. It is not possible to execute multiple SQL statements with a
single call to Execute, as you can with SQL scripting utilities. To execute more than one statement, call Execute repeatedly.
It is relatively easy to execute a statement that does not include any parameters. For example, the following code executes a
CREATE TABLE statement (DDL) without any parameters on a TSQLConnection component:
procedure TForm1.CreateTableButtonClick(Sender: TObject);
var
SQLstmt: String;
begin
SQLConnection1.Connected := True;
SQLstmt := 'CREATE TABLE NewCusts ' +
'( " +
' CustNo INTEGER, ' +
' Company CHAR(40), ' +
' State CHAR(2), ' +
' PRIMARY KEY (CustNo) ' +
')';
SQLConnection1.Execute(SQLstmt, nil, nil);
end;
void __fastcall TDataForm::CreateTableButtonClick(TObject *Sender)
{
SQLConnection1->Connected = true;
AnsiString SQLstmt = "CREATE TABLE NewCusts " +
"( " +
" CustNo INTEGER, " +
" Company CHAR(40), " +
" State CHAR(2), " +
" PRIMARY KEY (CustNo) " +
")";
SQLConnection1->Execute(SQLstmt, NULL, NULL);
}
To use parameters, you must create a TParams object. For each parameter value, use the TParams.CreateParam method to
add a TParam object. Then use properties of TParam to describe the parameter and set its value.
This process is illustrated in the following example, which uses TDatabase to execute an INSERT statement. The INSERT
statement has a single parameter named: StateParam. A TParams object (called stmtParams) is created to supply a value of
"CA" for that parameter.
procedure TForm1.INSERT_WithParamsButtonClick(Sender: TObject);
var
SQLstmt: String;
stmtParams: TParams;
begin
stmtParams := TParams.Create;
try
Database1.Connected := True;
stmtParams.CreateParam(ftString, 'StateParam', ptInput);
stmtParams.ParamByName('StateParam').AsString := 'CA';
SQLstmt := 'INSERT INTO "Custom.db" '+
'(CustNo, Company, State) ' +
'VALUES (7777, "Robin Dabank Consulting", :StateParam)';
Database1.Execute(SQLstmt, stmtParams, False, nil);
finally
stmtParams.Free;
end; 3
end;
void __fastcall TForm1::INSERT_WithParamsButtonClick(TObject *Sender)
{
AnsiString SQLstmt;
TParams *stmtParams = new TParams;
try
{
Database1->Connected = true;
stmtParams->CreateParam(ftString, "StateParam", ptInput);
1503
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
stmtParams->ParamByName("StateParam")->AsString = "CA";
SQLstmt = "INSERT INTO "Custom.db" ";
SQLstmt += "(CustNo, Company, State) ";
SQLstmt += "VALUES (7777, "Robin Dabank Consulting", :StateParam)";
Database1->Execute(SQLstmt, stmtParams, false, NULL);
}
__finally
{
delete stmtParams;
}
}
If the SQL statement includes a parameter but you do not supply a TParam object to provide its value, the SQL statement may
cause an error when executed (this depends on the particular database back-end used). If a TParam object is provided but there
is no corresponding parameter in the SQL statement, an exception is raised when the application attempts to use the TParam.
See Also
Controlling Server Login ( see page 1507)
Each server type supports a different set of possible transaction isolation levels. There are three possible transaction isolation
levels:
• DirtyRead: When the isolation level is DirtyRead, your transaction sees all changes made by other transactions, even if they
have not been committed. Uncommitted changes are not permanent, and might be rolled back at any time. This value
provides the least isolation, and is not available for many database servers (such as Oracle, Sybase, MS-SQL, and
InterBase).
• ReadCommitted: When the isolation level is ReadCommitted, only committed changes made by other transactions are visible.
Although this setting protects your transaction from seeing uncommitted changes that may be rolled back, you may still
receive an inconsistent view of the database state if another transaction is committed while you are in the process of reading.
This level is available for all transactions except local transactions managed by the BDE.
• RepeatableRead: When the isolation level is RepeatableRead, your transaction is guaranteed to see a consistent state of the
database data. Your transaction sees a single snapshot of the data. It cannot see any subsequent changes to data by other
simultaneous transactions, even if they are committed. This isolation level guarantees that once your transaction reads a
record, its view of that record will not change. At this level your transaction is most isolated from changes made by other
transactions. This level is not available on some servers, such as Sybase and MS-SQL and is unavailable on local
transactions managed by the BDE.
In addition, TSQLConnection lets you specify database-specific custom isolation levels. Custom isolation levels are defined by
3 the dbExpress driver. See your driver documentation for details.
Note: For a detailed description of how each isolation level is implemented, see your server documentation.
TDatabase and TADOConnection let you specify the transaction isolation level by setting the TransIsolation property. When
you set TransIsolation to a value that is not supported by the database server, you get the next highest level of isolation (if
available). If there is no higher level available, the connection component raises an exception when you try to start a
transaction.
When using TSQLConnection, transaction isolation level is controlled by the IsolationLevel field of the transaction descriptor.
1504
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
When using InterBase express, transaction isolation level is controlled by a transaction parameter.
See Also
Managing Transactions ( see page 1498)
When using an implicit connection, you do not need to explicitly create a connection component. This can simplify your
application development, and the default connection you specify can cover a wide variety of situations. For complex,
mission-critical client/server applications with many users and different requirements for database connections, however, you
should create your own connection components to tune each database connection to your application's needs. Explicit
connection components give you greater control. For example, you need to access the connection component to perform the
following tasks:
• Customize database server login support ( see page 1507). (Implicit connections display a default login dialog to prompt the
user for a user name and password.)
• Control transactions and specify transaction isolation levels ( see page 1498).
• Execute SQL commands on the server without using a dataset ( see page 1502).
• Perform actions on all open datasets that are connected to the same database ( see page 1505).
In addition, if you have multiple datasets that all use the same server, it can be easier to use an connection component, so that
you only have to specify the server to use in one place. That way, if you later change the server, you do not need to update
several dataset components: only the connection component.
See Also
Controlling Connections ( see page 1497)
You can use this list as well, to perform actions on all the datasets that use a specific connection component to connect to a
3
particular database.
To close all open datasets without disconnecting from a server, you can use the CloseDataSets method.
For TADOConnection and TIBDatabase, calling CloseDataSets always leaves the connection open. For TDatabase and
1505
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Note: When you use a specialized client dataset to cache updates (as opposed to the generic client dataset, TClientDataSet),
the DataSets property lists the internal dataset owned by the client dataset, not the client dataset itself.
You can use DataSets with DataSetCount to cycle through all currently active datasets in code. For example, the following code
cycles through all active datasets and disables any controls that use the data they provide:
var
I: Integer;
begin
with MyDBConnection do
begin
for I := 0 to DataSetCount - 1 do
DataSets[I].DisableControls;
end;
end;
for (int i = 0; i < MyDBConnection->DataSetCount; i++)
MyDBConnection->DataSets[i]->DisableControls();
Note: TADOConnection supports command objects as well as datasets. You can iterate through these much like you iterate
through the datasets, by using the Commands and CommandCount properties.
See Also
Controlling Server Login ( see page 1507)
1506
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Note: For a discussion of some pros and cons of each of these mechanisms, see Using Databases ( see page 1572).
The connection component provides all the information necessary to establish a database connection. This information is
different for each type of connection component:
• For information about describing a BDE-based connection, see Identifying the Database ( see page 1648).
• For information about describing an ADO-based connection, see Connecting to a Data Store Using TADOConnection ( see
page 1478).
• For information about describing a dbExpress connection, see Setting up TSQLConnection ( see page 1834).
• For information about describing an InterBase Express connection, see TIBDatabase.
Although each type of dataset uses a different connection component, they are all descendants of TCustomConnection. They all
perform many of the same tasks and surface many of the same properties, methods, and events.
The following topics discuss many of these common tasks:
• Using Implicit Connections ( see page 1505)
• Controlling Connections ( see page 1497)
• Controlling Server Login ( see page 1507)
• Managing Transactions ( see page 1498)
• Working with Associated Datasets ( see page 1505)
• Sending Commands to the Server ( see page 1502)
• Obtaining Metadata ( see page 1501)
See Also
Designing Database Applications ( see page 1566)
1507
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
At design time, if a server requires a login, a standard login dialog box prompts for a user name and password when you first
attempt to connect to the database.
At runtime, there are three ways you can handle a server's request for a login:
The first way is to let the default login dialog and processes handle the login. This is the default approach. Set the LoginPrompt
property of the connection component to True (the default) and add DBLogDlg to the uses clause of the unit that declares the
connection component. Your application displays the standard login dialog box when the server requests a user name and
password.
The second way is to supply the login information before the login attempt. Each type of connection component uses a different
mechanism for specifying the user name and password:
• For BDE, dbExpress, and InterBase express datasets, the user name and password connection parameters can be accessed
through the Params property. (For BDE datasets, the parameter values can also be associated with a BDE alias, while for
dbExpress datasets, they can also be associated with a connection name).
• For ADO datasets, the user name and password can be included in the ConnectionString property (or provided as parameters
to the Open method).
If you specify the user name and password before the server requests them, be sure to set the LoginPrompt to False, so that the
default login dialog does not appear. For example, the following code sets the user name and password on a SQL connection
component in the BeforeConnect event handler, decrypting an encrypted password that is associated with the current
connection name:
procedure TForm1.SQLConnectionBeforeConnect(Sender: TObject);
begin
with Sender as TSQLConnection do
begin
if LoginPrompt = False then
begin
Params.Values['User_Name'] := 'SYSDBA';
Params.Values['Password'] := Decrypt(Params.Values['Password']);
end;
end;
end;
void __fastcall TForm1::SQLConnectionBeforeConnect(TObject *Sender)
{
if (SQLConnection1->LoginPrompt == false)
{
SQLConnection1->Params->Values["User_Name"] = "SYSDBA";
SQLConnection1->Params->Values["Password"] =
Decrypt(SQLConnection1->Params->Values["Password"]);
}
}
Note that setting the user name and password at design-time or using hard-coded strings in code causes the values to be
embedded in the application's executable file. This still leaves them easy to find, compromising server security:
The third way is to provide your own custom handling for the login event. The connection component generates an event when it
needs the user name and password.
• For TDatabase, TSQLConnection, and TIBDatabase, this is an OnLogin event. The event handler has two parameters, the
3 connection component, and a local copy of the user name and password parameters in a string list. (TSQLConnection
includes the database parameter as well). You must set the LoginPrompt property to True for this event to occur. Having a
LoginPrompt value of False and assigning a handler for the OnLogin event creates a situation where it is impossible to log in
to the database because the default dialog does not appear and the OnLogin event handler never executes.
• For TADOConnection, the event is an OnWillConnect event. The event handler has five parameters, the connection
component and four parameters that return values to influence the connection (including two for user name and password).
This event always occurs, regardless of the value of LoginPrompt.
Write an event handler for the event in which you set the login parameters. Here is an example where the values for the USER
1508
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
NAME and PASSWORD parameters are provided from a global variable (UserName) and a method that returns a password
given a user name (PasswordSearch)
procedure TForm1.Database1Login(Database: TDatabase; LoginParams: TStrings);
begin
LoginParams.Values['USER NAME'] := UserName;
LoginParams.Values['PASSWORD'] := PasswordSearch(UserName);
end;
void __fastcall TForm1::Database1Login(TDatabase *Database, TStrings *LoginParams)
{
LoginParams->Values["USER NAME"] = UserName;
LoginParams->Values["PASSWORD"] = PasswordSearch(UserName);
}
As with the other methods of providing login parameters, when writing an OnLogin or OnWillConnect event handler, avoid hard
coding the password in your application code. It should appear only as an encrypted value, an entry in a secure database your
application uses to look up the value, or be dynamically obtained from the user.
See Also
Using Implicit Connections ( see page 1505)
1509
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
1510
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Brokering Connections ( see page 1520) If you have multiple COM-based servers that your client application can choose
from, you can use an Object Broker to locate an available server system. The
object broker maintains a list of servers from which the connection component
can choose. When the connection component needs to connect to an application
server, it asks the Object Broker for a computer name (or IP address, host name,
or URL). The broker supplies a name, and the connection component forms a
connection. If the supplied name does not work (for example, if the server is
down), the broker supplies another name, and so... more ( see page 1520)
Building a Multi-tiered Application ( see page 1520)
Building an InternetExpress Application ( see page 1521) The following steps describe one way to build a Web application using
InternetExpress. The result is an application that creates HTML pages that let
users interact with the data from an application server via a javascript-enabled
Web browser. You can also build an InternetExpress application using the Site
Express architecture by using the InternetExpress page producer
(TInetXPageProducer).
Building Web Applications Using InternetExpress ( see page 1522) A client application can request that the application server provide data packets
that are coded in XML instead of OleVariants. By combining XML-coded data
packets, special javascript libraries ( see page 1549) of database functions,
and the Web server application support, you can create thin client applications
that can be accessed using a Web browser that supports javascript. This
combination of features is called InternetExpress.
Before building an InternetExpress application ( see page 1521), you should
understand the Web server application architecture and the multi-tiered database
architecture. These are described in Creating Internet Server Applications ( see
page 2251) and Creating multi-tiered Applications ( see page 1518)
An InternetExpress application extends the basic Web server... more ( see
page 1522)
Calling Server Interfaces ( see page 1522) Applications do not need to call the IAppServer or IAppServerSOAP interface
directly because the appropriate calls are made automatically when you use the
properties and methods of the client dataset. However, while it is not necessary
to work directly with the IAppServer or IAppServerSOAP interface, you may have
added your own extensions to the remote data module's interface. When you
extend the application server's interface ( see page 1531), you need a way to
call those extensions using the connection created by your connection
component. Unless you are using SOAP, you can do this using the AppServer
property of the connection component.
AppServer... more ( see page 1522)
Choosing a Connection Protocol ( see page 1523) Each communications protocol you can use to connect your client applications to
the application server provides its own unique benefits. Before choosing a
protocol, consider how many clients you expect, how you are deploying your
application, and future development plans.
The following topics describe the unique features for each connection protocol:
1511
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Configuring TSOAPDataModule ( see page 1525) To add a TSoapDataModule component to your application, choose
File New Other and select SOAP Server Data Module from the WebServices
page of the new items dialog. The SOAP data module wizard appears.
You must supply a class name for your SOAP data module. This is the base
name of a TSoapDataModule descendantthat your application creates. It is also
the base name of the interface for that class. For example, if you specify the
class name MyDataServer, the wizard creates a new unit declaring
TMyDataServer, a descendant of TSoapDataModule, which implements
IMyDataServer, a descendant of... more ( see page 1525)
Connecting to an Application Server That Uses Multiple Data Modules ( see If a COM-based application server uses a main "parent" remote data module and
page 1526) several child remote data modules, as described in Using multiple remote data
modules ( see page 1547), then you need a separate connection component
for every remote data module on the application server. Each connection
component represents the connection to a single remote data module.
While it is possible to have your client application form independent connections
to each remote data module on the application server, it is more efficient to use a
single connection to the application server that is shared by all the connection
components. That is, you... more ( see page 1526)
Creating an Active Form for the Client Application ( see page 1526)
Creating the Application Server ( see page 1527) You create an application server very much as you create most database
applications. The major difference is that the application server uses a remote
data module.
Creating the Client Application ( see page 1528) In most regards, creating a multi-tiered client application is similar to creating a
two-tiered client that uses a client dataset to cache updates. The major difference
is that a multi-tiered client uses a connection component to establish a conduit to
the application server.
Creating Web Pages with an InternetExpress Page Producer ( see page 1529) Each InternetExpress page producer generates an HTML document that appears
in the browsers of your application's clients. If your application includes several
separate Web documents, use a separate page producer for each of them.
The InternetExpress page producer (TInetXPageProducer) is a special page
producer component ( see page 2270). As with other page producers, you can
assign it as the Producer property of an action item or call it explicitly from an
OnAction event handler. For more information about using content producers
with action items, see Responding to request messages with action items ( see
page 2278).
The InternetExpress page producer has a default... more ( see page 1529)
Customizing the InternetExpress Page Producer Template ( see page 1529) The template of an InternetExpress page producer is an HTML document with
extra embedded tags that your application translates dynamically. Initially, the
page producer generates a default template as the value of the HTMLDoc
property. This default template has the form
Distributing a Client Application as an ActiveX Control ( see page 1530) The multi-tiered database architecture can be combined with ActiveX features to
distribute a client application as an ActiveX control.
When you distribute your client application as an ActiveX control, create the
application server ( see page 1527) as you would for any other multi-tiered
application.
When creating the client application, you must use an Active Form as the basis
instead of an ordinary form. See Creating an Active Form for the Client
Application ( see page 1526) for details.
Once you have built and deployed your client application, it can be accessed
from any ActiveX-enabled Web browser on another machine. For a Web browser
to successfully launch your... more ( see page 1530)
Dropping or Changing a Server Connection ( see page 1531) A connection component drops a connection to the application server when you
1512
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Extending the Interface of the Application Server ( see page 1531) Client applications interact with the application server by creating or connecting
to an instance of the remote data module. They use its interface as the basis of
all communication with the application server.
You can add to your remote data module's interface to provide additional support
for your client applications. This interface is a descendant of IAppServer and is
created for you automatically by the wizard when you create the remote data
module ( see page 1536).
To add to the remote data module's interface, you can
1513
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Pooling Remote Data Modules ( see page 1535) Object pooling allows you to create a cache of remote data modules that are
shared by their clients, thereby conserving resources. How this works depends
on the type of remote data module and on the connection protocol ( see page
1523).
If you are creating a transactional data module ( see page 1546) that will be
installed to COM+, you can use the COM+ Component Manager to install the
application server as a pooled object.
Even if you are not using a transactional data module, you can take advantage of
object pooling if the connection is formed using TWebConnection. Under this
second type of object pooling,... more ( see page 1535)
Registering the Application Server ( see page 1535) Before client applications can locate and use an application server, it must be
registered or installed.
1514
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Specifying a Connection Using SOAP ( see page 1538) You can establish a connection to a SOAP application server using the
TSoapConnection component. TSoapConnection is very similar to
TWebConnection, because it also uses HTTP as a transport protocol. Thus, you
can use TSoapConnection from any machine that has a TCP/IP address, and it
can take advantage of SSL security and to communicate with a server that is
protected by a firewall.
The SOAP connection component establishes a connection to a Web Service
provider that implements the IAppServerSOAP or IAppServer interface. (The
UseSOAPAdapter property specifies which interface it expects the server to
support.) If the server implements the IAppServerSOAP... more ( see page
1538)
Specifying a Connection Using Sockets ( see page 1538) You can establish a connection to the application server using sockets from any
machine that has a TCP/IP address. This method has the advantage of being
applicable to more machines, but does not provide for using any security
protocols. When using sockets, include a TSocketConnection component for
connecting to the application server.
TSocketConnection identifies the server machine using the IP Address or host
name of the server system, and the port number of the socket dispatcher
program (Scktsrvr.exe) that is running on the server machine. For more
information about IP addresses and port values, see Describing sockets ( see
page 2336).
Three properties... more ( see page 1538)
Supporting Master/detail Relationships ( see page 1539) You can create master/detail relationships between client datasets in your client
application in the same way you set them up using any table-type dataset. For
more information about setting up master/detail relationships in this way, see
Creating Master/detail Relationships ( see page 1590).
However, this approach has two major drawbacks:
• The detail table must fetch and store all of its records from
the application server even though it only uses one detail
set at a time. (This problem can be mitigated by using
parameters. For more information, see Limiting records
with parameters ( see page 1720).)
• It is very difficult to apply updates, because client
datasets... more ( see page 1539)
Supporting State Information in Remote Data Modules ( see page 1540) The IAppServer interface, which client datasets use to communicate with
providers on the application server, is mostly stateless. When an application is
stateless, it does not "remember" anything that happened in previous calls by the
client. This stateless quality is useful if you are pooling database connections in a
transactional data module, because your application server does not need to
distinguish between database connections for persistent information such as
record currency. Similarly, this stateless quality is important when you are
sharing remote data module instances between many clients, as occurs with
just-in-time activation or object pooling. SOAP data modules must... more ( see
page 1540)
The Structure of the Application Server ( see page 1542) When you set up and run an application server, it does not establish any
connection with client applications. Rather, client applications initiate and
maintain the connection. The client application uses a connection component to
connect to the application server, and uses the interface of the application server
to communicate with a selected provider. All of this happens automatically,
without your having to write code to manage incoming requests or supply
interfaces.
The basis of an application server is a remote data module, which is a
specialized data module that supports the IAppServer interface (for application
servers that also function as... more ( see page 1542)
The Structure of the Client Application ( see page 1543) To the end user, the client application of a multi-tiered application looks and
behaves no differently than a two-tiered application that uses cached updates.
User interaction takes place through standard data-aware controls that display
data from a TClientDataSet component. For detailed information about using the
properties, events, and methods of client datasets, see Using Client Datasets ( 3
see page 1740).
TClientDataSet fetches data from and applies updates to a provider component,
just as in two-tiered applications that use a client dataset with an external
provider. For details about providers, see Using Provider Components ( see
page 1819). For details about client dataset features that facilitate its... more (
see page 1543)
1515
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Understanding Multi-tiered Database Applications ( see page 1544) Multi-tiered applications use the components on the DataSnap page, the Data
Access page, and possibly the WebServices page of the Tool palette, plus a
remote data module that is created by a wizard on the Multitier or WebServices
page of the New Items dialog. They are based on the ability of provider
components to package data into transportable data packets and handle updates
received as transportable delta packets.
The components needed for a multi-tiered application are described in the
following table:
Components used in multi-tiered applications
Using an XML Broker ( see page 1544) The XML broker serves two major functions:
1516
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Using the Javascript Libraries ( see page 1549) The HTML pages generated by the InternetExpress components and the Web
items they contain make use of several javascript libraries that ship in the
source/webmidas directory:
Javascript libraries
Using the Web Page Editor ( see page 1549) The Web page editor lets you add Web items to your InternetExpress page
producer and view the resulting HTML page. Display the Web page editor by
double-clicking on a InternetExpress page producer component.
Note: You must have Internet Explorer 4 or better installed to use the Web page
editor.
The top of the Web page editor displays the Web items that generate the HTML
document. These Web items are nested, where each type of Web item
assembles the HTML generated by its subitems. Different types of items can
contain different subitems. On the left, a tree view displays all of... more ( see
page 1549)
Using Web Connections ( see page 1550) HTTP lets you create clients that can communicate with an application server
that is protected by a firewall. HTTP messages provide controlled access to
internal applications so that you can distribute your client applications safely and
widely. Like socket connections, HTTP messages provide a lowest common
denominator that you know will be available for connecting to the application
server. For more information about HTTP messages, see Creating Internet
Server Applications ( see page 2251)
Instead of instantiating the remote data module directly from the client (as
happens with DCOM), HTTP-based connections use a Web server application on
the server (httpsrvr.dll) that accepts client requests... more ( see page 1550)
Writing Web-based Client Applications ( see page 1551) If you want to create Web-based clients for your multi-tiered database
application, you must replace the client tier with a special Web application that
acts simultaneously as a client to an application server and as a Web server
application that is installed with a Web server on the same machine. This
architecture is illustrated in the following figure.
There are two approaches that you can take to build the Web application:
• Identify the protocol for communicating with the application server. Each type of connection component represents a different
communication protocol. See Choosing a connection protocol ( see page 1523) for details on the benefits and limitations of
the available protocols.
• Indicate how to locate the server machine. The details of identifying the server machine vary depending on the protocol. See
the following topics for details:
• Specifying a connection using DCOM ( see page 1537) 3
• Specifying a connection using sockets ( see page 1538)
• Specifying a connection using HTTP ( see page 1537)
• Specifying a connection using SOAP ( see page 1538)
• Identify the application server on the server machine.
• If you are not using SOAP, identify the server using the ServerName or ServerGUID property. ServerName identifies the base
name of the class you specify when creating the remote data module on the application server. See Setting up the remote
1517
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
data module ( see page 1536) for details on how this value is specified on the server. If the server is registered or installed
on the client machine, or if the connection component is connected to the server machine, you can set the ServerName
property at design time by choosing from a drop-down list in the Object Inspector. ServerGUID specifies the GUID of the
remote data module's interface. You can look up this value using the type library editor.
• Manage server connections ( see page 1533). Connection components can be used to create or drop connections and to
call application server interfaces.
If you are using SOAP, the server is identified in the URL you use to locate the server machine. Follow the steps in Specifying a
connection using SOAP ( see page 1538).
Usually the application server is on a different machine from the client application, but even if the server resides on the same
machine as the client application (for example, during the building and testing of the entire multi-tier application), you can still
use the connection component to identify the application server by name, specify a server machine, and use the application
server interface.
See Also
The Structure of the Client Application ( see page 1543)
In its simplest form, sometimes called the "three-tiered model," a multi-tiered application is partitioned into thirds:
1518
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
The connection is opened automatically when client datasets try to access the application server. For example, setting the Active
property of the client dataset to True opens the connection, as long as the RemoteServer property has been set.
If you do not link any client datasets to the connection component, you can open the connection by setting the Connected
property of the connection component to True.
Before a connection component establishes a connection to an application server, it generates a BeforeConnect event. You can
perform any special actions prior to connecting in a BeforeConnect handler that you code. After establishing a connection, the
connection component generates an AfterConnect event for any special actions.
See Also
Dropping or Changing a Server Connection ( see page 1531)
Connecting to an Application Server That Uses Multiple Data Modules ( see page 1526)
• Encapsulation of business logic in a shared middle tier. Different client applications all access the same middle tier. This
allows you to avoid the redundancy (and maintenance cost) of duplicating your business rules for each separate client
application. 3
• Thin client applications. Your client applications can be written to make a small footprint by delegating more of the
processing to middle tiers. Not only are client applications smaller, but they are easier to deploy because they don't need to
worry about installing, configuring, and maintaining the database connectivity software (such as the database server's
client-side software). Thin client applications can be distributed over the Internet for additional flexibility.
• Distributed data processing. Distributing the work of an application over several machines can improve performance
because of load balancing, and allow redundant systems to take over when a server goes down.
• Increased opportunity for security. You can isolate sensitive functionality into tiers that have different access restrictions.
1519
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
This provides flexible and configurable levels of security. Middle tiers can limit the entry points to sensitive material, allowing
you to control access more easily. If you are using HTTP or COM+, you can take advantage of the security models they
support.
See Also
Understanding MIDAS Technology ( see page 1544)
Once the connection component has formed a connection with a name supplied by the broker, it saves that name as the value of
the appropriate property (ComputerName, Address, Host,RemoteHost, or URL). If the connection component closes the
connection later, and then needs to reopen the connection, it tries using this property value, and only requests a new name from
the broker if the connection fails.
Use an Object Broker by specifying the ObjectBroker property of your connection component. When the ObjectBroker property is
set, the connection component does not save the value of ComputerName, Address, Host, RemoteHost, or URL to disk.
Note: You can not use the ObjectBroker property with SOAP connections.
See Also
Specifying a Connection Using DCOM ( see page 1537)
1520
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
See Also
Understanding MIDAS Technology ( see page 1544)
1521
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
Before building an InternetExpress application ( see page 1521), you should understand the Web server application
architecture and the multi-tiered database architecture. These are described in Creating Internet Server Applications ( see
page 2251) and Creating multi-tiered Applications ( see page 1518)
An InternetExpress application extends the basic Web server application architecture to act as the client of an application server.
InternetExpress applications generate HTML pages that contain a mixture of HTML, XML, and javascript. The HTML governs the
layout and appearance of the pages seen by end users in their browsers. The XML encodes the data packets and delta packets
that represent database information. The javascript allows the HTML controls to interpret and manipulate the data in these XML
data packets on the client machine.
If the InternetExpress application uses DCOM to connect to the application server, you must take additional steps to ensure that
the application server grants access and launch permissions ( see page 1532) to its clients.
Tip: You can create an InternetExpress application to provide Web browsers with "live" data even if you do not have an
application server. Simply add the provider and its dataset to the Web module.
See Also
Building a Multi-tiered Application ( see page 1520)
AppServer is a Variant that represents the application server's interface. If you are not using SOAP, you can call an interface
method using AppServer by writing a statement such as
MyConnection.AppServer.SpecialMethod(x,y);
However, this technique provides late (dynamic) binding of the interface call. That is, the SpecialMethod procedure call is not
bound until runtime when the call is executed. Late binding is very flexible, but by using it you lose many benefits such as code
insight and type checking. In addition, late binding is slower than early binding, because the compiler generates additional calls
to the server to set up interface calls before they are invoked.
3
Using early binding with DCOM
When you are using DCOM as a communications protocol, you can use early binding of AppServer calls. Use the as operator to
cast the AppServer variable to the IAppServer descendant you created when you created the remote data module ( see page
1536). For example:
with MyConnection.AppServer as IMyAppServer do
SpecialMethod(x,y);
To use early binding under DCOM, the server's type library must be registered on the client machine. You can use TRegsvr.exe,
1522
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
Note: See the TRegSvr demo (which provides the source for TRegsvr.exe) for an example of how to register the type library
programmatically.
• Your client application must include the definition of the application server's interface and register it with the invocation
registry. You can add the definition of this interface to your client application by referencing a WSDL document that describes
the interface you want to call. For information on importing a WSDL document that describes the server interface, see
Importing WSDL documents ( see page 2307). When you import the interface definition, the WSDL importer automatically
adds code to register it with the invocation registry. For more information about interfaces and the invocation registry, see
Understanding invokable interfaces ( see page 2292).
• The TSOAPConnection component must have its UseSOAPAdapter property set to True. This means that the server must
support the IAppServerSOAP interface. If the application server is built using Delphi 6 or Kylix 1, it does not support
IAppServerSOAP and you must use a separate THTTPRio component instead. For details on how to call an interface using a
THTTPRio component, see Calling invokable interfaces ( see page 2307).
• You must set the SOAPServerIID property of the SOAP connection component to the GUID of the server interface. You must
set this property before your application connects to the server, because it tells the TSOAPConnection component what
interface to fetch from the server.
Assuming the previous three conditions are met, you can fetch the server interface as follows:
with MyConnection.GetSOAPServer as IMyAppServer do
SpecialMethod(x,y);
IDispatch* disp = (IDispatch*)(MyConnection->AppServer)
IMyAppServerDisp TempInterface( (IMyAppServer*)disp);
TempInterface.SpecialMethod(x,y);
See Also
Connecting to the Server ( see page 1519)
3
Dropping or Changing a Server Connection ( see page 1531)
Connecting to an Application Server That Uses Multiple Data Modules ( see page 1526)
1523
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
development plans.
The following topics describe the unique features for each connection protocol:
You must supply a class name for your remote data module. This is the base name of a descendant of TMTSDataModule that
your application creates. It is also the base name of the interface for that class. For example, if you specify the class name
MyDataServer, the wizard creates a new unit declaring TMyDataServer, a descendant of TMTSDataModule, which implements
IMyDataServer, a descendant of IAppServer.
Note: You can add your own properties and methods to your new interface. For more information, see Extending the application
server's interface ( see page 1531).
You must specify the threading model in the Transactional Data Module wizard. Choose Single, Apartment, or Both.
• If you choose Single, client requests are serialized so that your application services only one at a time. You do not need to
worry about client requests interfering with each other.
• If you choose Apartment, the system ensures that any instance of your remote data module services one request at a time,
and calls always use the same thread. You must guard against thread conflicts if you use global variables or objects not
contained in the remote data module. Instead of using global variables, you can use the shared property manager.
• If you choose Both, MTS calls into the remote data module's interface in the same way as when you choose Apartment.
However, any callbacks you make to client applications are serialized, so that you don't need to worry about them interfering
with each other.
Note: The Apartment model under MTS or COM+ is different from the corresponding model under DCOM.
You must also specify the transaction attributes of your remote data module. You can choose from the following options:
• Requires a transaction. When you select this option, every time a client uses your remote data module's interface, that call is
executed in the context of a transaction. If the caller supplies a transaction, a new transaction need not be created.
• Requires a new transaction. When you select this option, every time a client uses your remote data module's interface, a new
3 transaction is automatically created for that call.
• Supports transactions. When you select this option, your remote data module can be used in the context of a transaction, but
the caller must supply the transaction when it invokes the interface.
• Does not support transactions. When you select this option, your remote data module can't be used in the context of
transactions.
See Also
Configuring TSOAPDataModule ( see page 1525)
1524
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications
You must supply a class name for your remote data module. This is the base name of a descendant of TRemoteDataModule that
your application creates. It is also the base name of the interface for that class. For example, if you specify the class name
MyDataServer, the wizard creates a new unit declaring TMyDataServer, a descendant of TRemoteDataModule, which
implements IMyDataServer, a descendant of IAppServer.
Note: You can add your own properties and methods to the new interface. For more information, see Extending the application
server's interface ( see page 1531).
You must specify the threading model in the Remote Data Module wizard. You can choose Single-threaded,
Apartment-threaded, Free-threaded, or Both.
• If you choose Single-threaded, COM ensures that only one client request is serviced at a time. You do not need to worry
about client requests interfering with each other.
• If you choose Apartment-threaded, COM ensures that any instance of your remote data module services one request at a
time. When writing code in an Apartment-threaded library, you must guard against thread conflicts if you use global variables
or objects not contained in the remote data module. This is the recommended model if you are using BDE-enabled datasets.
(Note that you will need a session component with its AutoSessionName property set to True to handle threading issues on
BDE-enabled datasets).
• If you choose Free-threaded, your application can receive simultaneous client requests on several threads. You are
responsible for ensuring your application is thread-safe. Because multiple clients can access your remote data module
simultaneously, you must guard your instance data (properties, contained objects, and so on) as well as global variables. This
is the recommended model if you are using ADO datasets.
• If you choose Both, your library works the same as when you choose Free-threaded, with one exception: all callbacks (calls to
client interfaces) are serialized for you.
• If you choose Neutral, the remote data module can receive simultaneous calls on separate threads, as in the Free-threaded
model, but COM guarantees that no two threads access the same method at the same time.
If you are creating an EXE, you must also specify what type of instancing to use. You can choose Single instance or Multiple
instance (Internal instancing applies only if the client code is part of the same process space.)
• If you choose Single instance, each client connection launches its own instance of the executable. That process instantiates a
single instance of the remote data module, which is dedicated to the client connection.
• If you choose Multiple instance, a single instance of the application (process) instantiates all remote data modules created for
clients. Each remote data module is dedicated to a single client connection, but they all share the same process space.
See Also
Configuring TSOAPDataModule ( see page 1525)
Note: To use TSoapDataModule, the new data module should be added to a Web Service application. The IAppServerSOAP
interface is an invokable interface, which is registered in the initialization section of the new unit. This allows the invoker
1525
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide
component in the main Web module to forward all incoming calls to your data module.
You may want to edit the definitions of the generated interface and TSoapDataModule descendant, adding your own properties
and methods. These properties and methods are not called automatically, but client applications that request your new interface
by name or GUID can use any of the properties and methods that you add.
See Also
Configuring TRemoteDataModule ( see page 1525)
While it is possible to have your client application form independent connections to each remote data module on the application