0% found this document useful (0 votes)
35 views

devwin32

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views

devwin32

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 2467

RAD Studio

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.


RAD Studio

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

Developing Database Applications for the Win32 Platform 13


dbGo Overview 14
BDE Overview 15
dbExpress Components 16
Getting Started with InterBase Express 17
dbExpress 4 Feature Overview 22
Blackfish SQL Overview 24
dbExpress Framework 26
dbExpress Framework Compatibility 27

Developing Interoperable Applications 29


Developing COM Applications 29

Developing Reports for Your Win32 Applications 35


Using Rave Reports in RAD Studio 35

Developing Applications with VCL Components 36


VCL Overview 36
Using TEncoding for Unicode Files 38
Components Available Only on Specific OS 39

Developing Web Applications with WebSnap 41


Win32 Web Applications Overview 41

Developing Web Services with Win32 Applications 44


Web Services Overview 44

iii
RAD Studio

Developing Windows Applications 45


Windows Overview 45

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

Interoperable Applications Procedures 79

iv
RAD Studio

Using COM Wizards 79

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

Defining the Thread Object 126


Handling Exceptions 129
Initializing a Thread 130
Using the Main VCL Thread 131
Waiting for Threads 132
Writing the Thread Function (Procedure) 134
Placing A Bitmap Image in a Control in a VCL Forms Application 135
Reading a String and Writing It To a File 136
Renaming Files 137
Adding and Sorting Strings 138
Creating a VCL Forms ActiveX Button 139
Creating a VCL Forms ActiveX Active Form 140
Building a VCL Forms Web Browser Application 142
Creating an Application that Uses Ribbon Controls 143
Adding Commands to the Ribbon 144

WebSnap Procedures 147


Building a WebSnap Application 148
Building a WebSnap "Hello World" Application 149
Debugging a WebSnap Application using the Web Application Debugger 150
Using the HTML Tag Editor 151

Web Services Procedure 153


Building a "Hello World" Web Services Application 153

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

MAKE Directives 186


MAKE Macros 191
MAKE Rules (Explicit and Implicit) and Commands 193
Message Options 197
Module Definition Files 199
Using Precompiled Header Files 203
RLINK32.DLL, the Resource Linker (C++) 204
TDUMP.EXE, the File Dumping Utility 204
TLIB.EXE, the Library Manager 208
Using TOUCH.EXE 212
TRIGRAPH 213
RC.EXE, the Microsoft SDK Resource Compiler 213
WSDLIMP.EXE, the Command Line WSDL Import Tool 214
C++ Compiler Errors And Warnings (C++) 216
E2066: Invalid MOM inheritance (C++) 256
E2525: You must define _PCH_STATIC_CONST before including xstring to use this feature (C++) 257
E2526: Property 'name' uses another property as getter/setter; Not allowed (C++) 257
E2008: Published property access functions must use __fastcall calling convention (C++) 257
E2122: Function call terminated by unhandled exception 'value' at address 'addr' (C++) 257
E2506: Explicit specialization of 'specifier' is ambiguous: must specify template arguments (C++) 257
E2483: Array dimension 'specifier' could not be determined (C++) 258
E2509: Value out of range (C++) 258
E2510: Operand size mismatch (C++) 258
E2050: __declspec(delphireturn) class 'class' must have exactly one data member (C++) 258
E2530: Unrecognized option, or no help available (C++) 258
E2527: Option 'name' cannot be set via 'name' (C++) 258
E2528: Option 'name' must be set before compilation begins (C++) 258
E2074: Value after -g or -j should be between 0 and 255 inclusive (C++) 259
E2492: Properties may only be assigned using a simple statement, e.g. \"prop = value;\" (C++) 259
E2505: Explicit instantiation requires an elaborated type specifier (i.e.,"class foo<int>") (C++) 259
E2100: Invalid template declarator list (C++) 259
E2102: Cannot use template 'template' without specifying specialization parameters (C++) 260
E2107: Invalid use of template 'template' (C++) 260
E2105: 'template' qualifier must specify a member template name (C++) 260
E2066: Information not available (C++) 261
E2471: pragma checkoption failed: options are not as expected (C++) 261
E2504: 'dynamic' can only be used with non-template member functions (C++) 261
E2191: '__far16' may only be used with '__pascal' or '__cdecl' (C++) 261
E2199: Template friend function 'function' must be previously declared (C++) 262

vii
RAD Studio

E2502: Error resolving #import: problem (C++) 262


E2501: Unable to open import file 'filename' (C++) 262
E2494: Unrecognized __declspec modifier (C++) 262
E2493: Invalid GUID string (C++) 263
E2499: Invalid __declspec(uuid(GuidString)) format (C++) 263
E2496: Invalid call to uuidof(struct type|variable) (C++) 263
E2511: Unterminated macro argument (C++) 263
E2489: Maximum option context replay depth exceeded; check for recursion (C++) 263
E2488: Maximum token reply depth exceeded; check for recursion (C++) 263
E2491: Maximum VIRDEF count exceeded; check for recursion (C++) 263
E2230: In-line data member initialization requires an integral constant expression (C++) 264
E2241: VCL style classes need virtual destructors (C++) 264
E2524: Anonymous structs/unions not allowed to have anonymous members in C++ (C++) 264
E2246: x is not abstract public single inheritance class hierarchy with no data (C++) 264
E2249: = expected (C++) 264
E2267: First base must be VCL class (C++) 264
E2472: Cannot declare a member function via instantiation (C++) 265
E2515: Cannot explicitly specialize a member of a generic template class (C++) 265
E2474: 'function' cannot be declared as static or inline (C++) 265
E2498: Need previously defined struct GUID (C++) 266
E2295: Too many candidate template specializations from 'specifier' (C++) 266
E2475: 'function' cannot be a template function (C++) 266
E2299: Cannot generate template specialization from 'specifier' (C++) 267
E2300: Could not generate a specialization matching type for 'specifier' (C++) 267
E2497: No GUID associated with type:'type' (C++) 267
E2522: Non-const function 'function' called for const object (C++) 267
E2523: Non-volatile function 'name' called for volatile object (C++) 267
E2513: Cannot emit RTTI for 'parameter' in 'function' (C++) 267
E2512: Cannot emit RTTI for return type of 'function' (C++) 267
E2507: 'class' is not a direct base class of 'class' (C++) 268
E2529: Path 'path' exceeds maximum size of 'n' (C++) 268
E2495: Redefinition of uuid is not identical (C++) 268
E2500: __declspec(selectany) is only for initialized and externally visible variables (C++) 268
E2482: String constant expected (C++) 268
E2481: Unexpected string constant (C++) 268
E2386: Cannot involve parameter 'parameter' in a complex partial specialization expression (C++) 268
E2387: Partial specializations may not specialize dependent non-type parameters ('parameter') (C++) 269
E2388: Argument list of specialization cannot be identical to the parameter list of primary template (C++) 269
E2389: Mismatch in kind of substitution argument and template parameter 'parameter' (C++) 269

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

F1009: Unable to open input file 'filename' (C++) 285


F1011: Register allocation failure (C++) 285
F1012: Compiler stack overflow (C++) 285
F1013: Error writing output file (C++) 285
F1000: Compiler table limit exceeded (C++) 285
F1005: Include files nested too deep (C++) 286
F1008: Out of memory (C++) 286
F1010: Unable to open 'filename' (C++) 286
E2000: 286/287 instructions not enabled (C++) 286
Abnormal program termination (C++) 286
E2009: Attempt to grant or reduce access to 'identifier' (C++) 286
E2011: Illegal to take address of bit field (C++) 286
E2010: Cannot add or subtract relocatable symbols (C++) 287
E2013: 'function1' cannot be distinguished from 'function2' (C++) 287
E2014: Member is ambiguous: 'member1' and 'member2' (C++) 287
E2015: Ambiguity between 'function1' and 'function2' (C++) 287
E2017: Ambiguous member name 'name' (C++) 287
E2019: 'identifier' cannot be declared in an anonymous union (C++) 288
E2020: Global anonymous union not static (C++) 288
E2022: Array size too large (C++) 288
E2024: Cannot modify a const object (C++) 288
E2025: Assignment to 'this' not allowed, use X::operator new instead (C++) 288
E2026: Assembler statement too long (C++) 288
E2001: Constructors and destructors not allowed in __automated section (C++) 289
E2002: Only __fastcall functions allowed in __automated section (C++) 289
E2003: Data member definition not allowed in __automated section (C++) 289
E2004: Only read or write clause allowed in property declaration in __automated section (C++) 289
E2005: Redeclaration of property not allowed in __automated section (C++) 290
E2027: Must take address of a memory location (C++) 290
E2028: operator -> must return a pointer or a class (C++) 290
E2029: 'identifier' must be a previously defined class or struct (C++) 290
E2030: Misplaced break (C++) 290
E2031: Cannot cast from 'type1' to 'type2' (C++) 290
E2033: Misplaced continue (C++) 291
E2034: Cannot convert 'type1' to 'type2' (C++) 291
E2036: Conversion operator cannot have a return type specification (C++) 292
E2037: The constructor 'constructor' is not allowed (C++) 292
E2039: Misplaced decimal point (C++) 292
E2041: Incorrect use of default (C++) 292

xi
RAD Studio

E2042: Declare operator delete (void*) or (void*, size_t) (C++) 293


E2044: operator delete must return void (C++) 293
E2045: Destructor name must match the class name (C++) 293
E2048: Unknown preprocessor directive: 'identifier' (C++) 293
E2046: Bad file name format in include directive OR Bad file name format in line directive (C++) 294
E2051: Invalid use of dot (C++) 294
E2053: Misplaced elif directive (C++) 294
E2054: Misplaced else (C++) 294
E2055: Misplaced else directive (C++) 294
E2056: Misplaced endif directive (C++) 295
E2059: Unknown language, must be C or C++ (C++) 295
E2060: Illegal use of floating point (C++) 295
E2061: Friends must be functions or classes (C++) 295
E2062: Invalid indirection (C++) 295
E2063: Illegal initialization (C++) 296
E2064: Cannot initialize 'type1' with 'type2' (C++) 296
E2068: 'identifier' is not a non-static data member and can't be initialized here (C++) 296
E2069: Illegal use of member pointer (C++) 296
E2071: operator new must have an initial parameter of type size_t (C++) 297
E2072: Operator new[] must return an object of type void (C++) 297
E2075: Incorrect 'type' option: option (C++) 297
E2076: Overloadable operator expected (C++) 297
E2080: 'function' must be declared with one parameter (C++) 298
E2077: 'operator' must be declared with one or no parameters (C++) 298
E2079: 'function' must be declared with no parameters (C++) 298
E2078: 'operator' must be declared with one or two parameters (C++) 298
E2081: 'function' must be declared with two parameters (C++) 298
E2082: 'identifier' must be a member function or have a parameter of class type (C++) 298
E2083: Last parameter of 'operator' must have type 'int' (C++) 299
E2084: Parameter names are used only with a function body (C++) 299
E2085: Invalid pointer addition (C++) 299
E2086: Illegal pointer subtraction (C++) 299
E2087: Illegal use of pointer (C++) 299
E2088: Bad syntax for pure function definition (C++) 300
E2089: Identifier 'identifier' cannot have a type qualifier (C++) 300
E2090: Qualifier 'identifier' is not a class or namespace name (C++) 300
E2092: Storage class 'storage class' is not allowed here (C++) 300
E2096: Illegal structure operation (C++) 300
E2104: Invalid use of template keyword (C++) 300

xii
RAD Studio

E2108: Improper use of typedef 'identifier' (C++) 301


E2109: Not an allowed type (C++) 301
E2110: Incompatible type conversion (C++) 301
E2113: Virtual function 'function1' conflicts with base class 'base' (C++) 301
E2114: Multiple base classes require explicit class names (C++) 301
E2115: Bit field too large (C++) 301
E2116: Bit fields must contain at least one bit (C++) 301
W8005: Bit fields must be signed or unsigned int (C++) 302
E2119: User break (C++) 302
E2111: Type 'typename' may not be defined here (C++) 302
E2121: Function call missing ) (C++) 302
E2123: Class 'class' may not contain pure functions (C++) 302
E2126: Case bypasses initialization of a local variable (C++) 302
E2127: Case statement missing : (C++) 302
E2128: Case outside of switch (C++) 302
E2129: Character constant too long (or empty) (C++) 303
E2133: Unable to execute command 'command' (C++) 303
E2134: Compound statement missing closing brace (C++) 303
E2137: Destructor for 'class' required in conditional expression (C++) 303
E2135: Constructor/Destructor cannot be declared 'const' or 'volatile' (C++) 303
E2138: Conflicting type modifiers (C++) 303
E2136: Constructor cannot have a return type specification (C++) 303
E2038: Cannot declare or define 'identifier' here: wrong namespace (C++) 304
E2154: Cannot define 'identifier' using a namespace alias (C++) 304
E2421: Cannot use local type 'identifier' as template argument (C++) 304
E2035: Conversions of class to itself or base class not allowed (C++) 304
E2139: Declaration missing ; (C++) 304
E2140: Declaration is not allowed here (C++) 304
E2141: Declaration syntax error (C++) 304
E2142: Base class 'class' contains dynamically dispatchable functions (C++) 304
E2143: Matching base class function 'function' has different dispatch number (C++) 305
E2144: Matching base class function 'function' is not dynamic (C++) 305
E2145: Functions 'function1' and 'function2' both use the same dispatch number (C++) 305
E2146: Need an identifier to declare (C++) 305
E2147: 'identifier' cannot start a parameter declaration (C++) 305
E2150: Type mismatch in default argument value (C++) 305
E2152: Default expression may not use local variables (C++) 306
E2153: Define directive needs an identifier (C++) 306
E2155: Too many default cases (C++) 306

xiii
RAD Studio

E2156: Default outside of switch (C++) 306


E2158: Operand of 'delete' must be non-const pointer (C++) 306
E2159: Trying to derive a far class from the huge base 'base' (C++) 306
E2160: Trying to derive a far class from the near base 'base' (C++) 306
E2161: Trying to derive a huge class from the far base 'base' (C++) 307
E2162: Trying to derive a huge class from the near base 'base' (C++) 307
E2163: Trying to derive a near class from the far base 'base' (C++) 307
E2164: Trying to derive a near class from the huge base 'base' (C++) 307
E2165: Destructor cannot have a return type specification (C++) 307
E2166: Destructor for 'class' is not accessible (C++) 307
E2167: 'function' was previously declared with the language 'language' (C++) 307
E2168: Division by zero (C++) 308
E2169: 'identifier' specifies multiple or duplicate access (C++) 308
E2170: Base class 'class' is included more than once (C++) 308
E2171: Body has already been defined for function 'function' (C++) 308
E2172: Duplicate case (C++) 308
E2175: Too many storage classes in declaration (C++) 308
E2176: Too many types in declaration (C++) 309
E2179: virtual specified more than once (C++) 309
E2007: Dispid only allowed in __automated sections (C++) 309
Divide error (C++) 309
E2182: Illegal parameter to __emit__ (C++) 309
E2183: File must contain at least one external declaration (C++) 309
E2184: Enum syntax error (C++) 310
E2185: The value for 'identifier' is not within the range of 'type-name' (C++) 310
E2186: Unexpected end of file in comment started on line 'number' (C++) 310
E2187: Unexpected end of file in conditional started on line 'number' (C++) 310
E2188: Expression syntax (C++) 310
E2190: Unexpected closing brace (C++) 311
E2189: extern variable cannot be initialized (C++) 311
E2344: Earlier declaration of 'identifier' (C++) 311
E2192: Too few parameters in call (C++) 311
E2193: Too few parameters in call to 'function' (C++) 311
E2194: Could not find file 'filename' (C++) 311
E2197: File name too long (C++) 311
E2195: Cannot evaluate function call (C++) 312
E2198: Not a valid expression format type (C++) 312
E2200: Functions may not be part of a struct or union (C++) 312
Floating point error: Divide by 0 OR Floating point error: Domain OR Floating point error: Overflow (C++) 312

xiv
RAD Studio

Floating point error: Stack fault (C++) 312


Floating point error: Partial loss of precision OR Floating point error: Underflow (C++) 312
E2201: Too much global data defined in file (C++) 313
E2203: Goto bypasses initialization of a local variable (C++) 313
E2204: Group overflowed maximum size: 'name' (C++) 313
E2206: Illegal character 'character' (0x'value') (C++) 313
E2207: Implicit conversion of 'type1' to 'type2' not allowed (C++) 313
E2208: Cannot access an inactive scope (C++) 313
E2209: Unable to open include file 'filename' (C++) 314
E2210: Reference member 'member' is not initialized (C++) 314
E2212: Function defined inline after use as extern (C++) 314
E2211: Inline assembly not allowed in inline and template functions (C++) 314
F1001: Internal code generator error (C++) 315
E2413: Invalid template declaration (C++) 315
E2070: Invalid use of namespace 'identifier' (C++) 315
E2214: Cannot have a 'non-inline function/static data' in a local class (C++) 315
E2215: Linkage specification not allowed (C++) 315
E2216: Unable to create turboc.$ln (C++) 315
E2218: Templates can only be declared at namespace or class scope (C++) 315
E2217: Local data exceeds segment size limit (C++) 316
E2219: Wrong number of arguments in call of macro 'macro' (C++) 316
E2220: Invalid macro argument separator (C++) 316
E2221: Macro argument syntax error (C++) 316
E2222: Macro expansion too long (C++) 316
E2223: Too many decimal points (C++) 316
E2224: Too many exponents (C++) 316
E2225: Too many initializers (C++) 316
E2226: Extra parameter in call (C++) 317
E2227: Extra parameter in call to function (C++) 317
E2228: Too many error or warning messages (C++) 317
E2233: Cannot initialize a class member here (C++) 317
E2232: Constant/Reference member 'member' in class without constructors (C++) 317
E2229: Member 'member' has the same name as its class (C++) 317
E2234: Memory reference expected (C++) 317
E2231: Member 'member' cannot be used without an object (C++) 318
E2235: Member function must be called or its address taken (C++) 318
O2237: DPMI programs must use the large memory model (C++) 318
E2238: Multiple declaration for 'identifier' (C++) 318
E2239: 'identifier' must be a member function (C++) 319

xv
RAD Studio

E2240: Conversion of near pointer not allowed (C++) 319


E2243: Array allocated using 'new' may not have an initializer (C++) 319
E2244: 'new' and 'delete' not supported (C++) 319
E2245: Cannot allocate a reference (C++) 319
E2309: Inline assembly not allowed (C++) 320
E2250: No base class to initialize (C++) 320
E2254: : expected after private/protected/private (C++) 320
E2255: Use :: to take the address of a member function (C++) 320
E2256: No : following the ? (C++) 320
E2257: , expected (C++) 320
E2258: Declaration was expected (C++) 320
E2259: Default value missing (C++) 321
E2260: Default value missing following parameter 'parameter' (C++) 321
E2263: Exception handling not enabled (C++) 321
E2264: Expression expected (C++) 321
E2266: No file names given (C++) 321
E2265: No file name ending (C++) 321
E2271: Goto statement missing label (C++) 321
E2272: Identifier expected (C++) 321
E2275: Opening brace expected (C++) 322
E2276: ( expected (C++) 322
E2274: < expected (C++) 322
E2277: Lvalue required (C++) 322
E2278: Multiple base classes not supported for Delphi classes (C++) 322
E2280: Member identifier expected (C++) 322
E2279: Cannot find default constructor to initialize member 'identifier' (C++) 323
E2310: Only member functions may be 'const' or 'volatile' (C++) 323
E2311: Non-virtual function 'function' declared pure (C++) 323
E2283: Use . or -> to call 'function' (C++) 323
E2284: Use . or -> to call 'member', or & to take its address (C++) 323
E2285: Could not find a match for 'argument(s)' (C++) 323
E2286: Overloaded function resolution not supported (C++) 324
E2287: Parameter 'number' missing name (C++) 324
E2288: Pointer to structure required on left side of -> or ->* (C++) 324
E2290: 'code' missing ] (C++) 324
E2291: brace expected (C++) 324
E2292: Function should return a value (C++) 324
E2293: ) expected (C++) 325
E2294: Structure required on left side of . or .* (C++) 325

xvi
RAD Studio

E2312: 'constructor' is not an unambiguous base class of 'class' (C++) 325


E2313: Constant expression required (C++) 325
E2296: Templates not supported (C++) 325
E2314: Call of nonfunction (C++) 325
E2321: Declaration does not specify a tag or an identifier (C++) 325
E2297: 'this' can only be used within a member function (C++) 326
E2316: 'identifier' is not a member of 'struct' (C++) 326
E2317: 'identifier' is not a parameter (C++) 326
E2319: 'identifier' is not a public base class of 'classtype' (C++) 326
E2320: Expression of scalar type expected (C++) 326
E2302: No type information (C++) 327
E2303: Type name expected (C++) 327
E2304: 'Constant/Reference' variable 'variable' must be initialized (C++) 327
E2305: Cannot find 'class::class' ('class'&) to copy a vector OR Cannot find 'class'::operator=('class'&) to 327
copy a vector (C++)
E2306: Virtual base classes not supported for Delphi classes (C++) 328
E2308: do statement must have while (C++) 328
E2322: Incorrect number format (C++) 328
E2324: Numeric constant too large (C++) 328
E2282: Namespace name expected (C++) 328
E2334: Namespace member 'identifier' declared outside its namespace (C++) 328
E2325: Illegal octal digit (C++) 329
E2329: Invalid combination of opcode and operands (C++) 329
E2327: Operators may not have default argument values (C++) 329
E2330: Operator must be declared as function (C++) 329
E2333: Class member 'member' declared outside its class (C++) 329
E2335: Overloaded 'function name' ambiguous in this context (C++) 329
E2339: Cannot overload 'main' (C++) 330
E2336: Pointer to overloaded function 'function' doesn't match 'type' (C++) 330
E2337: Only one of a set of overloaded functions can be "C" (C++) 330
E2338: Overlays only supported in medium, large, and huge memory models (C++) 330
E2340: Type mismatch in parameter 'number' (C++) 330
E2341: Type mismatch in parameter 'number' in call to 'function' (C++) 331
E2342: Type mismatch in parameter 'parameter' (C++) 331
E2343: Type mismatch in parameter 'parameter' in call to 'function' (C++) 331
E2345: Access can only be changed to public or protected (C++) 331
E2349: Nonportable pointer conversion (C++) 331
E2350: Cannot define a pointer or reference to a reference (C++) 332
E2352: Cannot create instance of abstract class 'class' (C++) 332

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

E2047: Bad 'directive' directive syntax (C++) 345


E2049: Class type 'type' cannot be marked as __declspec(delphireturn) (C++) 345
E2052: Dynamic function 'function' conflicts with base class 'class' (C++) 345
E2057: Exception specification not allowed here (C++) 345
E2058: Exception handling variable may not be used here (C++) 346
E2065: Using namespace symbol 'symbol' conflicts with intrinsic of the same name (C++) 346
E2067: 'main' must have a return type of int (C++) 346
E2073: Nothing allowed after pragma option pop (C++) 346
E2091: Functions cannot return arrays or functions (C++) 346
E2093: Operator 'operator' not implemented in type 'type' for arguments of the same type (C++) 346
E2094: Operator 'operator' not implemented in type 'type' for arguments of type 'type' (C++) 346
E2097: Explicit instantiation only allowed at file or namespace scope (C++) 347
E2098: Explicit specialization declarator "template<>" now required (C++) 347
E2099: Explicit specialization only allowed at file or namespace scope (C++) 347
E2101: 'export' keyword must precede a template declaration (C++) 347
E2103: Explicit instantiation must be used with a template class or function (C++) 347
E2106: Explicit specialization must be used with a template class or function (C++) 347
E2112: Unknown unit directive: 'directive' (C++) 347
E2118: Bit fields must have integral type (C++) 348
E2120: Cannot call 'main' from within the program (C++) 348
E2125: Compiler could not generate copy constructor for class 'class' OR Compiler could not generate 348
default constructor for class 'class' OR Compiler could not generate operator = for class 'class' (C++)
E2130: Circular property definition (C++) 348
E2131: Objects of type 'type' cannot be initialized with { } (C++) 348
E2148: Default argument value redeclared for parameter 'parameter' (C++) 348
E2149: Default argument value redeclared (C++) 349
E2151: Type mismatch in default value for parameter 'parameter' (C++) 349
E2157: Deleting an object requires exactly one conversion to pointer operator (C++) 349
E2173: Duplicate handler for 'type1', already had 'type2' (C++) 349
E2174: The name handler must be last (C++) 349
E2177: Redeclaration of #pragma package with different arguments (C++) 350
E2178: VIRDEF name conflict for 'function' (C++) 350
E2180: Dispid number already used by identifier (C++) 350
E2181: Cannot override a 'dynamic/virtual' with a 'dynamic/virtual' function (C++) 350
E2202: Goto into an exception handler is not allowed (C++) 350
E2205: Illegal type type in __automated section (C++) 350
E2242: Specifier requires Delphi style class type (C++) 351
E2247: 'member' is not accessible (C++) 351
E2248: Cannot find default constructor to initialize array element of type 'class' (C++) 351

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

Initializing enumeration with type (C++) 360


<name> is not a valid identifier (C++) 361
Example for "Temporary used ..." error messages (C++) 361
Application is running (C++) 361
Printf/Scanf floating-point formats not linked (C++) 361
W8000: Ambiguous operators need parentheses (C++) 362
W8060: Possibly incorrect assignment (C++) 362
W8002: Restarting compile using assembly (C++) 362
W8003: Unknown assembler instruction (C++) 362
W8052: Base initialization without a class name is now obsolete (C++) 362
E2117: Bit fields must be signed or unsigned int (C++) 363
W8064: Call to function with no prototype (C++) 363
W8065: Call to function 'function' with no prototype (C++) 363
W8009: Constant is long (C++) 363
W8008: Condition is always true OR W8008 Condition is always false (C++) 363
W8012: Comparing signed and unsigned values (C++) 364
W8010: Continuation character \ found in // comment (C++) 364
W8080: 'identifier' is declared but never used (C++) 364
W8014: Declaration ignored (C++) 365
W8068: Constant out of range in comparison (C++) 365
W8016: Array size for 'delete' ignored (C++) 365
W8082: Division by zero (C++) 365
W8018: Assigning 'type' to 'enumeration' (C++) 365
W8006: Initializing 'identifier' with 'identifier' (C++) 366
W8001: Superfluous & with function (C++) 366
W8020: 'identifier' is declared as both external and static (C++) 366
W8007: Hexadecimal value contains more than three digits (C++) 366
W8024: Base class 'class1' is also a base class of 'class2' (C++) 366
W8022: 'function1' hides virtual function 'function2' (C++) 367
W8023: Array variable 'identifier' is near (C++) 367
W8061: Initialization is only partially bracketed (C++) 367
W8038: constant member 'identifier' is not initialized (C++) 367
W8071: Conversion may lose significant digits (C++) 367
W8043: Macro definition ignored (C++) 368
W8017: Redefinition of 'x' is not identical (C++) 368
W8079: Mixing pointers to different 'char' types (C++) 368
W8067: Both return and return with a value used (C++) 368
W8048: Use qualified name to access member type 'identifier' (C++) 368
W8039: Constructor initializer list ignored (C++) 368

xxii
RAD Studio

W8040: Function body ignored (C++) 369


W8042: Initializer for object 'x' ignored (C++) 369
W8044: #undef directive ignored (C++) 369
W8037: Non-const function 'function' called for const object (C++) 369
W8051: Non-volatile function 'function' called for volatile object (C++) 369
W8019: Code has no effect (C++) 370
W8057: Parameter 'parameter' is never used (C++) 370
W8070: Function should return a value (C++) 370
W8047: Declaration of static function function ignored (C++) 370
W8041: Negating unsigned value (C++) 370
W8054: Style of function definition is now obsolete (C++) 371
W8025: Ill-formed pragma (C++) 371
W8063: Overloaded prefix operator 'operator' used as a postfix operator (C++) 371
W8015: Declare 'type' prior to use in prototype (C++) 371
W8069: Nonportable pointer conversion (C++) 372
W8066: Unreachable code (C++) 372
W8029: Temporary used for parameter '???' (C++) 372
W8031: Temporary used for parameter 'parameter' OR W8029 Temporary used for parameter 'number' OR 372
W8030 Temporary used for parameter 'parameter' in call to 'function' OR W8032 Temporary used for
parameter 'number' in call to 'function' (C++)
W8032: Temporary used for parameter 2 in call to '???' (C++) 373
W8028: Temporary used to initialize 'identifier' (C++) 373
W8074: Structure passed by value (C++) 373
W8011: Nonportable pointer comparison (C++) 374
W8075: Suspicious pointer conversion (C++) 374
W8059: Structure packing size has changed (C++) 374
W8045: No declaration for function 'function' (C++) 374
W8073: Undefined structure 'structure' (C++) 375
W8013: Possible use of 'identifier' before definition (C++) 375
W8004: 'identifier' is assigned a value that is never used (C++) 375
W8081: Void functions may not return a value (C++) 375
W8078: Throw expression violates exception specification (C++) 376
W8021: Handler for 'type1' hidden by previous handler for 'type2' (C++) 376
W8056: Integer arithmetic overflow (C++) 376
W8035: User-defined message (C++) 376
W8049: Use '> >' for nested templates Instead of '>>' (C++) 376
W8026: Functions with exception specifications are not expanded inline (C++) 377
W8058: Cannot create pre-compiled header: 'reason' (C++) 377
W8046: Pragma option pop with no matching option push (C++) 377
W8050: No type OBJ file present; disabling external types option. (C++) 377

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

W8105: Reference/Constant member 'identifier' in class without constructors (C++) 385


W8107: Type name expected (C++) 385
W8112: Unresolved dependencies in expression (C++) 385
C++ Language Guide 385
C++ Specifics 385
Keywords, Alphabetical Listing 513
Keywords, By Category 579
Language Structure 586
Lexical Elements 660
The Preprocessor 687
C Runtime Library Reference 711
alloc.h 712
assert.h 730
conio.h 732
ctype.h 766
delayimp.h 787
direct.h 790
dirent.h 792
dir.h 799
dos.h 818
errno.h 831
except.h 838
fastmath.h 842
fcntl.h 844
float.h 853
io.h 864
limits.h 913
locale.h 915
malloc.h 920
math.h 921
mem.h 959
new.h 968
process.h 971
setjmp.h 993
share.h 996
signal.h 997
stdarg.h 1003
stddef.h 1004
stdio.h 1006

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

Win32 Developer's Guide 1217


Component Writer's Guide 1217
Creating a graphic component 1218
Creating events 1231
Creating methods 1241
Creating properties 1245
Customizing a grid 1258
Extending the IDE 1276
Handling messages 1298
Introduction to component creation 1310
Making a control data aware 1325
Making components available at design time 1339
Making a dialog box a component 1358
Modifying an existing component 1363
Object-oriented programming for component writers 1367
Using graphics in components 1376
Developing COM-based Applications 1381
COM basics 1382
Creating an Active Server Page 1400
Using ActiveX controls 1406
Creating COM clients 1418
Creating simple COM servers 1427
Working with type libraries 1441
Developing Database Applications 1469
Working with ADO components 1470
Connecting to databases 1495
Creating multi-tiered applications 1510
Creating reports with Rave Reports 1551
Designing database applications 1556
Understanding datasets 1573

xxvi
RAD Studio

Using the Borland Database Engine 1637


Using client datasets 1700
Using data controls 1743
Using decision support components 1779
Using provider components 1805
Using dbExpress Components 1821
Using XML in database applications 1840
Working with field components 1849
Programming with Delphi 1879
Building applications, components, and libraries 1879
Creating international applications 1920
Delphi programming fundamentals 1935
Deploying applications 1938
Developing the application user interface 1955
Exception handling 2014
Types of controls 2031
Understanding the component library 2053
Using the object model 2062
Using the VCL/RTL 2082
Working with components 2142
Working with controls 2149
Working with graphics and multimedia 2169
Working with packages and components 2208
Writing multi-threaded applications 2224
Writing Internet Applications 2243
Creating Internet server applications 2243
Using IntraWeb (VCL for the Web) 2254
Using Web Broker 2261
Using Web Services 2289
Using WebSnap 2310
Working with sockets 2335
Working with XML documents 2351

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

1.1 Debugging C++ Applications with CodeGuard


Error Reporting
CodeGuard provides runtime debugging for C++ applications developed with RAD Studio. CodeGuard reports errors that are not
1
caught by the compiler because they do not violate syntax rules. CodeGuard tracks runtime libraries with full support for
multithreaded applications.

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:

• Memory and Resource Use


• Function Call Validation
CodeGuard Warnings ( see page 10) CodeGuard can report situations where your application may access memory
beyond a buffer's maximum size. Warnings are available for three types of
runtime library functions.

1.1.1 CodeGuard Errors


CodeGuard reports four types of runtime errors.

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:

• Access in freed memory


• Access in uninitialized stack
• Access in invalid stack
Exception Errors ( see page 5) When a system exception occurs, CodeGuard reports the runtime error using
information provided by the operating system. If possible, the CodeGuard log
shows where your application caused the exception. CodeGuard does not trap or
redirect the exception or otherwise interfere with normal program behavior.
The following exceptions illustrate how CodeGuard exception reporting:

• General Protection Fault


• Divide by zero
Function Failure Errors ( see page 6) CodeGuard reports function calls that fail, as indicated by their return value.
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.

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

1.1.1.1 Access Errors


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:

• Access in freed memory


• Access in uninitialized stack
• Access in invalid stack
Access In Freed Memory
In the following example, CodeGuard identifies the line where an invalid access occurrs. CodeGuard then indicates where the
memory block was allocated and subsequently freed.
Error 00004. 0x100430 (Thread 0xFFF87283):
Access in freed memory: Attempt to access 19 byte(s) at 0x00B423DC.
strcpy(0x00B423DC, 0x004091CA ["Copy to free block"])
| lang.cpp line 106:
|
| free(buf_h);
|> strcpy(buf_h, "Copy to free block");
|
| //-----------------------//
Call Tree:
0x004011F1(=LANG.EXE:0x01:0001F1) lang.cpp#106
0x00407EE5(=LANG.EXE:0x01:006EE5)

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)

The memory block (0x00B423DC) was freed with free


| lang.cpp line 105:
| //-------------//
|
|> free(buf_h);
| strcpy(buf_h, "Copy to free block");

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)

1.1.1.2 Exception Errors


When a system exception occurs, CodeGuard reports the runtime error using information provided by the operating system. If
possible, the CodeGuard log shows where your application caused the exception. CodeGuard does not trap or redirect the
exception or otherwise interfere with normal program behavior.

The following exceptions illustrate how CodeGuard exception reporting:

• General Protection Fault


• Divide by zero
General Protection Fault
In the following example, CodeGuard provides information on a general protection fault (Intel system exception 0xD). In addition
to the location of the source code that caused the exception, the log shows where the memory was allocated and subsequently
freed. The reported incorrect value is a result of accessing a byte pattern that CodeGuard uses to identify invalid memory
locations.
Error 00003. 0x400003 (Thread 0x0090):
Exception 0xC0000005: Access violation at 0x80828082.
| gpfault.c line 32:
| {¬
| q = p[3];

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)

The memory block (0x008322A4) was freed with free


| 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)
Divide By Zero
In the following example, CodeGuard identifies the location in source code where division by zero (Intel system exception 0x0)
occurred.
Error 00001. 0x400000 (Thread 0x008B):
Exception 0xC0000094:
| ZERODIV.C line 9:
| {¬
| x = 1;
|> return x / y;
| }
|
Call Tree:
0x0040109C(=ZERODIV.EXE:0x01:00009C) ZERODIV.C#9
0x00406321(=ZERODIV.EXE:0x01:005321)

1.1.1.3 Function Failure Errors


CodeGuard reports function calls that fail, as indicated by their return value.

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)

1.1.1.4 Resource Errors


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: 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 file handle (0x00000003) was closed with close


| lang.cpp line 176:
| //----------------------//
| int i = open("lang.cpp", 0);
|> close(i);
| read (i, buffer, 5);
|
Call Tree:
0x00401477(=LANG.EXE:0x01:000477) lang.cpp#176
1 0x00407EED(=LANG.EXE:0x01:006EED)
Resource Type Mismatch
In the following example, a memory block that was allocated with the new[] operator, and should therefore be released with the
delete[] operator, is instead released with a call to the free function.
Error 00024. 0x350010 (Thread 0xFFF840F1):
Resource type mismatch: a(n) memory block was expected.
free(0x00B42464)
| lang.cpp line 188:
| //---------------//
| char * ss = new char[21];
|> free(ss);
|
| #ifdef __WIN32__
Call Tree:
0x0040149F(=LANG.EXE:0x01:00049F) lang.cpp#188
0x00407EED(=LANG.EXE:0x01:006EED)

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.

Error 00001. 0x340010 (Thread 0x0062):


Resource from different RTL:

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)

1.1.2 CodeGuard Overview


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:

• Memory and Resource Use


• Function Call Validation
Memory and Resource Use
CodeGuard checks for faulty memory use, improper memory allocation or deallocation, invalid file streams or handles, and
resource leaks caused by improper use of file streams or handles. CodeGuard verifies pointer dereferencing and pointer
arithmetic. CodeGuard can report an error if your program tries to access memory or resources that have already been released.

Function Call Validation


CodeGuard verifies function arguments and reports function failure as indicated by the return value of the function. It validates
Windows resource handles used in function calls.

See Also
CodeGuard Errors ( see page 3)

CodeGuard Warnings ( see page 10)

Using CodeGuard ( see page 48)

9
CodeGuard Warnings RAD Studio 1.1 Debugging C++ Applications with

1.1.3 CodeGuard Warnings


CodeGuard can report situations where your application may access memory beyond a buffer's maximum size. Warnings are
available for three types of runtime library functions.

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.1.3.1 Memory Block Comparison Warnings


Each of the following functions has a parameter that determines the maximum number of bytes it compares:

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.1.3.2 Pathname Merging and Splitting Warnings


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
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.

1.1.3.3 String Comparison Warnings


Each of the following functions has a parameter that determines the maximum number of bytes it compares:

• 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

1.2 Developing Database Applications for the


Win32 Platform
The Borland Database Engine (BDE) has been deprecated, so it will not be enhanced. For instance, BDE will never have
1
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 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:

• Industry standards compliance


• Entry level SQL-92
• Unicode storage of character data
• Unicode-based collation key support for sorting and
indexing
• dbExpress 4 drivers for win32 Delphi and C++
• ADO.NET 2.0 providers for .NET
• JDBC for Java
• JavaBean data access components for Java
• XA/JTA Distributed transactions for Java
• High performance and scalability for demanding online
transaction processing (OLTP) and decision support
system (DSS) applications
• Delphi, C#, and VB.NET stored procedures and triggers...
more ( see page 24)
dbExpress Framework ( see page 26) The dbExpress framework (DBX framework) is a set of abstract classes provided
in the unit DBXCommon. Applications can interface with the framework in several
ways: using the framework directly for both native and managed applications,
and using the dbExpress VCL components that are layered on top of the
framework for both native and managed applications.
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... more ( see
page 26)
dbExpress Framework Compatibility ( see page 27) Some dbExpress software developed prior to the dbExpress driver framework
(DBX driver framework) has been modified to work with the DBX driver
framework. As a result of these changes, some compatibility issues arise.

1.2.1 dbGo Overview


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

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.

The main dbGo components are:

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)

1.2.2 BDE Overview


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 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

using the BDE.

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.

The main BDE components are:

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)

Borland Database Engine ( see page 1946)

1.2.3 dbExpress Components


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 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)

Using dbExpress Datasets ( see page 1823)

Configuring TSQL Connection ( see page 53)

Using Data Explorer to get Connection Information ( see page 52)

1.2.4 Getting Started with InterBase Express


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.

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.

To set up a database connection:

1. Drop an IBDatabase component onto a form or data module.


2. Fill out the DatabaseName property. For a local connection, this is the drive, path, and filename of the database file. Set the
Connected property to true.
3. Enter a valid username and password and click OK to establish the database connection.
Warning: Tip: You can store the username and password in the IBDatabase component's Params property by setting the
LoginPrompt property to false after logging in. For example, after logging in as the system administrator and setting the
LoginPrompt property to false, you may see the following when editing the Params property:

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:

1. Set up an IBDatabase connection as described above.


2. Drop an IBTransaction component onto the form or data module
3. Set the DefaultDatabase property to the name of your IBDatabase component.
4. Set the Active property to true to start the transaction.
IBX dataset components
There are a variety of dataset components from which to choose with IBX, each having their own characteristics and task
suitability:
IBTable
Use an TIBTable component to set up a live dataset on a table or view without having to enter any SQL statements.
IBTable components are easy to configure:

18
1.2 Developing Database Applications for RAD Studio Getting Started with InterBase Express

1. Add an IBTable component to your form or data module.


2. Specify the associated database and transaction components.
3. Specify the name of the relation from the TableName drop-down list.
4. Set the Active property to true.
IBQuery
Use an TIBQuery component to execute any InterBase DSQL statement, restrict your result set to only particular columns and
rows, use aggregate functions, and join multiple tables. 1
IBQuery components provide a read-only dataset, and adapt well to the InterBase client/server environment. To set up an
IBQuery component:
1. Set up an IBDatabase connection as described above.
2. Set up an IBTransaction connection as described above.
3. Add an IBQuery component to your form or data module.
4. Specify the associated database and transaction components.
5. Enter a valid SQL statement for the IBQuery's SQL property in the String list editor.
6. Set the Active property to true
IBDataSet
Use an TIBDataSet component to execute any InterBase DSQL statement, restrict your result set to only particular columns and
rows, use aggregate functions, and join multiple tables. IBDataSet components are similar to IBQuery components, except
that they support live datasets without the need of an IBUpdateSQL component.
The following is an example that provides a live dataset for the COUNTRY table in employee.gdb:
1. Set up an IBDatabase connection as described above.
2. Specify the associated database and transaction components.
3. Add an IBDataSet component to your form or data module.
4. Enter SQL statements for the following properties:

SelectSQL SELECT Country, Currency FROM Country


RefreshSQL SELECT Country, Currency FROM Country WHERE Country = :Country
ModifySQL UPDATE Country SET Country = :Country, Currency = :Currency WHERE Country = :Old_Country
DeleteSQL DELETE FROM Country WHERE Country = :Old_Country
InsertSQL INSERT INTO Country (Country, Currency) VALUES (:Country, :Currency)

1. Set the Active property to true.


2.
Note: Note: Parameters and fields passed to functions are case-sensitive in dialect 3. For example,

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:

1. Set up an IBDatabase connection as described above.


2. Put an IBSQL component on the form or data module and set its Database property to the name of the database.
3. Add an SQL statement to the SQL property string list editor, for example:
1 SELECT GEN_ID(MyGenerator, 1) FROM RDB$DATABASE
IBUpdateSQL

Use an TIBUpdateSQL component to update read-only datasets. You can update IBQuery output with an IBUpdateSQL
component:

1. Set up an IBQuery component as described above.


2. Add an IBUpdateSQL component to your form or data module.
3. Enter SQL statements for the following properties: DeleteSQL, InsertSQL, ModifySQL, and RefreshSQL.
4. Set the IBQuery component's UpdateObject property to the name of the IBUpdateSQL component.
5. Set the IBQuery component's Active property to true.
IBSQLMonitor
Use an TIBSQLMonitor component to develop diagnostic tools to monitor the communications between your application and the
InterBase server. When the TraceFlags properties of an IBDatabase component are turned on, active TIBSQLMonitor
components can keep track of the connection's activity and send the output to a file or control.
A good example would be to create a separate application that has an TIBSQLMonitor component and a Memo control. Run this
secondary application, and on the primary application, activate the TraceFlags of the IBDatabase component. Interact with the
primary application, and watch the second's memo control fill with data.
IBDatabaseInfo
Use an TIBDatabaseInfo component to retrieve information about a particular database, such as the sweep interval, ODS
version, and the user names of those currently attached to this database.
For example, to set up an IBDatabaseInfo component that displays the users currently connected to the database:
1. Set up an IBDatabase connection as described above.
2. Put an IBDatabaseInfo component on the form or data module and set its Database property to the name of the database.
3. Put a Memo component on the form.
4. Put a Timer component on the form and set its interval.
5. Double click on the Timer's OnTimer event field and enter code similar to the following:
Memo1.Text := IBDatabaseInfo.UserNames.Text; // Delphi example
Memo1->Text = IBDatabaseInfo->UserNames->Text; // C++ example
IBEvents

Use an IBEvents component to register interest in, and asynchronously handle, events posted by an InterBase server.

To set up an IBEvents component:

1. Set up an IBDatabase connection as described above.


2. Put an IBEvents component on the form or data module and set its Database property to the name of the database.
3. Enter events in the Events property string list editor, for example:
IBEvents.Events.Add('EVENT_NAME'); // Delphi example
IBEvents->Events->Add("EVENT_NAME"); // C++ Example
1. 4. Set the Registered property to true.

20
1.2 Developing Database Applications for RAD Studio Getting Started with InterBase Express

2. InterBase Administration Components


If you have InterBase installed, you can use the InterBase Administration components, which allow you to use access the
powerful InterBase Services API calls.
The components are located on the InterBase Admin tab of the IDE and include:

TIBConfigService

TIBBackupService

TIBRestoreService
1
TIBValidationService

TIBStatisticalService

TIBLogService

TIBSecurityService

TIBLicensingService

TIBServerProperties

TIBInstall

TIBUnInstall

Note: You must install InterBase to use these features.

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

Use an TIBLogService object to create a log file.

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

Use an TIBLicensingService component to add or remove InterBase software activation certificates.

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

Use an TIBUnInstall component to set up an uninstall component.

1.2.5 dbExpress 4 Feature Overview


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
• 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.

dbExpress Metadata Improvements


New metadata providers for 9 different database backends are written completely in Delphi. Full source code to all metadata
providers is included in the product.

Metadata read and write capabilities


Each provider is composed of a metadata reader and metadata writer implementation contained inside the dbExpress driver
packages. The separate metadata readers and writers that were in the DbxReadOnlyMetaData and DbxMetaData packages no
longer exist.

Provider based approach


The metadata providers are detached from the driver, so that one metadata provider can be used for multiple driver
implementations as long as the database backend is the same. Data Explorer also takes advantage of metadata providers to
provide metadata support for other database drivers.

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

TDBXPropertyNames.MetaDataPackageLoader in the dbxdrivers.ini files that can be set to a TDBXCommandFactory object.


This command factory implementation creates a TDBXCommand that can execute metadata commands. This approach allows
multiple driver implementations for a specific database backend to use the same metadata provider. Data Explorer also takes
advantage of this architecture to provide dbExpress 4 structured metadata for drivers from other vendors. The decoupling of
driver and metadata provider also benefits "thin" driver implementations. If metadata commands can be serviced on a server,
there is no need to have the metadata provider logic on the client.

Provider source directory


1
All database source is now contained in the following installation location:
C:\Program FIles \ CodeGear\ RAD Studio \ 6.0 \ source \ database

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.

Command line properties


New units have been added to the DbxDynalinkDriver package for all 8 of Dynalink drivers:

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

1.2.6 Blackfish SQL Overview


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:

• Industry standards compliance


• Entry level SQL-92
• Unicode storage of character data
• Unicode-based collation key support for sorting and indexing
• dbExpress 4 drivers for win32 Delphi and C++
• ADO.NET 2.0 providers for .NET

24
1.2 Developing Database Applications for RAD Studio Blackfish SQL Overview

• JDBC for Java


• JavaBean data access components for Java
• XA/JTA Distributed transactions for Java
• High performance and scalability for demanding online transaction processing (OLTP) and decision support system (DSS)
applications
• Delphi, C#, and VB.NET stored procedures and triggers for Windows
• Java-stored procedures and triggers 1
• Zero-administration, single assembly or single-jar deployment
• Database incremental backup and failover
Blackfish SQL DataStore
Blackfish SQL is the name of the product, its tools, and of the file format. Within this product, there is a datastore package that
includes a DataStore class, as well as several additional classes that have DataStore as part of their names.

Blackfish SQL Compatibility


Blackfish SQL for Windows and Blackfish SQL for Java are highly compatible with one another. The database file format is
binary-compatible between Blackfish SQL for Windows and Blackfish SQL for Java. In addition, database clients and servers are
interchangeable. Windows clients can connect to Java servers and Java clients can connect to Windows servers.

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:

• ISQL SQL Command Line Interpreter


• High Availability features, including incremental backup and failover
• Graphical tooling for administrative capabilities
• Access to file and object streams
• Tracking and resolving of row-level insert, update and delete operations
• Access to the Blackfish SQL File System directory
Blackfish SQL Connectivity
This section provides an overview of the connection drivers provided for Blackfish SQL for Windows and Blackfish SQL for Java,
respectively. For instructions on using the drivers to connect to a Blackfish SQL database, see the Blackfish SQL Developer's
Guide, Establishing Connections section

Blackfish SQL for Windows Connectivity


Blackfish SQL for Windows provides the following connection drivers:

• 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.

Blackfish SQL for Java Connectivity


Blackfish SQL for Java provides the following JDBC connection drivers:

• 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

1.2.7 dbExpress Framework


The dbExpress framework (DBX framework) is a set of abstract classes provided in the unit DBXCommon. Applications can
interface with the framework in several ways: using the framework directly for both native and managed applications, and using
the dbExpress VCL components that are layered on top of the framework for both native and managed applications.

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.

Here are some of the key features of the DBX framework:

• 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)

Deploying dbExpress Database Applications ( see page 1942)

1.2.8 dbExpress Framework Compatibility


Some dbExpress software developed prior to the dbExpress driver framework (DBX driver framework) has been modified to
work with the DBX driver framework. As a result of these changes, some compatibility issues arise.

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.

Here is a list of known compatibility issues:

• 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)

Deploying dbExpress Database Applications ( see page 1942)

28
1.3 Developing Interoperable Applications RAD Studio Developing COM Applications

1.3 Developing Interoperable Applications


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 1
Objects), ActiveX controls, or ActiveForms.

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:

• COM Technologies Overview


• COM Interfaces
• COM Servers
• COM Clients

1.3.1 Developing COM Applications


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:

• COM Technologies Overview


• COM Interfaces
• COM Servers
• COM Clients
COM Technologies Overview
COM is a language-independent software component model that enables interaction between software components and
applications running on a Windows platform. The most important 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).

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.

Key aspects of COM interfaces are as follows:

• 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.

The IUnknown interface


All COM objects must support the fundamental interface, called IUnknown, a typedef to the base interface type IInterface.
IUnknown contains the following routines:

• QueryInterface: Provides pointers to other interfaces that the object supports.


• AddRef and Release: Simple reference counting methods that keep track of the object’s lifetime so that an object can delete
itself when the client no longer needs its service.
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

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.

COM Interface Pointers


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
1
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 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.

As a minimum, a COM server must perform the following:

• 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.

Automation is defined by two major points:

• 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

1.4 Developing Reports for Your Win32


Applications
RAD Studio ships with Rave Reports from Nevrona. Using the report components, you can build full-featured reports for your
1
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.

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.

1.4.1 Using Rave Reports in RAD Studio


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.

Creating New Reports in RAD Studio


You can include reports in RAD Studio just as you would other 3rd-party components. The report is stored as a separate Rave
Report object. You can reference the report in other applications that need to call or generate that report. When you create a
new application, you can include the report object by adding a reference to it in the Project Manager. Rave Reports also provide
the capability to connect your report object to a datasource, which allows your application to build the report dynamically, based
on current database information.

See Also
Adding Rave Reports to RAD Studio ( see page 81)

35
VCL Overview RAD Studio 1.5 Developing Applications with VCL

1.5 Developing Applications with VCL


Components
1 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.

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

1.5.1 VCL Overview


This section introduces:

• 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.

Other VCL Classes


Classes that are not components (that is, classes that descend from System::TObject but not TComponent) are also used for a
variety of tasks. Typically, these classes are used for accessing system objects (such as a file or the clipboard) or for transient
tasks (such as storing data in a list). You cannot create instances of these classes at designtime, although they are sometimes
created by the components that you add in the Form Designer.

Working With Components


Many components are provided in the IDE on the Component Palette. You select components from the Component Palette
and place them onto a form or data module. You design the user interface of an application by arranging the visual components
such as buttons and list boxes on a form. You can also place nonvisual components, such as data access components, on either
a form or a data module. At first, Delphi’s components appear to be just like any other classes. But there are differences between
components in Delphi and the standard class hierarchies that many programmers work with. Some differences are:

• All Delphi components descend from TComponent.


• Components are most often used as is. They are changed through their properties, rather than serving as base classes to be
subclassed to add or change functionality. When a component is inherited, it is usually to add specific code to existing event
handling member functions.
• Components can only be allocated on the heap, not on the stack.
• Properties of components contain runtime type information.
• Components can be added to the Component Palette in the IDE and manipulated on a form.
Components often achieve a better degree of encapsulation than is usually found in standard classes. For example, consider a
dialog box containing a button. In a Windows program developed using VCL components, when a user clicks the button, the
system generates a WM_LBUTTONDOWN message. The program must catch this message (typically in a switch statement, a
message map, or a response table) and send it to a routine that will execute in response to the message. Most Windows
messages (VCL applications) are handled by Delphi components. When you want to respond to a message or system event,
you only need to provide an event handler.

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)

Building a VCL Forms "Hello world" Application ( see page 101)

Organizing Actions for Toolbars and Menus ( see page 1992)

1.5.2 Using TEncoding for Unicode Files


Reading and Writing in the Old Format
Many Delphi applications will need to continue to interact with other applications or datasources, many of which can only handle
data in ANSI or ASCII. For this reason, the defaults for the TStrings methods will write the files ANSI encoded based on the
active code page and will read the files based on whether or not the file contains a Byte Order Mark (BOM).

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).

Using the new encodings


You may want to read/write text data using the TStrings class a loss-less Unicode format, be that Little-Endian UTF16,
Big-Endian UTF16, UTF8, UTF7 so on. The TEncoding class is very similar in methods and functionality that you can find in the

38
1.5 Developing Applications with VCL RAD Studio Components Available Only on Specific OS

System.Text.Encoding class in the .NET Framework.


var
S: TStrings;
begin
S: TStringList.Create();
{ ... }
S.SaveToFile('config.txt', TEncoding UTF8);
Without the extra parameter, ‘config.txt’ would simply be converted and written out as ANSI encoded based on the current active
codepage. You do not need to change the read code since TStrings will automatically detect the encoding based on the BOM 1
and do the right thing.

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.

Here is a list of codepage identifiers (MSDN).:

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)

1.5.3 Components Available Only on Specific OS


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

39
Components Available Only on Specific OS RAD Studio 1.5 Developing Applications with VCL

Component Windows Windows XP Windows Vista


2000
CheckBox, Checked, and FixedWidth properties for THeaderSection No No Yes
CheckBoxes, NoSizing and OverFlow properties to THeaderControl No No Yes
Group support for TListView No Yes Yes
ImageList support for TButton No Yes Yes
1
Platform Default Style for ActionMenus/ActionToolBars Yes, Yes, XP style Yes, Vista style
standard
style
Support of transparent PNGs in TImage Yes Yes Yes
TBalloonHints, Vista style No Yes, with themes Yes
enabled
TButton.ElevationRequired No No Yes
TButton.CommandLink No No Yes
TButton.SplitButton No No Yes
TComboBox.TextHint No No Yes
TEdit.TextHint No No Yes
TGlassFrame No No Yes
TImageList.ColorDepth := cd32Bit No Yes, with themes Yes, with themes
enabled enabled
TLabel.GlowSize (only on TGlassFrame) No No Yes
TLinkLabel No (plain text Yes, with themes Yes, with themes
only) enabled enabled
TListView collapsible groups No No Yes
TProgessBar colors and progress automatically set for state by the No Yes, with themes Yes
engines enabled
TProgressBar.SmoothReverse No No Yes
TStaticText support HTML links in the textfield. AllowLInks property No Yes, with themes Yes
enabled
TTaskDialog No No Yes

See Also
Building a VCL Forms Application ( see page 99)

Building a VCL Forms "Hello world" Application ( see page 101)

40
1.6 Developing Web Applications with RAD Studio Win32 Web Applications Overview

1.6 Developing Web Applications with WebSnap


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. 1
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
Win32 Web Applications Overview ( see page 41) This section covers:

• Web Application Support


• Web Broker Overview
• Web Snap Overview
• Debugging With the Web Application Debugger
For more detailed information on web applications, please
see the Win32 Developers Guide in the Reference section
of this Help system.

1.6.1 Win32 Web Applications Overview


This section covers:

• Web Application Support


• Web Broker Overview
• Web Snap Overview
• Debugging With the Web Application Debugger
For more detailed information on web applications, please see the Win32 Developers Guide in the Reference section of this Help
system.
Win32 Web Application Support
The following types of web applications will be supported in RAD Studio.

• 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.

Web Application Debugger


Selecting this type of application sets up an environment for developing and testing Web server applications. This type of
1 application is not intended for deployment.

Web Broker Overview


Web Broker components, located on the Internet tab of the Component Palette, enable you to create event handlers that are
associated with a specific Uniform Resource Identifier (URI). When processing is complete, you can construct HTML or XML
documents within your program and transfer them to the client. You can use Web Broker components for cross-platform
application development.

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.

Web Snap Overview


Note: 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/.

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.

Debugging With the Web Application Debugger


The Web Application Debugger provides an easy way to monitor HTTP requests, responses, and response times. The Web
Application Debugger takes the place of the Web server. Once you have debugged your application, you can convert it to one of
the supported types of Web application and install it with a commercial Web server.

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.

Launching your application with the Web Application Debugger


Once you have developed your Web server application, you can run and debug it using the Web Application Debugger. You can
set breakpoints in it just like any other executable. When you run your application, it displays the console window of the COM
server that is your Web server application. Once you start your application and run the Web App Debugger, the ServerInfo page
is displayed in your default browser, and you can select your application from a drop-down list. Once you have selected your
application, click the Go button. This launches your application in the Web Application Debugger, which provides you with details
on request and response messages that pass between your application and the Web Application Debugger.

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)

Building a WebSnap "Hello world" Application ( see page 149) 1


Debugging a WebSnap Application Using the Web Application Debugger ( see page 150)

Converting Your Application to Another Type of Web Server Application ( see page 2245)

Using IntraWeb ( see page 2254)

43
Web Services Overview RAD Studio 1.7 Developing Web Services with Win32

1.7 Developing Web Services with Win32


Applications
1 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.

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)

1.7.1 Web Services Overview


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 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

1.8 Developing Windows Applications


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. 1
Topics
Name Description
Windows Overview ( see page 45) The Windows platform provides several ways to help you create and build
applications. The most common types of Windows applications are:

• GUI Applications
• Console Applications
• Service Applications
• Packages and DLLs

1.8.1 Windows Overview


The Windows platform provides several ways to help you create and build applications. The most common types of Windows
applications are:

• 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.

The RAD Studio IDE offers two application UI models:

• Single Document Interface (SDI)


• Multiple Document Interface (MDI)

Single Document Interface


A SDI application normally contains a single document view.

Multiple Document Interface


In an MDI application, more than one document or child window can be opened within a single parent window. This is common in
applications such as spreadsheets or word processors.

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.

Creating Packages and DLLs


Dynamic link libraries (DLLs) are modules of compiled code that work in conjunction with an executable to provide functionality to
an application. You can create DLLs in cross-platform programs.

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:

• Your code module will be called from non-Delphi applications.


• You are extending the functionality of a Web server.
• You are creating a code module to be used by third-party developers.
• Your project is an OLE container.
You cannot pass Delphi runtime type information (RTTI) across DLLs or from a DLL to an executable. If you pass an object from
one DLL to another DLL or to an executable, you will not be able to use the is or as operators with the passed object. This is
because the is and as operators need to compare RTTI. If you need to pass objects from a library, use packages instead of
DLLs, because packages can share RTTI. Similarly, you should use packages instead of DLLs in Web Services because they
rely on Delphi RTTI.
See Also
Building a Windows Application ( see page 89)

Building a Windows “Hello World” Console Application ( see page 88)

Building a VCL Forms “Hello World” Application ( see page 101)

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

2.1 CodeGuard Procedures


Use these procedures to debug your C++ applications with CodeGuard.

Topics
Name Description
Using CodeGuard ( see page 48) This procedure describes how to use CodeGuard when debugging a C++
application.

2.1.1 Using CodeGuard


This procedure describes how to use CodeGuard when debugging a C++ application.

To run a C++ application with CodeGuard reporting


1. Enable the CodeGuard reporting tool.
2. Enable CodeGuard compiler options for your project.
3. Choose Run Run to run your application.
During the execution of your application, CodeGuard runtime errors appear in the Message view.

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.

To enable the CodeGuard reporting tool


1. Choose Tools CodeGuard Configuration to display the CodeGuard Configuration dialog box.
2. Verify that CodeGuard is enabled.
3. Click OK.
Note: If you change any CodeGuard settings in the CodeGuard Configuration
dialog box, CodeGuard generates a .cgi configuration file with the same name and directory as your project file.

To enable CodeGuard compiler options for your project


1. Choose Project Options C++ Compiler Debugging to display the CodeGuard compiler options.
2. Check Enable all CodeGuard options to enable full CodeGuard coverage.
3. Click OK.
4. Rebuild your project.
Note: If you compile and link your project in separate steps, remember to include the CodeGuard library (cg32.lib
) before including other libraries.
See Also
CodeGuard Overview ( see page 9)

48
2.1 CodeGuard Procedures RAD Studio Using CodeGuard

CodeGuard Configuration dialog box

49
RAD Studio 2.2 Database Procedures

2.2 Database Procedures


This topic describes how to use the database components in the Tool Palette, like dbGo components, dbExpress components,
BDE components, and DataSnap components.

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:

• Persistent database connections


• Customized database server logins
• Transaction control
• Application-specific BDE aliases
Using TQuery (Procedure) ( see page 63) TQuery is a query-type dataset that encapsulates an SQL statement and
enables applications to access the resulting records.
Using TSQLQuery ( see page 65) TSQLQuery represents a query that is executed using dbExpress. TSQLQuery
can represent the results of a SELECT statement or perform actions on the
database server using statements such as INSERT, DELETE, UPDATE, ALTER
TABLE, and so on. You can add a TSQLQuery component to a form at design
time, or create one dynamically at runtime.
Using TSQLStoredProc (Procedure) ( see page 66) TSQLStoredProc represents a stored procedure that is executed using
dbExpress. TSQLStoredProc can represent the result set if the stored procedure
returns a cursor. You can add a TSQLStoredProc component to a form at
design time, or create one dynamically at runtime.
Using TSQLTable ( see page 66) TSQLTable represents a database table that is accessed using dbExpress.
TSQLTable generates a query to fetch all of the rows and columns in a table you
specify. You can add a TSQLTable component to a form at designtime, or create
one dynamically at runtime.
Managing Database Sessions Using TSession ( see page 67) A session provides global connection over a group of database components. A
default TSession component is automatically created for each database
application. You must use TSession component only if you are creating a
multithreaded database application. Each database thread requires its own
session components.
Using TSimpleDataSet ( see page 68) TSimpleDataSet is a special type of client dataset designed for simple two-tiered
applications. Like a unidirectional dataset, it can use an SQL connection
component to connect to a database server and specify an SQL statement to 2
execute on that server. Like other client datasets, it buffers data in memory to
allow full navigation and editing support.
Using TSimpleObjectBroker ( see page 69) 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.
Using TStoredProc ( see page 69) TStoredProc is a stored procedure-type dataset that executes a stored procedure
that is defined on a database server.
Using TTable (Procedure) ( see page 70) TTable is a table-type dataset that represents all of the rows and columns of a
single database table.
Using TUpdateSQL to Update a Dataset ( see page 72) When the BDE-enabled dataset represents a stored procedure or a query that is
not “live”, it is not possible to apply updates directly from the dataset. Such
datasets may also cause a problem when you use a client dataset to cache
updates.
Using dbExpress ( see page 72)
Adding a New Connection to the Data Explorer ( see page 73) You can add new connections to the Data Explorer, which persist as long as the
connection object exists.
Browsing a Database in the Data Explorer ( see page 74) Once you have a live connection, you can use the Data Explorer to browse
database objects.
Executing SQL in the Data Explorer ( see page 74) You can write, edit, and execute SQL in an SQL Window, which is available from
within the Data Explorer.
Modifying Connections in the Data Explorer ( see page 75) You can modify connections in a variety of ways from the Data Explorer.
Connecting to a Database using the dbExpress Driver Framework ( see page This procedure tells how to use the dbExpress driver framework to connect to a
76) database and read its records. In the sample code, the dbExpress ini files
contain all the information about the particular database connection, such as
driver, user name, password, and so on.

2.2.1 Accessing Schema Information


The schema information or metadata includes information about what tables and stored procedures are available on the server

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).

To access schema information


1. To populate a unidirectional dataset with metadata from the database server, call SetSchemaInfo method to indicate what
data you want to see.
2. Set the type of schema information parameter of SetSchemaInfo method.
3. Set the name of table or stored procedure parameter of SetSchemaInfo method.
4. To fetch data after using the dataset for metadata, do one of the following:
• Set the CommandText property to specify the query, table, or stored procedure from which you want to fetch data.
• Set the type of schema information to stNoSchema and call SetSchemaInfo method.
Note: If you choose the second option, the dataset fetches the data specified by the CommandText property.

See Also
dbExpress Components ( see page 16)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Debugging dbExpress Applications ( see page 55)


2
Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using TSimpleDataSet ( see page 68)

Using Unidirectional Datasets ( see page 1823)

2.2.2 Using Data Explorer to Obtain Connection Information


Before you have a connection, you can use Data Explorer to assemble connection strings.

To browse database providers


1. Choose View Data Explorer or click the Data Explorer tab in the Project Manager.
2. Expand a provider node under dbExpress to expose the list of available database providers.
3. Expand the second–level provider node to view the list of potential connections.

To get connection information


1. In the Data Explorer list of providers, right-click a second–level provider.
2. In the context menu, click Modify Connection. The Modify Connection dialog is displayed.
3. In the Modify Connection dialog, click Advanced. The Advanced Properties dialog is displayed, containing a scrollable list

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.

To format a connection string


1. In the Advanced Properties dialog, enter values in the right-hand column for the connection properties named in the left
column.
2. The text field at the bottom of the Advanced Properties dialog contains the resulting connection string text. Drag the cursor
over the connection string text to select the connection string text. Copy the text. You can then paste this connection string
wherever you want.
See Also
Browsing a Database in the Data Explorer ( see page 74)

Adding a New Connection ( see page 73)

Modifying Connections ( see page 75)

2.2.3 Configuring TSQL Connection


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.

Metaprocedure: Configuring a TSQL Connection 2


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 TSQLConnection component to the form.
4. Identify the driver (see steps below).
5. Specify connection parameters (see steps below).
6. Identify a database connection (see steps below).
7. Display and use the dbExpress Connection Editor (see steps below).

To identify the driver


1. Select the TSQLConnection component.
2. In the Object Inspector, set the DriverName property, to an installed dbExpress driver.
3. Identify the files associated with the driver name. Select any of the following:
• The dbExpress driver
• The dynamic link library
Note: The relationship between the dbExpress driver or dynamic link library and the database name is stored in a file called
dbxdrivers.ini
, which is updated when you install a dbExpress driver. The SQL connection component looks the dbExpress driver and the
dynamic-link library up in dbxdrivers.ini when given the value of DriverName. When you set the DriverName property,
TSQLConnection automatically sets the LibraryName and VendorLib properties to the names of the associated dlls. Once
LibraryName and VendorLib have been set, your application does not need to rely on dbxdrivers.ini.

53
Configuring TSQL Connection RAD Studio 2.2 Database Procedures

To specify a connection parameter


1. Double-click on the Params property in the Object Inspector to edit the parameters using Value List Editor at designtime.
2. Use the Params.Values property to assign values to individual parameters at run time.

To identify a database connection


1. Set the ConnectionName property to a valid connection name. This automatically sets the DriverName and Params
properties.
2. Edit the Params property to change the saved set of parameter values.
3. Set the LoadParamsOnConnect property to True to develop your application using one database and deploy it using another.
This causes TSQLConnection to automatically set DriverName and Params to the values associated with ConnectionName
in dbxconnections.ini when the connection is opened.
4. Call the LoadParamsFromIniFile method. This method sets DriverName and Params to the values associated with
ConnectionName in dbxconnections.ini (or in another file that you specify). You might choose to use this method if you
want to then override certain parameter values before opening the connection.

To display the Connection Editor


1. Double-click the TSQLConnection component. The dbExpress Connection Editor appears, with a drop-down drivers list, a
list of connection names for the currently selected driver, and a connection parameters table for the currently selected
connection name.
2. From the Driver Name drop-down list, select a driver to indicate the connection to use.
3. From the Connection Name list, select a connection name.
4. Choose the configuration that you want.

2 5. Click the Test Connection button to check for a valid configuration.

To define and modify connections using the Connection Editor


1. To edit the currently selected named connections in dbxconnections.ini, edit the parameter values in the parameter
table.
2. Click OK. The new parameter values are saved to dbxconnections.ini.
3. Click the Add Connection button to define a new connection. The New Connection dialog appears.
4. In the New Connection dialog box, set the Driver Name and the Connection Name.
5. Click OK.
6. Click the Delete Connection button to delete the currently selected named connection from dbxconnections.ini.
7. Click the Rename Connection button to change the name of the currently selected named connection.
See Also
dbExpress Components ( see page 16)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Debugging dbExpress Applications ( see page 55)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

54
2.2 Database Procedures RAD Studio Debugging dbExpress Applications using

Using TSQLQuery ( see page 65)

Using TSimpleDataSet ( see page 68)

Using Unidirectional Datasets ( see page 1823)

2.2.4 Connecting to the Application Server using DataSnap


Components
A client application uses one or more connection components in the DataSnap category of the Tool Palette to establish and
maintain a connection to an application server.

To connect to the application server using DataSnap components


1. Identify the protocol for communicating with the application server.
2. Locate the server machine.
3. Identify the application server on the server machine.
4. If you are not using SOAP, identify the server using the ServerName or ServerGUID property.
5. Manage server connections.
See Also
Connecting to the Application Server ( see page 1517)

Using TLocalConnection or TConnectionBroker ( see page 59)


2
Using TSimpleObjectBroker ( see page 69)

2.2.5 Debugging dbExpress Applications using TSQLMonitor


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 by a provider
component or by the dbExpress driver).

To debug dbExpress applications


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. To monitor SQL commands, from the dbExpress category of the Tool Palette, drag a TSQLMonitor component to the form.
4. Set the SQLConnection property of the TSQLMonitor to the TSQLConnection component.
5. Set the Active property of the TSQLMonitor to True.

To use a callback to monitor SQL commands


1. Use the SetTraceEvent method of the TSQLConnection component.
2. Set the TDBXTraceEvent event parameter.
The dbExpress driver triggers the event every time the SQL connection component passes a command to the server or the

55
Executing the Commands using RAD Studio 2.2 Database Procedures

server returns an error message.


Warning: Do not call SetTraceEvent if the TSQLConnection
object has an associated TSQLMonitor component. TSQLMonitor uses the callback mechanism to work, and
TSQLConnection can only support one callback at a time.
See Also
dbExpress Components ( see page 16)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Using Unidirectional Datasets ( see page 1823)

2.2.6 Executing the Commands using TSQLDataSet


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
2 neither evaluate the SQL nor execute it, but pass the command to the server for execution.

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.

To specify the command to execute


1. Set the CommandType and CommandText properties in the Object Inspector to specify the command for a TSQLDataSet.
2. Set the SQL property in the Object Inspector to specify the SQL statement to pass to the server for a TSQLQuery .
3. Set the StoredProcName property in the Object Inspector to specify the name of the stored procedure to execute for a
TSQLStoredProc .

To execute the command


1. If the dataset is an instance of a TSQLDataSet or a TSQLQuery, call the ExecSQL method.
2. If the dataset is an instance of a TSQLStoredProc, call the ExecProc method.
Tip: If you are executing the query or stored procedure multiple times, it is a good idea to set the Prepared property to True.

56
2.2 Database Procedures RAD Studio Fetching the Data using TSQLDataSet

To create and modify server metadata


1. To create tables in a database, use the CREATE TABLE statement.
2. To create new indexes for those tables, use the CREATE INDEX statement.
3. To add various metadata objects, use CREATE DOMAIN, CREATE VIEW, CREATE SCHEMA, and CREATE PROCEDURE
statements.
4. To delete any of the above metadata objects, use DROP TABLE, DROP VIEW, DROP DOMAIN, DROP SCHEMA, and
DROP PROCEDURE.
5. To change the structure of a table, use the ALTER TABLE statement.
See Also
dbExpress Components ( see page 16)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Accessing Schema Information ( see page 51)

Debugging dbExpress Applications ( see page 55)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using Unidirectional Datasets ( see page 1823) 2

2.2.7 Fetching the Data using TSQLDataSet


To fetch the data
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. To fetch the data for a unidirectional dataset, do one of the following:
• In the Object Inspector, set the Active property to True.
• Call the Open method at runtime.
Tip: Use GetMetadata property to selectively fetch metadata on a database object. Set GetMetadata to False if you are
fetching a dataset for read-only purposes.

5. Set its Prepared property to True to prepare the dataset explicitly.


6. Call the NextRecordSet method to fetch multiple sets of records.
Note: NextRecordSet returns a newly created TCustomSQLDataSet component that provides access to the next set of
records. That is, the first time you call NextRecordSet, it returns a dataset for the second set of records. Calling
NextRecordSet returns a third dataset, and so on, until there are no more sets of records. When there are no additional
datasets, NextRecordSet does not return anything.

57
Specifying the Data to Display using RAD Studio 2.2 Database Procedures

See Also
dbExpress Components ( see page 16)

Specifying Display Data ( see page 58)

Fetching the Data

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Debugging dbExpress Applications ( see page 55)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using Unidirectional Datasets ( see page 1823)

2.2.8 Specifying the Data to Display using TSQLDataSet


To specify the data to display
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
2 displays.
3. From the dbExpress category of the Tool Palette, drag a TSQLDataSet component to the form.
4. For TSQLDataSet, specify the type of unidirectional dataset by CommandType property in the Object Inspector.
5. Specify whether information comes from results of query, a database table, or a stored procedure.

To display results from a query


1. Set the CommandType property to ctQuery for a TSQLDataSet.
2. For TSQLQuery, drag a TSQLQuery component from the Tool Palette to the form.
3. Set the SQL property to the query you want to assign.
4. Select TSQLDataSet.
5. Click the CommandText property. The CommandText Editor opens.
6. In the CommandText Editor, set the SQL property to the text of the query statement.
Note: When you specify the query, it can include parameters, or variables, the values of which can be varied at design time
or runtime. Parameters can replace data values that appear in the SQL statement. SQL defines queries such as UPDATE
queries that perform actions on the server but do not return records.

To display records in a table


1. In the Object Inspector, set the CommandType property to ctTable. TSQLDataSet generates a query based on the values of
two properties: CommandText that specifies the name of the database table that the TSQLDataSet object should represent
and SortFieldNames that lists the names of any fields to use to sort the data, in the order of significance
2. Drag a TSQLTable component to the form.
3. In the Object Inspector , set the TableName property to the table you want.
4. Set the IndexName property to the name of an index defined on the server or set the IndexFieldNames property to a

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.

To display the results of a stored procedure


1. In the Object Inspector, set the CommandType property to ctStoredProc.
2. Specify the name of the stored procedure as the value of the CommandText property.
3. Set the StoredProcName property to the name of the stored procedure for TSQLStoredProc.
Note: After you have identified a stored procedure, your application may need to enter values for any input parameters of the
stored procedure or retrieve the values of output parameters after you execute the stored procedure.
See Also
dbExpress Components ( see page 16)

Configuring TSQLConnection ( see page 53)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Debugging dbExpress Applications ( see page 55)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using TSimpleDataSet ( see page 68)

Using Unidirectional Datasets ( see page 1823) 2

2.2.9 Specifying the Provider using TLocalConnection or


TConnectionBroker
Client datasets are specialized datasets that hold all the data in memory. They 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.

To specify the provider


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, drag a TConnectionBroker component to the form if the provider is on a
remote application server.
4. In the Object Inspector, set the ConnectionBroker property of your client dataset to the TConnectionBroker component to
the form.
5. From the DataSnap category of the Tool Palette, drag a TLocalConnection component to the form if the provider is in the
same application as the client dataset.
6. Set the RemoteServer property of your client dataset to the TLocalConnection component to the form.

59
Using DataSnap RAD Studio 2.2 Database Procedures

See Also
Using DataSnap ( see page 60)

Connecting To Application Server ( see page 55)

Using TSimpleObjectBroker ( see page 69)

2.2.10 Using BDE


To use BDE
1. Choose File New Other. The New Items dialog box opens.
2. In the New Items dialog, select Delphi Projects and double-click VCL Forms Application. The Windows Designer
displays.
3. From the BDE category of the Tool Palette, drag a TTable component to the form. This will encapsulate the full structure of
data in an underlying database table.
4. From the BDE category of the Tool Palette, drag a TQuery component to the form. This will encapsulate an SQL statement
and enables applications to access the resulting records.
5. From the BDE category of the Tool Palette, drag a TStoredProc component to the form. This will execute a stored procedure
that is defined on a database server.
6. From the BDE category of the Tool Palette, drag a TBatchMove component to the form. This will copy a table structure or its
data.
7. From the BDE category of the Tool Palette, drag a TUpdateSQL component to the form. This will provide a way to update
2 the underlying datasets.
See Also
BDE Overview ( see page 15)

Using TDatabase ( see page 62)

Using TSession ( see page 67)

Using TTable ( see page 70)

Using TQuery ( see page 63)

Using TStoredProc ( see page 69)

Using TBatchMove ( see page 61)

Using TUpdateSQL ( see page 72)

2.2.11 Using DataSnap


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.

60
2.2 Database Procedures RAD Studio Using TBatchMove (BDE)

To build multi-tiered database applications using DataSnap


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, drag a TDCOMConnection component to the form. This will establish a
DCOM connection to a remote server in a multi-tiered database application.
4. From the DataSnap category of the Tool Palette, drag a TSocketConnection component to the form. This will establish a
TCP/IP connection to a remote server in a multi-tiered database application.
5. From the DataSnap category of the Tool Palette, drag a TSimpleObjectBroker component to the form. This will locate a
server for a connection component from a list of available application servers.
6. From the DataSnap category of the Tool Palette, drag a TWebConnection component to the form. This will establish an
HTTP connection to a remote server in a multi-tiered database application.
7. From the DataSnap category of the Tool Palette, drag a TConnectionBroker component to the form. This will centralize all
connections to the application server so that applications do not need major rewriting when changing the connection protocol.
8. From the DataSnap category of the Tool Palette, drag a TSharedConnection component to the form. This will connect to a
child remote data module when the application server is built using multiple remote data modules.
9. From the DataSnap category of the Tool Palette, drag a TLocalConnection component to the form. This will provide access
to IAppServer methods that would otherwise be unavailable, and make it easier to scale up to a multi-tiered application at a
later time. It acts like a connection component for providers that reside in the same application.
See Also
Connecting To Application Server ( see page 55)

Deploying Multi-tiered Database Applications (DataSnap) ( see page 1952)


2
Using TLocalConnection or TConnectionBroker ( see page 59)

Using TSimpleObjectBroker ( see page 69)

2.2.12 Using TBatchMove (BDE)


TBatchMove copies a table structure or its data. It can be used to move entire tables from one database format to another.

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)

Using TTable ( see page 70)

61
Connecting to Databases with TDatabase RAD Studio 2.2 Database Procedures

Using TQuery ( see page 63)

Using TStoredProc ( see page 69)

Using Update Objects to Update a Dataset ( see page 1692)

Using TSession ( see page 67)

2.2.13 Connecting to Databases with TDatabase


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:

• Persistent database connections


• Customized database server logins
• Transaction control
• Application-specific BDE aliases

To connect to databases with TDatabase


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.

2 3. Associate a database component with a session.


4. Identify the database.
5. Open a connection using TDatabase.

To associate a database component with a session


1. From the BDE category of the Tool Palette, drag a TDatabase component to the form.
2. Drag a TSession component to the form.
3. In the Object Inspector, set the SessionName property of the TSession component. SessionName is set to “Default," which
means it is associated with the default session component that is referenced by the global Session variable.
4. Add a TSession component for each session if you use multiple sessions.
5. Set the SessionName property of the TDatabase component to the SessionName property of the TSession component to
associate your dataset with a session component.
6. Read the Session property to access the session component with which the database is associated at runtime. If
SessionName is blank or “Default," the Session property references the same TSession instance referenced by the global
Session variable.
Session enables applications to access the properties, methods, and events of a database component’s parent session
component without knowing the session’s actual name. If you are using an implicit database component, the session for that
database component is the one specified by the dataset’s SessionName property.

To identify the database


1. In the drop-down lists for dataset components, specify the alias name or the name of an existing BDE alias for a database
component.
Note: This clears any value already assigned to DriverName. Alternatively, you can specify a driver name instead of an alias
when you create a local BDE alias for a database component using the DatabaseName property. Specifying the driver name

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.

2. Create a local BDE alias.


3. Double-click a database component. The Database editor opens.
4. In the Name edit box in the properties editor, enter the same name as specified by the DatabaseName property.
5. In the Alias name combo box, enter an existing BDE alias name or choose from existing aliases in the drop-down list.
6. To create or edit connection parameters at designtime, do one of the following:
• Use the Database Explorer or BDE Administration utility.
• Double-click the Params property in the Object Inspector to invoke the Value List editor.
• Double-click a database component in a data module or form to invoke the Database editor.
Note: All of these methods edit the Params property for the database component. When you first invoke the Database
Properties
editor, the parameters for the BDE alias are not visible. To see the current settings, click Defaults. The current parameters
are displayed in the Parameter overrides memo box. You can edit existing entries or add new ones. To clear existing
parameters, click Clear. Changes you make take effect only when you click OK.

To open a connection using TDatabase


1. In the Params property of a TDatabase component, configure the ODBC driver for your application.
2. To connect to a database using TDatabase, set the Connected property to True or call the Open method.
Note: Calling TDatabase. Rollback does not call TDataSet. Cancel for any data sets associated with the database.
See Also 2
BDE Overview ( see page 15)

Using TSession ( see page 67)

Using TTable ( see page 70)

Using TQuery ( see page 63)

Using TStoredProc ( see page 69)

Using TBatchMove ( see page 61)

Using TUpdateSQL ( see page 72)

2.2.14 Using TQuery (Procedure)


TQuery is a query-type dataset that encapsulates an SQL statement and enables applications to access the resulting records.

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. Obtain an editable result set.


6. Update read-only result sets.

To associate a dataset with database and session connections


1. From the BDE category of the Tool Palette, drag a TDatabase component to the form.
2. Drag a TSession component to the form.
3. Set the DatabaseName property of the TDatabase component to associate a BDE-enabled dataset with a database. For the
TDatabase component, database name is the value of the DatabaseName property of the database component.
4. Specify a BDE alias as the value of DatabaseName if you want to use an implicit database component and the database has
a BDE alias.
Note: A BDE alias represents a database plus configuration information for that database. The configuration information
associated with an alias differs by database type (Oracle, Sybase, InterBase, Paradox, dBASE, and so on).

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.

2 To create mixed queries


1. Define separate BDE aliases for each database accessed in the query using the BDE Administration tool or the SQL explorer.
2. Leave the DatabaseName property of the TQuery component blank. The names of the databases used will be specified in the
SQL statement.
3. Set the SQL property to the SQL statement you want to execute.
4. Precede each table name in the statement with the BDE alias for the database of the table, enclosed in colons. This whole
reference is then enclosed in quotation marks.
5. Set the Params property to any parameters for the query.
6. Write a Prepare method to prepare the query for execution prior to executing it for the first time.
7. Write an Open or ExecSQL method depending on the type of query you are executing.
8. Use a TDatabase component as an alternative to using a BDE alias to specify the database in a mixed query.
9. Configure the TDatabase to the database, set the TDatabase. DatabaseName to an unique value, and use that value in the
SQL statement instead of a BDE alias name.

To obtain an editable result set


1. Set RequestLive property of the TQuery component to True.
2. If the query contains linked fields, treat the result set as a read-only result set, and update it.
If an application requests a live result set, but the SELECT statement syntax does not allow it, the BDE returns either a read-only
result set for queries made against Paradox or dBASE, or an error code for SQL queries made against a remote server.

To update read-only result sets


1. If all updates are applied to a single database table, indicate the underlying table to update in an OnGetTableName event
handler.

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)

Using TDatabase ( see page 62)

Using TSession ( see page 67)

Using TTable ( see page 70)

Using TStoredProc ( see page 69)

Using TBatchMove ( see page 61)

Using TUpdateSQL ( see page 72)

2.2.15 Using TSQLQuery


TSQLQuery represents a query that is executed using dbExpress. TSQLQuery can represent the results of a SELECT
statement or perform actions on the database server using statements such as INSERT, DELETE, UPDATE, ALTER TABLE,
and so on. You can add a TSQLQuery component to a form at design time, or create one dynamically at runtime.

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)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSimpleDataSet ( see page 68)

65
Using TSQLTable RAD Studio 2.2 Database Procedures

Using Unidirectional Datasets ( see page 1823)

2.2.16 Using TSQLStoredProc (Procedure)


TSQLStoredProc represents a stored procedure that is executed using dbExpress. TSQLStoredProc can represent the result
set if the stored procedure returns a cursor. You can add a TSQLStoredProc component to a form at design time, or create one
dynamically at runtime.

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

2 dbExpress Components ( see page 16)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Using TSQLTable ( see page 66)

Using TSQLQuery ( see page 65)

Using TSimpleDataSet ( see page 68)

Using Unidirectional Datasets ( see page 1823)

2.2.17 Using TSQLTable


TSQLTable represents a database table that is accessed using dbExpress. TSQLTable generates a query to fetch all of the
rows and columns in a table you specify. You can add a TSQLTable component to a form at designtime, or create one
dynamically at runtime.

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)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using TSimpleDataSet ( see page 68)

Using Unidirectional Datasets ( see page 1823)


2

2.2.18 Managing Database Sessions Using TSession


A session provides global connection over a group of database components. A default TSession component is automatically
created for each database application. You must use TSession component only if you are creating a multithreaded database
application. Each database thread requires its own session components.

To manage database sessions


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. Activate a session.
4. Specify default database connection behavior.
5. Manage database connections.
6. Work with password-protected Paradox and dBASE tables.
7. Work with BDE aliases.
8. Retrieve information about a session.
9. Create, Name, and Manage additional sessions.
See Also
Managing Database Sessions ( see page 1664)

67
Using TSimpleObjectBroker RAD Studio 2.2 Database Procedures

Using TTable ( see page 70)

Using TQuery ( see page 63)

Using TStoredProc ( see page 69)

Using TDatabase ( see page 62)

Using TBatchMove ( see page 61)

Using TUpdateSQL ( see page 72)

2.2.19 Using TSimpleDataSet


TSimpleDataSet is a special type of client dataset designed for simple two-tiered applications. Like a unidirectional dataset, it
can use an SQL connection component to connect to a database server and specify an SQL statement to execute on that
server. Like other client datasets, it buffers data in memory to allow full navigation and editing support.

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)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using Unidirectional Datasets ( see page 1823)

68
2.2 Database Procedures RAD Studio Using TStoredProc

2.2.20 Using TSimpleObjectBroker


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.

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)

Connecting To Application Server ( see page 55)

Using TLocalConnection or TConnectionBroker ( see page 59)


2

2.2.21 Using TStoredProc


TStoredProc is a stored procedure-type dataset that executes a stored procedure that is defined on a database server.

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.

To associate a dataset with database and session connections


1. From the BDE category of the Tool Palette, drag a TDatabase component to the form.
2. To associate a BDE-enabled dataset with a database, set the DatabaseName property. For TDatabase component, database
name is the value of the DatabaseName property of the database component.
3. Drag a TSession component to the form.
4. To control all database connections in your application, use the default session.
5. In the Object Inspector, set the SessionName property of the TSession component to associate your dataset with an
explicitly created session component.
Note: If you use a session component, the SessionName property of a dataset must match the SessionName property for the

69
Using TTable (Procedure) RAD Studio 2.2 Database Procedures

database component with which the dataset is associated.

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)

Using TTable ( see page 70)

Using TQuery ( see page 63)

Using TBatchMove ( see page 61)

Using TUpdateSQL ( see page 72)


2

2.2.22 Using TTable (Procedure)


TTable is a table-type dataset that represents all of the rows and columns of a single database table.

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.

To associate a dataset with database and session connections


1. From the BDE category of the Tool Palette, drag a TDatabase component to the form.
2. Drag a TSession component to the form.
3. To associate a BDE-enabled dataset with a database, in the Object Inspector, set the DatabaseName property of the
TDatabase component . For a TDatabase component, the database name is the value of the DatabaseName property of the
database component.

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.

To specify the TableType and control read/write access


1. From the BDE category of the Tool Palette, drag a TTable component to the form.
2. In the Object Inspector, set the TableType property if an application accesses Paradox, dBASE, FoxPro, or comma-delimited
ASCII text tables. BDE uses the TableType property to determine the table’s type.
3. Set TableType to ttDefault if your local Paradox, dBASE, and ASCII text tables use the file extensions like, .DB, .DBF, and
.TXT.
4. For other extensions, set TableType to ttParadox for Paradox, ttDBase for dBASE, ttFoxPro for FoxPro, and ttASCII for
Comma-delimited ASCII text respectively.
5. Set the table component’s Exclusive property to True before opening the table to gain sole read/write access.
Note: If the table is already in use when you attempt to open it, exclusive access is not granted. You can attempt to set
Exclusive on SQL tables, but some servers do not support exclusive table-level locking. Others may grant an exclusive lock,
but permit other applications to read data from the table.

To specify a dBASE index file


1. Set the IndexFiles property to the name of the non-production index file or list the files with a .NDX extension.
2. Specify one index in the IndexName property to have it actively sorting the dataset.
3. At designtime, click the ellipsis button in the IndexFiles property. The Index Files editor opens. 2
4. To add a non-production index file or file with .NDX extension, click the Add button in the Index Files dialog and select the file
from the Open dialog.
Note: For each non-production index file or .NDX file, repeat Steps 3 and 4.

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.

To rename local tables


1. To rename a Paradox or dBASE table at design time, right-click the table component. A drop-down context menu opens.
2. From the context menu, select Rename Table.
3. To rename a Paradox or dBASE table at runtime, call the table’s RenameTable method.

To import data from another table


1. Use the BatchMove method of a table component to import data, copy, update, append records from another table into this
table, or delete records from a table.
2. Set the name of the table from which to import data, and a mode specification that determines which import operation to
perform.
See Also
BDE Overview ( see page 15)

Using TDatabase ( see page 62)

Using TSession ( see page 67)

71
Using dbExpress RAD Studio 2.2 Database Procedures

Using TQuery ( see page 63)

Using TStoredProc ( see page 69)

Using TBatchMove ( see page 61)

Using TUpdateSQL ( see page 72)

2.2.23 Using TUpdateSQL to Update a Dataset


When the BDE-enabled dataset represents a stored procedure or a query that is not “live”, it is not possible to apply updates
directly from the dataset. Such datasets may also cause a problem when you use a client dataset to cache updates.

To update a dataset using an update object


1. From the Tool Palette, add a TUpdateSQL component to the same form as the BDE-enabled dataset.
2. In the Object Inspector, set the UpdateObject property of the BDE-enabled dataset component’s to the TUpdateSQL
component in the form.
3. Set the ModifySQL, InsertSQL, and DeleteSQL properties of the update object to specify the SQL statements needed to
perform updates.
4. Close the dataset.
5. Set the dataset component’s CachedUpdates property to True or link the dataset to the client dataset using a dataset
provider.
6. Reopen the dataset.
2 7. Create SQL statements for update components.
8. Use multiple update objects.
9. Execute the SQL statements.
See Also
Using Update Objects to Update a Dataset ( see page 1692)

Using TTable ( see page 70)

Using TQuery ( see page 63)

Using TStoredProc ( see page 69)

Using TBatchMove ( see page 61)

Using TSession ( see page 67)

2.2.24 Using dbExpress


To build a database applications using dbExpress
1. Connect to the database server and configure a TSQL connection.
2. Specify the data to display.
3. Fetch the data.
4. Execute the commands.

72
2.2 Database Procedures RAD Studio Browsing a Database in the Data Explorer

5. Access the schema information.


6. Debug dbExpress application using TSQLMonitor.
7. Use TSQLTable to represent a table on a database server that is accessed via TSQLConnection.
8. Use TSQLQuery to execute an SQL command on a database server that is accessed via TSQLConnection.
9. Use TSQLStoredProc to execute a stored procedure on a database server that is accessed via TSQLConnection.
See Also
dbExpress Components ( see page 16)

Configuring TSQLConnection ( see page 53)

Specifying Display Data ( see page 58)

Fetching the Data ( see page 57)

Executing the Commands ( see page 56)

Accessing Schema Information ( see page 51)

Debugging dbExpress Applications ( see page 55)

Using TSQLTable ( see page 66)

Using TSQLStoredProc ( see page 66)

Using TSQLQuery ( see page 65)

Using TSimpleDataSet ( see page 68)

Using dbExpress Datasets ( see page 1823)


2

2.2.25 Adding a New Connection to the Data Explorer


You can add new connections to the Data Explorer, which persist as long as the connection object exists.

To add a new connection


1. Choose View Data Explorer. This displays the Data Explorer.
2. Select a provider from the tree list.
3. Right-click to display a pop-up menu.
4. Choose Add New Connection. This displays the Add New Connection dialog.
5. Enter the name of the new connection.
6. Click OK.

To modify connection settings


1. Right-click your connection and scroll down to modify a connection. A Modify Connection dialog appears.
2. Enter your connection settings and click OK.
See Also
Browsing a Database ( see page 74)

Executing SQL in the Data Explorer ( see page 74)

Modifying Connections ( see page 75)

73
Executing SQL in the Data Explorer RAD Studio 2.2 Database Procedures

2.2.26 Browsing a Database in the Data Explorer


Once you have a live connection, you can use the Data Explorer to browse database objects.

To browse database objects


1. Choose View Data Explorer.
2. Expand a provider node to expose the list of available connections.
3. Expand a connection node to view the list of database objects (tables, views, and procedures).
Note: If you receive an error because your connection is not live, you should refresh your provider, and/or modify your
connection.

To retrieve data from the database


1. Expand a connection in the Data Explorer.
2. Double-click a table name or view name to retrieve data. This operation returns a result set into a tabbed Data Explorer page
in the Code Editor.
Tip: You can also select a table in the Data Explorer
and right-click to display a pop-up menu with a Retrieve Data From Table command.

To run a stored procedure


2 1. Choose View Data Explorer.
2. Expand a connection in the Data Explorer and locate a stored procedure.
3. Double-click the stored procedure to view its parameters. The parameters open in a separate page on the design surface.
4. Edit input parameters as necessary.
5. Click the Execute button in the top left corner of the page to execute the procedure. The result set appears in a datagrid.
Tip: You can also select a procedure in the Data Explorer
and right-click to display a pop-up menu with an Execute command.
See Also
Adding a New Connection ( see page 73)

Executing SQL in the Data Explorer ( see page 74)

Modifying Connections ( see page 75)

2.2.27 Executing SQL in the Data Explorer


You can write, edit, and execute SQL in an SQL Window, which is available from within the Data Explorer.

To open a SQL Window


1. Choose View Data Explorer.
2. Select a connection.

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)

Adding a New Connection ( see page 73)

Modifying Connections ( see page 75)

2.2.28 Modifying Connections in the Data Explorer


You can modify connections in a variety of ways from the Data Explorer.

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

5. Make changes to the appropriate values in the editor.


6. Click OK.

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)

2 Executing SQL in the Data Explorer ( see page 74)

Adding a New Connection ( see page 73)

2.2.29 Connecting to a Database using the dbExpress Driver


Framework
This procedure tells how to use the dbExpress driver framework to connect to a database and read its records. In the sample
code, the dbExpress ini files contain all the information about the particular database connection, such as driver, user name,
password, and so on.

To connect to a database and read its records


1. Configure the connections ini file with the information about the database you are connecting to. This includes setting the
driver name, user name, password, and so on.
2. Obtain a TDBXConnectionFactory, which is returned by TDBXConnectionFactory.GetConnectionFactory.
3. Get a TDBXConnectionobject returned by TDBXConnectionFactory.GetConnection.
4. Open the database connection by calling TDBXConnection.Open on the TDBXConnection instance.
5. Get a TDBXCommandobject by calling TDBXConnection.CreateCommand on the TDBXConnection instance.
6. Set the TDBXCommand's Textproperty to the desired SQL command. Call TDBXCommand.Prepare on the TDBXCommand
instance.
7. Execute the SQL query by calling TDBXCommand.ExecuteQuery, which returns a TDBXReader instance.
8. Read the first database record by calling TDBXReader.Next. Call this method to retrieve successive database records.

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.

// Get a TDBXConnection using a TDBXConnectionFactory.


// ConnectionName = section in the connections ini file.
class function TForm1.BuildConnectionFromConnectionName(
ConnectionName: WideString): TDBXConnection;
var
ConnectionFactory: TDBXConnectionFactory;
ConnectionProps: TDBXProperties;
begin
ConnectionFactory := TDBXConnectionFactory.GetConnectionFactory;
ConnectionProps := ConnectionFactory.GetConnectionProperties(ConnectionName);
Result := ConnectionFactory.GetConnection(ConnectionProps,
ConnectionProps.Values[TDBXPropertyNames.UserName],
ConnectionProps.Values[TDBXPropertyNames.Password] );
end;

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;

// Get values from DB


if reader.Next then
begin
numCols := reader.GetColumnCount;
Str(numCols, colCountStr);
ListBox1.Items.Add('Number of columns = ' + colCountStr);
j := 1;
repeat
for i := 0 to reader.GetColumnCount - 1 do
begin
valueType := reader.ValueType[i];
if valueType.DataType = TDBXDataTypes.AnsiStringType then

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

2.3 Interoperable Applications Procedures


Delphi provides wizards and classes to make it easy to implement applications 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.

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

2.3.1 Using COM Wizards


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

79
Using COM Wizards RAD Studio 2.3 Interoperable Applications Procedures

• COM+ Event Object


• 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

To use a COM wizard


1. Choose File New Other. The New Items dialog box displays.
2. In the Item Categories tree, click the ActiveX folder beneath your chosen personality, either C++Builder Projects or Delphi
Projects.
3. In the ActiveX folder, double-click ActiveX Library. This creates a Dynamic Link Library [DLL] project that you can use to
host in-process ActiveX Objects.
4. Choose File New Other again.
5. Do either one of the following:
• To display the COM wizards, click the same ActiveX folder that you clicked in step 2.
• To display the multitier wizards, click the Multitier folder in your selected personality.
6. Double-click the wizard that you want to use.
Note: To create a client application to interact with the server created by a COM wizard, use the Import Component wizard or
2 the TLIBIMP utility.
If your application implements more than one COM object, you should specify the same instancing for all of them.
See Also
Overview of COM Technologies ( see page 1385)

80
2.4 Reporting Procedures RAD Studio Adding Rave Reports to RAD Studio

2.4 Reporting Procedures


This topic provides how-to information on using reporting solutions.

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.

2.4.1 Adding Rave Reports to RAD Studio


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.

To add a Rave Reports command to the Tools menu


1. Choose Tools Configure Tools. This displays the Tool Options dialog box.
2. Click Add. This displays the Tool Properties dialog box.
2
3. Type Rave Reports in the Title text box.
4. Click the Browse button.
5. Browse to the \RaveReports subdirectory in your RAD Studio installation directory.
6. Select the Rave.exe icon.
7. Click OK. This adds the path for the program and the working directory to the Tool Properties dialog box.
8. Click OK
9. Click Close. This adds the command to your Tools menu that will initiate a Rave Reports session. Refer to the Rave Reports
online Help for information on how to build and integrate report objects.
See Also
Rave Reports Overview ( see page 35)

81
RAD Studio 2.5 VCL Procedures

2.5 VCL Procedures


This section provides how-to information on developing VCL for Win32 applications.

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:

1. Create a VCL form.


2. Add a decision query and dataset.
3. Add a decision cube.
4. Add a decision source.
5. Optionally add a decision pivot.
2 6. Add one or more decision grids and graphs.
7. Set the active property of the decision query (or alternate
dataset component) to True.
Building VCL Forms Applications With Graphics ( see page 93) Each of the procedures listed below builds a VCL Form application that uses
graphics. Build one or more of the examples and then add other graphics
features to these basic VCL Form applications.

1. Draw straight lines.


2. Draw rectangles and ellipses.
3. Draw a polygon.
4. Display a bitmap image.
5. Place a bitmap in a combo box.
Building a VCL Forms MDI Application Using a Wizard ( see page 93) The VCL Forms MDI application wizard automatically creates a project that
includes the basic files for an MDI application. In addition to the Main source file,
the wizard creates unit files for child and about box windows, along with the
supporting forms files and resources.
Building a VCL Forms MDI Application Without Using a Wizard ( see page 94)
Building a VCL Forms SDI Application ( see page 96)
Creating a New VCL Component ( see page 97) You can use the New VCL Component wizard to create a new VCL component
for your application. The wizard detects the personality of the product you are
using and creates the appropriate type of component.

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:

1. Set up the database connection.


2. Set up the dataset.
3. Set up the data provider, client dataset, and data source.
4. Connect a DataGrid to the connection components.
5. Run the application.
Building a VCL Forms Application ( see page 99) The following procedure illustrates the essential steps to building a VCL Forms
application using RAD Studio.
Creating Actions in a VCL Forms Application ( see page 100) Using RAD Studio, the following procedure illustrates how to create actions using
the ActionList tool. It sets up a simple application and describes how to create a
file menu item with a file open action.
Building the VCL application with ActionList actions consists of the following
major steps:

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.
Building a VCL Forms "Hello World" Application ( see page 101) This procedure demonstrates how to construct a simple “Hello world” VCL Forms
application using either Delphi or C++. Though simple, the Windows Forms
"Hello world" application demonstrates the essential steps for creating a VCL
Forms application. The application uses a VCL Form, a control, an event, and
displays a dialog in response to a user action.
Creating the "Hello world" application consists of the following steps:

1. Create a VCL Form with a button control. 2


2. Write the code to display "Hello world" when the button is
clicked.
3. Run the application.
Using ActionManager to Create Actions in a VCL Forms Application ( see page Using RAD Studio, the following procedure illustrates how to create actions using
102) ActionManager. It sets up a simple user interface with a text area, as would be
appropriate for a text editing application, and describes how to create a file menu
item with a file open action.
Building the VCL application with ActionManager actions consists of the following
major steps:

1. Create a main window.


2. Add a File open action to the ActionManager.
3. Create the main menu.
4. Add the action to the menu.
5. Build and run the application.
Building a VCL Forms dbExpress Database Application ( see page 103) The following procedure describes how to build a dbExpress database
application.
Building a VCL Forms dbExpress application consists of the following major
steps:

1. Set up the database connection.


2. Set up the unidirectional dataset.
3. Set up the data provider, client dataset, and data source.
4. Connect a DataGrid to the connection components.
5. Run the application.

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:

1. Create a project directory containing a text file to copy.


2. Create a VCL Form with a button control.
3. Write the code to read the string and write it to a file.
4. Run the application.
Copying a Complete String List (VCL) ( see page 107) Copying a string list can have the effect of appending to or overwriting an existing
string list. This VCL application appends to a string list. With a simple change, it
can overwrite a string list. Creating this VCL application consists of the following
steps:

1. Create a VCL Form with TButtons, TComboBox, and


TMemo controls.
2. Write the code to create a string list to the Button1
OnClick handler.
3. Write the code to copy the string list to the Button2
OnClick handler.
4. Run the application.
Creating Strings ( see page 109) Creating this VCL application consists of the following steps:

1. Create a VCL Form with TButton and TComboBox


controls.
2. Write the code to create strings to the TButton OnClick
handler.

2 3. Run the application.


Creating a VCL Form Instance Using a Local Variable ( see page 110) A safe way to create a unique instance of a modal VCL form is to use a local
variable in an event handler as a reference to a new instance. If you use a local
variable, it doesn't matter whether the form is auto-created or not. The code in
the event handler makes no reference to the global form variable. Using RAD
Studio, the following procedure creates a modal form instance dynamically. It
(optionally) removes the second form's invocation at startup.
Building this VCL application consists of the following steps:

1. Create the project directory.


2. Create two forms for the project.... more ( see page 110)
Deleting Strings ( see page 112) Creating this VCL application consists of the following steps:

1. Create a VCL Form with Buttons and ListBox controls.


2. Write the code to add strings to a list.
3. Write the code to delete a string from the list.
4. Run the application.
Displaying an Auto-Created VCL Form ( see page 113) Using RAD Studio, the following procedure creates a modal form at design time
that is displayed later during program execution.
Building this VCL application consists of the following steps:

1. Create the project directory.


2. Create two forms for the project.
3. Link the forms.
4. Create a control on the main form to display the modal
form; then write the event handler.
5. Build and run the application.

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.

1. Create a VCL form with a button control.


2. Provide a bitmap image.
3. Code the button's onClick event handler to load and
display a bitmap image.
4. Build and run the application.
Displaying a Full View Bitmap Image in a VCL Forms Application ( see page This procedure loads a bitmap image from a file and displays it in its entirety to a
116) VCL form. The procedure uses the Height and Width properties of the Bitmap
object to display a full view of the image.

1. Create a VCL form with a button control.


2. Provide a bitmap image.
3. Code the button's onClick event handler to load and
display a bitmap image.
4. Build and run the application.
Drawing a Polygon in a VCL Forms Application ( see page 117) This procedure draws a polygon in a VCL form.

1. Create a VCL form.


2. Code the form's OnPaint event handler to draw a polygon.
3. Build and run the application.
Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118) This procedure draws a rectangle and ellipse in a VCL form.

1. Create a VCL form.


2. Code the form's OnPaint event handler to draw a
rectangle and ellipse.
2
3. Build and run the application.
Drawing a Rounded Rectangle in a VCL Forms Application ( see page 118) This procedure draws a rounded rectangle in a VCL form.

1. Create a VCL form and code the form's OnPaint event


handler.
2. Build and run the application.
Drawing Straight Lines In a VCL Forms Application ( see page 119) This procedure draws two diagonal straight lines on an image in a VCL form.

1. Create a VCL form.


2. Code the form's OnPaint event handler to draw the
straight lines.
3. Build and run the application.
Dynamically Creating a VCL Modal Form ( see page 120) You may not want all your VCL application's forms in memory at once. To reduce
the amount of memory required at load time, your application can create forms
only when it needs to make them available for use. A dialog box, for example,
needs to be in memory only during the time the user interacts with it. Using RAD
Studio, the following procedure creates a modal form dynamically. The main
difference between dynamically creating a form and displaying an auto-created
VCL form is that you remove the second form's invocation at startup and write
code to dynamically create the form.... more ( see page 120)

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:

1. Create the project directory.


2. Create two forms for the project.
3. Remove the second form's invocation at startup.
4. Link the forms.
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.
Iterating Through Strings in a List ( see page 123) This VCL application first creates a list of strings. Then it iterates through the
strings, changing all string characters to uppercase. It consists of the following
steps:

1. Create a VCL Form with Buttons and TListBox controls.


2. Write the code to create a string list and add strings to it.
3. Write the code to iterate through the string list to process
string characters.
4. Run the application.
Building a Multithreaded Application ( see page 124) These are the essential steps to building a VCL Forms multithreaded application
with a thread object using RAD Studio.
Writing Cleanup Code ( see page 125)
Avoiding Simultaneous Thread Access to the Same Memory ( see page 125) Use these basic techniques to prevent other threads from accessing the same
memory as your thread:
2 1. Lock objects.
2. Use critical sections.
3. Use a multi-read exclusive-write synchronizer
Defining the Thread Object ( see page 126)
Handling Exceptions ( see page 129)
Initializing a Thread ( see page 130)
Using the Main VCL Thread ( see page 131) Using the main VCL thread consists of the following basic steps:

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.
Waiting for Threads ( see page 132) The following are procedures that can be used to wait for threads.

• Wait for a thread to finish executing.


• Wait for a task to complete.
• Check if another thread is waiting for your thread to
terminate.
Writing the Thread Function (Procedure) ( see page 134) The Execute method is your thread function. You can think of it as a program that
is launched by your application, except that it shares the same process space.
Writing the thread function is a little trickier than writing a separate program,
because you must make sure that you do not overwrite memory that is used by
other processes in your application. On the other hand, because the thread
shares the same process space with other threads, you can use the shared
memory to communicate between threads.

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:

1. Create a VCL Form with a button control.


2. Write the code to read the string and write it to a file.
3. Run the application.
Renaming Files ( see page 137) Creating this VCL application consists of the following steps:

1. Create a project directory containing a file to rename.


2. Create a VCL Form with button and label controls.
3. Write the code to rename the file.
4. Run the application.
Adding and Sorting Strings ( see page 138) Creating this VCL application consists of the following steps:

1. Create a VCL Form with Button, Label, and TListBox


controls.
2. Write the code to add and sort strings.
3. Run the application.
Creating a VCL Forms ActiveX Button ( see page 139) Like a Delphi control, an ActiveX control generates program code when you
2
place the component on a form or other logical container in the IDE. The main
difference between an ActiveX control and a Delphi control is that an ActiveX
control is language independent. You can create ActiveX controls for deployment
to a variety of programming environments on Windows, not just Delphi or
C++Builder.
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... more ( see page 139)
Creating a VCL Forms ActiveX Active Form ( see page 140) Like a Delphi control, an ActiveX control generates program code when you
place the component on a form or other logical container in the IDE. The main
difference between an ActiveX control and a Delphi control is that an ActiveX
control is language independent. You can create ActiveX controls for deployment
to a variety of programming environments on Windows, not just Delphi or
C++Builder, for example.
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... more ( see page 140)
Building a VCL Forms Web Browser Application ( see page 142) Creating the Web browser application consists of the following steps:

1. Create a VCL Form with a button control.


2. Add a TWebBrowser component to the form.
3. Add controls to enter a URL and launch the browser.
4. Write the code to launch the browser when a button is
clicked.
5. Run the application.

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:

1. TRibbon: Main visual component that provides most


functionality.
2. TRibbonApplicationMenuBar: Component that provides
the functionality of the application menu.
3. TRibbonQuickAccessToolbar: Component that provides
the functionality of the Quick Access Toolbar
4. TRibbonPage: Component that represents the page of
the ribbon that is currently visible
5. TRibbonGroup: Component that all of the pages
commands are displayed in. Commands must be placed
in a group.... more ( see page 143)
Adding Commands to the Ribbon ( see page 144) This topic follows in sequence the creation of a ribbon application using either the
Ribbon Application Wizard or the manual steps described in Creating an
Application that Uses Ribbon Controls ( see page 143).
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... more ( see
2 page 144)

2.5.1 Building a Windows "Hello World" Console Application


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.

To create the "Hello world" console application


1. Create a Windows console application.
2. Create the logic.
3. Run the application.

To create a Windows console application


1. Choose File New Other.... The New Items dialog box appears.
2. In the New Items dialog box, select either Delphi Projects or C++Builder Projects and then double-click Console
Application.
3. For C++, in the New Console Application dialog box, make sure that VCL Forms and Multi-threaded are unchecked, and
Console application is checked. Then click OK.

To associate code with the console window


1. In the code template that is displayed in the Code Editor: For Delphi, enter the following statements after the try keyword and
before the except keyword:

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.

To run the "Hello World" application


1. Choose Run Run. The application compiles and displays a console window with your "Hello World" message.
2. Press the ENTER key. The console window closes when the program terminates.
See Also
Windows Overview ( see page 45)

Building a Windows Application ( see page 89)

Building Applications Menus ( see page 90)

2.5.2 Developing a Windows Application


The following procedure illustrates the essential steps for building a Windows application. 2

To create a Windows project


1. Select New VCL Forms Application — Delphi for Win32. The Windows Designer displays.
2. If necessary, select Design view.
3. From the Tool Palette, drag components onto the designer to create the user interface.
4. Associate logic with the controls.

To associate code with a control


1. In the Designer, double-click the component to which you want to apply logic. The Code Editor appears, cursor in place
between the reserved words begin and end in the event handler.
2. Code your application logic.
3. Save and compile the application.
See Also
Windows Overview ( see page 45)

Building a Windows "Hello World" Application ( see page 88)

Building Windows Application Menus ( see page 90)

89
Building Application Menus RAD Studio 2.5 VCL Procedures

2.5.3 Building Application Menus


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.

To create application menus


1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select VCL Forms Application. The Windows Designer displays.
3. Build application menus.
4. Use the Menu Designer.
5. Create an event handler for each menu item.
6. Move menu items.
7. Add images to menu items.

To build application menus


1. From the Standard category of the Tool Palette, add TMainMenu or TPopupMenu component to your form. A visual
representation of the menu appears on the designer.
Note: A TMainMenu
component creates a menu that is attached to the title bar of the form. A TPopupMenu component creates a menu that
2 appears when the user right-clicks in the form.
2. To view the menu, if the form is visible, click the form. The menu appears in the form exactly as it will when you run the
program.
3. To delete a menu item, select the menu item you want to delete. Press Delete.
4. To edit menu items, select the VCL form, select the menu item you want to edit, and edit its properties.
5. To make the menu item a separator bar, place the cursor on the menu where you want a separator to appear and enter a
hyphen (-) for the caption or press the hyphen (-) key.
6. To specify a keyboard shortcut for a menu item, in the Object Inspector, set the ShortCut property.

To use the Menu Designer


1. Select a menu component on the form.
2. Double-click the menu component. The Menu Designer window opens.
Note: You can also open the Menu Designer
by clicking the ellipsis(...) button next to the Items property in the Object Inspector.
3. To name a menu component, in the Object Inspector, set the Caption property.
Tip: Delphi derives the Name property from the caption, for e.g. if you give a menu item a Caption property value of File,
Delphi assigns the menu item a Name property of File1. However, if you fill in the Name property before filling in the Caption
property, Delphi leaves the Caption property blank until you type a value.

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.

To create an event handler for a menu item


1. In the designer, double-click the menu item to which you wish to add an event handler. The Code Designer appears, cursor
in place between event handler brackets.
2. Code your menu item logic.
3. Save and compile the application.

To move menu items


1. To move a menu item along the desired menu bar, drag the item until the arrow tip of the cursor points to the new location.
2. Release the mouse button.
3. To move a menu item into a menu list, drag the item until the arrow tip of the cursor points to the new menu.
4. Release the mouse button.

To add images to menu items


1. From the Tool Palette, drag a TMainMenu or TPopupMenu component to a form.
2. From the Tool Palette, drop a TImageList component to the form.
3. Double-click on the TImageList component. The ImageList editor opens.
4. Click Add to select the bitmap or bitmap group you want to use in the menu.
5. Select the bitmap that you want and click OK. 2
6. In the Object Inspector, set the Images property of the TMainMenu or TPopupMenu component to the image you selected
in the ImageList editor.
See Also
Windows Overview ( see page 45)

Building a Windows Application ( see page 89)

2.5.4 Building a VCL Forms Application with Decision


Support Components
Creating a form with tables and graphs of multidimensional data consists of the following major steps:

1. Create a VCL form.


2. Add a decision query and dataset.
3. Add a decision cube.
4. Add a decision source.
5. Optionally add a decision pivot.
6. Add one or more decision grids and graphs.
7. Set the active property of the decision query (or alternate dataset component) to True.

91
Building a VCL Forms Application with RAD Studio 2.5 VCL Procedures

To create a VCL form


1. Choose File New Other Delphi Projects and double-click the VCL Forms Application icon. The VCL Forms Designer
displays.
2. If necessary, click Form1 to make it the active window.

To add a decision dataset


1. From the Decision Cube page on the Tool Palette, add a DecisionQuery component to the top of the form.
Tip: Place non-visual components such as this one in the top left corner of the form to keep them out of the way of visual
components you will be adding.

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.

To add a decision cube


1. From the Decision Cube page on the Tool Palette, add a decision cube component to the top left corner of the form.
2. In the Object Inspector, select DecisionQuery1 from the drop-down list next to the decision cube's DataSet property.

To add a decision source


1. From the Decision Cube page on the Tool Palette, add a decision source component to the top left corner of the form.
2. In the Object Inspector, select DecisionCube1 from the drop-down list next to the decision source's DecisionCube property.

To add a decision pivot


1. From the Decision Cube page on the Tool Palette, add an optional DecisionPivot component to the top of the form.
Tip: The decision pivot displays in the final application window. Place it to the right of the nonvisual components.

2. In the Object Inspector, select DecisionSource1 from the drop-down list next to the decision pivot's DecisionSource property.

To create a decision grid


1. From the Decision Cube page on the Tool Palette, add a decision grid component to the form just beneath the decision
pivot.
2. In the Object Inspector, select DecisionSource1 from the drop-down list next to the decision grid's DecisionSource property.

92
2.5 VCL Procedures RAD Studio Building a VCL Forms MDI Application

To create a decision graph


1. From the Decision Cube page on the Tool Palette, add a decision graph component to the form just beneath the decision
grid.
2. In the Object Inspector, select DecisionSource1 from the drop-down list next to the decision graph's DecisionSource
property.

To run the application


1. In the Object Inspector, select True from the Active property drop-down. The visual decision graph, grid, and pivot
components display data.
2. Choose Run Run to run the application. The application runs and displays the decision support components.
3. Use the decision pivot to update, as desired, the data displayed in the grid and graph.
See Also
VCL Overview ( see page 36)

2.5.5 Building VCL Forms Applications With Graphics


Each of the procedures listed below builds a VCL Form application that uses graphics. Build one or more of the examples and
then add other graphics features to these basic VCL Form applications.

1. Draw straight lines.


2. Draw rectangles and ellipses.
2
3. Draw a polygon.
4. Display a bitmap image.
5. Place a bitmap in a combo box.
See Also
Overview of Graphics Programming ( see page 2176)

Drawing Straight Lines In a VCL Application ( see page 119)

Drawing Rectangles and Ellipses in a VCL Application ( see page 118)

Displaying a Bitmap Image in a VCL Application ( see page 114)

Placing A Bitmap Image In a Combo Box of a VCL Application ( see page 135)

2.5.6 Building a VCL Forms MDI Application Using a Wizard


The VCL Forms MDI application wizard automatically creates a project that includes the basic files for an MDI application. In
addition to the Main source file, the wizard creates unit files for child and about box windows, along with the supporting forms
files and resources.

To create a new MDI application using a wizard


1. Choose File New Other Delphi Projects and double-click the MDI Application icon. The Browse to Folder dialog box
is displayed.

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)

2.5.7 Building a VCL Forms MDI Application Without Using a


Wizard
The basic steps to create a new MDI application with a child window without using a wizard are
1. Create a main window form (MDI parent window).
2. Create a child window form.
3. Have the main window create the child window under user control.
4. Write the event handler code to close the child window.
5. Create the main menu and commands.
6. Add the event handlers for the commands.
7. Compile and run the application.
2
To create the main window form
1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. In the Object Inspector, set the FormStyle property to fsMDIForm.
3. Enter a more descriptive name such as frMain for the Name property.
4. Save the unit file with a more descriptive name, such as uMain.pas (Delphi) or uMain.cpp (C++).

To create a child window


1. Choose File New Form
2. In the Object Inspector, set the FormStyle property to fsMDIChild.
3. Enter a more descriptive name such as frChild for the Name property.
4. Save the unit file as uChild.pas (Delphi) or uChild.cpp (C++).

To have the main window create the child window


1. Choose Project Options Forms. The Project Options dialog box appears.
2. Select frChild from Auto-create forms list and click [>] to move it to the Available forms list and click OK.
3. Select the frMain form to activate it; then switch to the Code view.
4. For Delphi, scroll to the uses section and add uChild to the list. For C++, add #include “uChild.h” to uMain.h.
5. For Delphi, scroll to the private declarations section and enter this procedure declaration:
procedure CreateChildForm(const childName: string);
For C++, add the following function declaration to the private: declarations of TfrMain.

94
2.5 VCL Procedures RAD Studio Building a VCL Forms MDI Application

void __fastcall CreateChildForm( const AnsiString childName );


6. For Delphi, scroll to the implementation section, and enter the code below:
procedure TfrMain.CreateChildForm (const childName: string);
var Child: TfrChild;
begin
Child := TfrChild.Create(Application);
Child.Caption := childName;
end;
For C++, add the following function definition to uMain.cpp:
void __fastcall TfrMain::CreateChildForm( const AnsiString childName )
{
TfrChild *Child = new TfrChild( Application );
Child->Caption = childName;
}

To write the event handler code to close the child window


1. If necessary, activate the frMain form; then select the Events tab in the Object Inspector.
2. Double-click the OnClose event. The Code Editor displays with the cursor in the TfrMain.FormClose (Delphi) or
TfrMain::FormClose (C++) event handler block.
3. For Delphi, enter the following code:
Action := caFree;
For C++, enter the following code:
Action = caFree;

To create the main menu and commands


2
1. From the Standard page on the Tool Palette, place a TMainMenu component on the main form.
2. Double-click the TMainMenu component. The Menu designer (frMain.MainMenu1) displays with the first blank menu item
highlighted.
3. In the Object Inspector on the Properties tab, enter mnFile for the Name property and &File for the Caption property; then
press ENTER. In the Menu designer, File displays as the name of the first menu item.
4. In the Menu designer, select File. A blank command field displays in the File group. Select the blank command.
5. In the Object Inspector, enter mnNewChild for the Name property and &New child for the Caption property; then press
ENTER. In the Menu designer, New child displays as the name of the first file command, and a blank command field displays
just beneath New child.
6. Select the blank command.
7. In the Object Inspector, enter mnCloseAll for the Name property and &Close All for the Caption property; then press ENTER.
In the Menu designer, Close All displays as the name of the second file command.

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).

To close the child window


1. Activate the child form.
2. In the Object Inspector, double-click the OnClose event on the Events tab. The Code Editor displays with the cursor in the
TfrChild.FormClose (Delphi) or TfrChild::FormClose (C++) event handler block.
3. For Delphi, enter the following statement:
Action := caFree;
For C++, enter the following statement:
2 Action = caFree;

To compile and run the MDI application


1. Choose Run Run.
2. The application executes, displaying the File command.
3. Choose File New child one or more times. A child window displays with each New child command.
4. Choose File Close All. The child windows close.
See Also
VCL Overview ( see page 36)

2.5.8 Building a VCL Forms SDI Application


To create a new SDI application
1. Choose File New Other Delphi Projects and double-click the SDI Application icon.
2. Pick a folder to save the files in and click OK.
3. Choose Run Run to compile and run the application.
See Also
VCL Overview ( see page 36)

96
2.5 VCL Procedures RAD Studio Creating a New VCL Component

2.5.9 Creating a New VCL Component


You can use the New VCL Component wizard to create a new VCL component for your application. The wizard detects the
personality of the product you are using and creates the appropriate type of component.

Metaprocedure: Creating a new VCL component


1. Specify an ancestor component on the Ancestor Component page.
2. Specify the class name and other properties on the Component page.
3. Choose from three methods for creating a unit:
• Create a unit, on the Create unit page
• Install the unit to an existing package, on the Existing package page
• Install the unit as a new package, on the New Package page

To specify an ancestor component


1. Create a new package for the new component by choosing File New Other Delphi Projects and double-clicking the
Package icon. This step adds a new package to the Project Manager and enables the Add unit to <my_new_package>
option on the Create unit page.
2. In the IDE, choose Component New VCL Component. This step displays the first page of the New VCL Component
wizard (the Ancestor Component page) and loads the page with names of components, along with the unit that defines each
component.
3. On the Ancestor Component page, select an ancestor component from the list. 2
4. Click Next. This displays the Component page of the New VCL Component wizard.

To specify the class name and other properties


1. On the Component page, the fields are prepopulated for Class Name, Palette Page, Unit name, and Search path. You can
either accept the default values for these fields, or you can change the values by using the following steps. If you want to
accept the default values, skip to step 6.
2. To change the default class name, enter a different class name in the Class Name textbox.
3. To change the default palette page for the component, in the Palette Page textbox, either enter the name of your chosen
Tool Palette area, or click the down-arrow to select from palette page areas.
4. In the Unit Name textbox, you can either enter or edit the full path of the unit name. Click [...] to browse for and select the unit
you want.
5. Either enter or edit the search path in the Search Path textbox.
6. Click Next. This opens the Create unit page of the wizard. The choices on the Create unit page are:
• Create Unit
• Install to Existing Package
• Install to New Package
• Add unit to <my_new_package> (this selection is present only if you create a new package in the very first step, above)

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 an existing package


1. On the Create unit page, select the Install to Existing Package radio button.
2. Click Next. This generates a list of existing packages.
3. On the Existing Package page, select the package you want to install the unit into.
4. Click Finish. The new unit opens in the Code Editor.

To install a unit into a new package


1. On the Create unit page, select the Install to New Package radio button.
2. Click Next.
3. On the New Package page, enter a name for the package into the File Name textbox.
4. In the Description textbox, enter a description of your new package .
5. Click Finish. The new unit opens in the Code Editor.

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.

Building a VCL ADO application consists of the following major steps:

1. Set up the database connection.


2. Set up the dataset.
3. Set up the data provider, client dataset, and data source.
4. Connect a DataGrid to the connection components.
5. Run the application.

To add an ADO connection component


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the dbGo page of the Tool Palette, place an ADOConnection component on the form.
3. Double-click the ADOConnection component to display the ConnectionString dialog.
4. If necessary, select Use Connection String; then click the Build button to display the Data Link Properties dialog.
5. On the Provider page of the dialog, select Microsoft Jet 4.0 OLE DB Provider; then click the Next button to display the
Connection page.
6. On the Connection page, click the ellipsis button to browse for the dbdemos.mdb database. The default path to this
database is C:\Program Files\Common Files\CodeGear Shared\Data.
7. Click Test Connection to confirm the connection. A dialog appears, indicating the status of the connection.

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.

To set up the dataset


1. From the dbGo page, place an ADODataSet component at the top of the form.
2. In the Object Inspector, select the Connection property drop-down list. Set it to ADOConnection1.
3. Set the CommandText property to an SQL command, for example, Select * from orders. You can either type the Select
statement in the Object Inspector or click the ellipsis to the right of CommandText to display the CommandText Editor
where you can build your own query statement.
Tip: If you need additional help while using the CommandText Editor
, click the Help button.
4. Set the Active property to True to open the dataset. You are prompted to log in. Use admin for the username and no
password.

To add the provider


1. From the Data Access page, place a DataSetProvider component at the top of the form.
2. In the Object Inspector, select the DataSet property drop-down list. Set it to ADODataSet1.

To add client dataset


1. From the Data Access page, place a ClientDataSet component to the right of the DataSetProvider component on the form.
2. In the Object Inspector, select the ProviderName drop-down. Set it to DataSetProvider1.
3. Set the Active property to True to allow data to be passed to your application. A data source connects the client dataset with
data-aware controls. Each data-aware control must be associated with a data source component to have data to display and
manipulate. Similarly, all datasets must be associated with a data source component for their data to be displayed and
manipulated in data-aware controls on the form. 2
To add the data source
1. In the Tool Palette on the Data Access page, place a DataSource component to the right of the ClientDataSet on the form.
2. In the Object Inspector, select the DataSet property drop-down. Set it to ClientDataSet1.

To connect a DataGrid to the DataSet


1. In the Tool Palette on the Data Controls page, place a DBGrid component on the form.
2. In the Object Inspector, select the DataSource property drop-down. Set the data source to DataSource1.
3. Choose Run Run.
4. You are prompted to log in. Enter admin for the username and no password. The application compiles and displays a VCL
form with a DBGrid.
See Also
VCL Overview ( see page 36)

2.5.11 Building a VCL Forms Application


The following procedure illustrates the essential steps to building a VCL Forms application using RAD Studio.

To create a VCL Form


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The

99
Creating Actions in a VCL Forms RAD Studio 2.5 VCL Procedures

VCL Forms Designer is displayed.


2. From the Tool Palette, place components onto the form to create the user interface.
3. Write the code for the controls.

To associate code with a control


1. Double-click the component on the form to which you want to apply logic. The Code Editor displays, cursor in place within the
event handler block.
2. Code your application logic.
3. Save and compile the application.
See Also
VCL Overview ( see page 36)

Building a VCL Forms "Hello World" Application ( see page 101)

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)

2.5.12 Creating Actions in a VCL Forms Application


Using RAD Studio, the following procedure illustrates how to create actions using the ActionList tool. It sets up a simple
application and describes how to create a file menu item with a file open action.
2 Building the VCL application with ActionList actions consists of the following major steps:

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.

To create a main window


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer displays.
2. From the Standard category of the Tool Palette, add a TMainMenu and TActionList component to the form.
Tip: To display icons for nonvisual components such as ActionList1, choose Tools->Options->Environment Options
, select VCL Designer from the Delphi options, click Show Component Options, and click OK.

To add the File category to the main menu


1. Double-click MainMenu1 on the form. The MainMenu1 editor displays with the first blank command category selected.
2. In the Object Inspector, enter &File for the Caption property and press RETURN. File displays on the main menu.
3. Click File on the MainMenu1 editor. The first blank action under the File command displays. Select the blank action.
4. Double-click ActionList1 on the form. The ActionList editor displays.
5. In the editor, select New Standard Action from the drop-down list to display the Standard Action Classes dialog.
6. Scroll to the File category, and click the TFileOpen action.
7. Click OK to close the dialog. File displays in the Categories listbox in the ActionList editor.

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.

To add the File Open action to the File category


1. Double-click MainMenu1, if necessary, to display the MainMenu1 editor; select the blank action under the File category.
2. In the Object Inspector, enter &Open for the Caption property and select FileOpen1 from the Action property drop-down list;
then press RETURN. Open... displays in the blank action field in the MainMenu1 editor.

To build and run the application


1. Choose Run Run. The application executes, displaying a form with the main menu bar and the File menu.
2. Choose File Open in the application. The standard Open file dialog displays.
See Also
VCL Overview ( see page 36)

2.5.13 Building a VCL Forms "Hello World" Application


This procedure demonstrates how to construct a simple “Hello world” VCL Forms application using either Delphi or C++. Though
simple, the Windows Forms "Hello world" application demonstrates the essential steps for creating a VCL Forms application. The
application uses a VCL Form, a control, an event, and displays a dialog in response to a user action.

Creating the "Hello world" application consists of the following steps:

1. Create a VCL Form with a button control.


2. Write the code to display "Hello world" when the button is clicked. 2
3. Run the application.

To create a VCL Form


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon.
The VCL Forms Designer is displayed.
2. Click the VCL form to display the form view.
3. From the Standard page of the Tool Palette, place a TButton component on the form.

To display the "Hello world" string


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action field on the Events tab. The Code Editor displays, with the cursor in
the Button1Click event handler block.
3. For Delphi, move the cursor before the begin reserved word and then press ENTER. This creates a new line above the code
block. For C++, place the cursor after the opening brace ({) and press ENTER.
4. For Delphi, insert the cursor on the new line created, and type the following variable declaration:
var s: string;
For C++, enter the following code:
AnsiString s;
5. For Delphi, insert the cursor within the code block and type the following code:
s:= 'Hello world!';
ShowMessage(s);
For C++, enter the following code:

101
Using ActionManager to Create Actions in RAD Studio 2.5 VCL Procedures

s = “Hello world!”;
ShowMessage( s );

To run the "Hello world" application


1. Choose Run Run to build and run the application. The form displays with a button called Button1.
2. Click Button1. A dialog box displays the message "Hello World!"
3. Close the VCL form to return to the IDE.
See Also
VCL Overview ( see page 36)

2.5.14 Using ActionManager to Create Actions in a VCL


Forms Application
Using RAD Studio, the following procedure illustrates how to create actions using ActionManager. It sets up a simple user
interface with a text area, as would be appropriate for a text editing application, and describes how to create a file menu item
with a file open action.

Building the VCL application with ActionManager actions consists of the following major steps:

1. Create a main window.


2. Add a File open action to the ActionManager.

2 3. Create the main menu.


4. Add the action to the menu.
5. Build and run the application.

To create a main window and add a File open action


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Additional page of the Tool Palette, add an TActionManager component to the form.
3. Double-click the TActionManager to display the Action Manager editor.
Tip: To display captions for nonvisual components such as ActionManager, choose Tools->Environment Options
. On the Designer tab, check Show component captions, and click OK.
4. If necessary, click the Actions tab.
5. Select New Standard Action from the drop-down list to display the Standard Action Classes dialog.
6. Scroll to the File category, and click the TFileOpen action.
7. Click OK to close the dialog.
8. In the Action Manager editor, select the File category. Open... displays in the Actions: list box.
9. Click Close to close the editor.

To create the main menu


1. From the Additional page of the Tool Palette, place an TActionMainMenuBar component on the form.
2. Open the Action Manager editor, and select the File category from the Categories: list box.
3. Drag File to the blank menu bar. File displays on the menu bar.

102
2.5 VCL Procedures RAD Studio Building a VCL Forms dbExpress

To build and run the application


1. Choose Run Run. The application executes, displaying a form with the main menu bar and the File menu.
2. Choose File Open. The Open file dialog displays.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

Building a VCL Forms MDI Application Without Using a Wizard ( see page 94)

2.5.15 Building a VCL Forms dbExpress Database


Application
The following procedure describes how to build a dbExpress database application.

Building a VCL Forms dbExpress application consists of the following major steps:

1. Set up the database connection.


2. Set up the unidirectional dataset.
3. Set up the data provider, client dataset, and data source.
4. Connect a DataGrid to the connection components.
5. Run the application. 2

To add a dbExpress connection component


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the dbExpress page of the Tool Palette, place a TSQLConnection component on the form.
3. Double-click the TSQLConnection component to display the Connection Editor.
4. In the Connection Editor, set the Connection Name field to IBConnection.
5. In the Connections Setting box, specify the path to the InterBase database file called employee.gdb in the Database field.
By default, the file is located in C:\Program Files\Common Files\Borland Shared\Data.
6. Accept the value in the User_Name field (sysdba) and Password field (masterkey).
7. Click OK to close the Connection Editor and save your changes.

To set up the unidirectional dataset


1. In the Tool Palette on the dbExpress page, place a TSQLDataSet component at the top of the form.
2. In the Object Inspector, select the SQLConnection property drop-down list. Set it to TSQLConnection1.
3. Set the CommandText property to an SQL command, for example, Select * from SALES. You are prompted to log in.
Use the masterkey password. For the SQL command, you can either type a Select statement in the Object Inspector or click
the ellipsis to the right of CommandText to display the CommandText Editor where you can build your own query statement.
Tip: If you need additional help while using the CommandText Editor
, click the Help button.
4. In the Object Inspector, set the Active property to True to open the dataset.

103
Building an Application with XML RAD Studio 2.5 VCL Procedures

To add the provider


1. In the Tool Palette on the Data Access page, place a TDataSetProvider component at the top of the form.
2. In the Object Inspector, select the DataSet property drop-down list. Set it to SQLDataSet1.

To add client dataset


1. In the Tool Palette on the Data Access page, place a TClientDataSet component to the right of the TDataSetProvider
component on the form.
2. In the Object Inspector, select the ProviderName drop-down. Set it to DataSetProvider1.
3. Set the Active property to True to allow data to be passed to your application. A data source connects the client dataset with
data-aware controls. Each data-aware control must be associated with a data source component to have data to display and
manipulate. Similarly, all datasets must be associated with a data source component for their data to be displayed and
manipulated in data-aware controls on the form.

To add the data source


1. In the Tool Palette on the Data Access page, place a TDataSource component to the right of the TClientDataSet on the
form.
2. In the Object Inspector, select the DataSet property drop-down. Set it to ClientDataSet1.

To connect a DataGrid to the DataSet


1. In the Tool Palette on the Data Controls page, place a TDBGrid component on the form.
2. In the Object Inspector, select the DataSource property drop-down. Set the data source to DataSource1.
3. ChooseRun Run. You are prompted to enter a password. Enter masterkey. If you enter an incorrect password or no
password, the debugger throws an exception. The application compiles and displays a VCL form with a DBGrid.
2
See Also
VCL Overview ( see page 36)

2.5.16 Building an Application with XML Components


This example creates a VCL Forms application that uses an XMLDocument component to display contents in an XML file.

The basic steps are:


1. Create an XML document.
2. Create a VCL form.
3. Place an XMLDocument component on the form, and associate it with the XML file.
4. Create VCL components to enable the display of XML file contents.
5. Write event handlers to display XML child node contents.
6. Compile and run the application.

To create the XML document


1. Copy the text below into a file in a text editor.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE StockHoldings [
<!ELEMENT StockHoldings (Stock+)>
<!ELEMENT Stock (name)>

104
2.5 VCL Procedures RAD Studio Building an Application with XML

<!ELEMENT Stock (price)>


<!ELEMENT Stock (symbol)>
<!ELEMENT Stock (shares)>
]>

<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.

To create a form with an XMLDocument component


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Internet page on the Tool Palette, place an TXMLDocument component on the form. 2
3. In the Object Inspector, click the ellipsis button next to the FileName property, browse to the location of the XML file you
created, and open it. The XML file is associated with the TXMLDocument component.
4. In the Object Inspector, set the Active property to true.

To set up the VCL components


1. From the Standard page on the Tool Palette, place a TMemo component on the form.
2. From the Standard page on the Tool Palette, place two TButton components on the form just above Memo1.
3. In the Object Inspector with Button1 selected, enter CodeGear for the Caption property.
4. In the Object Inspector with Button2 selected, enter MyCompany for the Caption property.

To display child node contents in the XML file


1. In the Object Inspector with Button1 selected, double-click the OnClick event on the Events tab. The Code displays with the
cursor in the TForm1.Button1Click event handler block.
2. Enter the following code to display the stock price for the first child node when the CodeGear button is clicked:
BorlandStock:=XMLDocument1.DocumentElement.ChildNodes[0];
Price:= BorlandStock.ChildNodes['price'].Text;
Memo1.Text := Price;
IXMLNode *BorlandStock = XMLDocument1->DocumentElement->
ChildNodes->GetNode(0);
WideString Price = BorlandStock->ChildNodes->
FindNode( "price" )->Text;
Memo1->Text = Price;
3. For Delphi, add a var section just above the code block in the event handler, and enter the following local variable
declarations:

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;

To compile and run the application


1. Choose Run Run to compile and execute the application. The application form displays two buttons and a memo.
2. Click the CodeGear button. The stock price displays.
3. Click the MyCompany button. The stock price displays.
See Also

2 VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

2.5.17 Copying Data From One Stream To Another


Creating this VCL application consists of the following steps:

1. Create a project directory containing a text file to copy.


2. Create a VCL Form with a button control.
3. Write the code to read the string and write it to a file.
4. Run the application.

To set up your project directory and a text file to copy


1. Create a directory in which to store your project files.
2. Using a text editor, create a simple text file and save it as from.txt in your project directory.

To create a VCL Form with a button control


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Standard page of the Tool palette, place a TButton component on the form.
3. In the Object Inspector, enter CopyFile for the Caption and Name properties.

106
2.5 VCL Procedures RAD Studio Copying a Complete String List (VCL)

To write the copy stream procedure


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.CopyFileClick (Delphi) or TForm1::CopyFileClick (C++) event handler block.
3. For Delphi, Place the cursor before the begin reserved word; then press return. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created and type the following variable declaration:
var stream1, stream2: TStream;
For C++, enter the following variable declarations:
TStream *stream1, *stream2;
5. Insert the cursor within the code block, and type the following code:
stream1 := TFileStream.Create('from.txt', fmOpenRead);
try
stream2:= TFileStream.Create('to.txt', fmCreate);
try
stream2.CopyFrom(stream1, stream1.Size);
finally
stream2.Free;
end;
finally
stream1.Free;
end;
stream1 = new TFileStream( “from.txt”, fmOpenRead );
try {
stream2 = new TFileStream( “to.txt”, fmCreate );
try { 2
stream2–>CopyFrom( stream1, stream1–>Size );
} __finally {
stream2–>Free();
}
} finally {
stream1–>Free();
}

To run the application


1. Save your project files; then choose Run Run to build and run the application. The form displays with a button called
CopyFile.
2. Click CopyFile.
3. Use a text editor to open the newly created file to.txt, which is located in your project directory. The contents of from.txt are
copied into to.txt.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

2.5.18 Copying a Complete String List (VCL)


Copying a string list can have the effect of appending to or overwriting an existing string list. This VCL application appends to a
string list. With a simple change, it can overwrite a string list. Creating this VCL application consists of the following steps:

107
Copying a Complete String List (VCL) RAD Studio 2.5 VCL Procedures

1. Create a VCL Form with TButtons, TComboBox, and TMemo controls.


2. Write the code to create a string list to the Button1 OnClick handler.
3. Write the code to copy the string list to the Button2 OnClick handler.
4. Run the application.

To create a VCL Form with Button, ComboBox, and Memo controls


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Standard page of the Tool palette, place two TButtons, a TComboBox, and a TMemo component on the form.

To create the string list


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. For Delphi, place the cursor before the begin reserved word; then press return. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created and type the following variable declarations:
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:
2 StringList := TStringList.Create;
try
with StringList do begin
Add('This example uses a string List.');
Add('It is the easiest way to add strings');
Add('to a combobox''s list of strings.');
Add('Always remember: the TStrings.Create');
Add('method is abstract; use the');
Add('TStringList.Create method instead.');
end;

with ComboBox1 do begin


Width := 210;
Items.Assign(StringList);
ItemIndex := 0;
end;
finally
StringList.free;
end;
StringList = new TStringList();
try {
StringList->Add( "This example uses a string list" );
StringList->Add( "It is the easiest way to add strings" );
StringList->Add( "to a ComboBox's list of strings." );
StringList->Add( "Remember to call the TStringList constructor!" );
ComboBox1->Width = 210;
ComboBox1->Items->Assign( StringList );
ComboBox1->ItemIndex = 0;
} __finally {
StringList->Free();
}

108
2.5 VCL Procedures RAD Studio Creating Strings

To copy the string list


1. Select Button2 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.Button2Click (Delphi) or TForm1::Button2Click (C++) event handler block. At the cursor, enter the following
code:
Memo1.Lines.AddStrings(ComboBox1.Items);
Memo1–>Lines->AddStrings( ComboBox1–>Items

To run the application


1. Save your project files; then choose Run Run to build and run the application. The form displays with the controls.
2. Click Button1.
3. In ComboBox1, click the arrow to expand the drop-down list. The strings display in the TComboBox in the order listed in the
event handler code for Button1.
4. Click Button2. In the Memo1 window, the strings from ComboBox1 are appended to the 'Memo1' string.
Note: Try replacing the code in the Button2 event handler with the following code; then compile and run the application again.

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)

Building a VCL Forms Application ( see page 99) 2

2.5.19 Creating Strings


Creating this VCL application consists of the following steps:

1. Create a VCL Form with TButton and TComboBox controls.


2. Write the code to create strings to the TButton OnClick handler.
3. Run the application.

To create a VCL Form with TButton and TComboBox controls


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Standard page of the Tool palette, place a TButton, a TLabel, and a TComboBox component on the form.

To write the create string procedure


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. For Delphi, place the cursor before the begin reserved word; then press RETURN. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created and type the following variable declarations:

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;

with ComboBox1 do begin


Width := 210;
Items.Assign(StringList);
ItemIndex := 0;
end;

Label1.Caption := 'Flowers has an index of ' +


IntToStr( StringList->IndexOf( 'Flowers' ) );
finally
StringList.free;
end;
StringList = new TStringList();
try {
StringList->Add( “Animals” );
StringList->Add( “Cats” );
StringList->Add( “Flowers” );
ComboBox1–>Width = 210;
2 ComboBox1–>Items->Assign( StringList );
ComboBox1–>ItemIndex = 0;
Label1–>Caption = “Flowers has an index of “ +
IntToStr( StringList->IndexOf( “Flowers” ) );
} __finally {
StringList->Free();
}

To run the application


1. Save your project files; then choose Run Run to build and run the application. The form displays with the controls.
2. Click the Button. The strings 'Animals', 'Cars', and 'Flowers' display alphabetically in a list in the ListBox. The Label caption
displays the message string: 'Flowers has an index value of 2.'
3. In the ComboBox, click the arrow to expand the drop-down list. The strings added in the TButton event handler appear.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

2.5.20 Creating a VCL Form Instance Using a Local Variable


A safe way to create a unique instance of a modal VCL form is to use a local variable in an event handler as a reference to a
new instance. If you use a local variable, it doesn't matter whether the form is auto-created or not. The code in the event handler
makes no reference to the global form variable. Using RAD Studio, the following procedure creates a modal form instance
dynamically. It (optionally) removes the second form's invocation at startup.

110
2.5 VCL Procedures RAD Studio Creating a VCL Form Instance Using a

Building this VCL application consists of the following steps:

1. Create the project directory.


2. Create two forms for the project.
3. Remove the second form's invocation at startup (optional).
4. Link the forms.
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.

To create the two forms


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer displays Form1.
2. Choose File New Other Delphi Projects Delphi Files or C++Builder Projects and double-click the Form icon. The VCL
Forms Designer displays Form2.

To optionally remove Form2's invocation at startup


1. Choose Project Options Forms. The Project Options dialog displays.
2. Select Form2 in the Auto-create forms list and click [>]. Form2 is moved to the Available forms list.
3. Click OK to close the dialog.

To link Form1 to Form2


1. Select Form1 and choose File Use Unit (Delphi) or Include Unit Hdr (C++). The Uses Unit dialog displays.
2. Select Form2 (the form that Form1 needs to reference) in the dialog.
2
3. Click OK.
For Delphi, a uses clause containing the unit name Unit2 is placed in the implementation section of Unit1.
For C++, the #include “Unit2.h” directive is added to Unit1.h.

To display Form2 from Form1


1. Select Form1, if necessary; then, from the Standard page of the Tool Palette, place a TButton on the form.
2. In the Object Inspector with Button1 selected, double-click the OnClick event on the Events tab. The Code Editor displays
with the cursor in the TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. For Delphi, insert the cursor just above the event handler block and enter the following statement to define a local variable:
var FM: TForm2;
For C++, enter the following variable declaration:
TForm2 *FM;
4. Insert the cursor in the event handler block, and enter the following code:
FM := TForm2.Create(self);
FM.ShowModal;
FM.Free;
FM = new TForm2( this );
FM->ShowModal();
FM->Free();

To build and run the application


1. Save all files in the project; then choose Run Run. The application executes, displaying Form1.
2. Click the button. Form2 displays.

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)

Building a VCL Forms Application ( see page 99)

Dynamically Creating a VCL Modeless Form ( see page 121)

Displaying an Auto-Created VCL Form ( see page 113)

2.5.21 Deleting Strings


Creating this VCL application consists of the following steps:

1. Create a VCL Form with Buttons and ListBox controls.


2. Write the code to add strings to a list.
3. Write the code to delete a string from the list.
4. Run the application.

To create a VCL Form with TButton and ListBox controls


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.

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.

To add strings to a list


1. Select the Add button on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.AddClick (Delphi) or TForm1::AddClick (C++) event handler block.
3. For Delphi, place the cursor before the begin reserved word; then press return. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created and type the following variable declaration:
var
MyList: TStringList;
For C++, enter the following variable declaration:
TStringList *MyList;
5. Insert the cursor within the code block, and type the following code:
MyList := TStringList.Create;
try
with MyList do
begin
Add('Mice');
Add('Goats');

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();
}

To delete a string from the list


1. Select the Delete button on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.DeleteClick (Delphi) or TForm1::DeleteClick (C++) event handler block.
3. For Delphi, place the cursor before the begin reserved word; then press ENTER. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created and type the following variable declaration:
var
BIndex: Integer;
For C++, enter the following variable declaration:
2
int BIndex;
5. For Delphi, insert the cursor within the code block and type the following code:
with ListBox1.Items do
begin
BIndex := IndexOf('Elephants');
Delete (BIndex);
end;
BIndex = ListBox1–>Items->IndexOf( “Elephants” );
ListBox1–>Items->Delete( BIndex );

To run the application


1. Save your project files; then choose Run Run to build and run the application. The form displays with the controls.
2. Click the Add button. The strings 'Mice', 'Goats', 'Elephants', and 'Birds' display in the order listed.
3. Click the Delete button. The string 'Elephants' is deleted from the list.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

2.5.22 Displaying an Auto-Created VCL Form


Using RAD Studio, the following procedure creates a modal form at design time that is displayed later during program execution.

113
Displaying a Bitmap Image in a VCL Forms RAD Studio 2.5 VCL Procedures

Building this VCL application consists of the following steps:

1. Create the project directory.


2. Create two forms for the project.
3. Link the forms.
4. Create a control on the main form to display the modal form; then write the event handler.
5. Build and run the application.

To create the two forms


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer displays Form1.
2. Choose File New Other Delphi Projects Delphi Files or File New Other C++Builder Files and double-click the
Form icon. The VCL Forms Designer displays Form2.

To link Form1 to Form2


1. For Delphi, select Form1 and choose File Use Unit. For C++, select Form1 and choose File Include Unit Hdr. The Uses
Unit dialog displays.
2. Select Form2 (the form that Form1 needs to reference) in the dialog.
3. Click OK.
For Delphi, a uses clause containing the unit name Unit2 is placed in the implementation section of Unit1.
For C++, the #include “Unit2.h” directive is added to Unit1.h.

To display Form2 from Form1


2 1. Select Form1, if necessary; then, from the Standard page of the Tool Palette, place a button on the form.
2. In the Object Inspector with Button1 selected, double-click the OnClick event on the Events tab. The Code Editor displays
with the cursor in the TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. Enter the following event handling code:
Form2.ShowModal;
Form2–>ShowModal();

To build and run the application


1. Save all files in the project; then choose Run Run. The application executes, displaying Form1.
2. Click the button. Form2 displays.
3. 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)

Building a VCL Forms Application ( see page 99)

Dynamically Creating a VCL Modal Form ( see page 120)

2.5.23 Displaying a Bitmap Image in a VCL Forms


Application
This procedure loads a bitmap image from a file and displays it to a VCL form.

114
2.5 VCL Procedures RAD Studio Displaying a Bitmap Image in a VCL Forms

1. Create a VCL form with a button control.


2. Provide a bitmap image.
3. Code the button's onClick event handler to load and display a bitmap image.
4. Build and run the application.

To create a VCL form and button


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Standard page of the Tool Palette, place a TButton component on the form.

To provide a bitmap image


1. Create a directory in which to store your project files.
2. Locate a bitmap image on your local drive, and copy it to your project directory.
3. Save all files in your project to your project directory.

To write the OnClick event handler


1. In the Object Inspector, double-click the Button1 OnClick event on the Events tab. The Code Editor displays with the cursor
in the TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
2. Enter the following event handling code, replacing MyFile.bmp with path to the bitmap image in your project directory:
Bitmap := TBitmap.Create;
try
Bitmap.LoadFromFile('MyFile.bmp');
Form1.Canvas.Brush.Bitmap := Bitmap;
Form1.Canvas.FillRect(Rect(0,0,100,100));
finally 2
Form1.Canvas.Brush.Bitmap := nil;
Bitmap.Free;
end;
Graphics::TBitmap *Bitmap = new Graphics::TBitmap();
try {
Bitmap->LoadFromFile( "..\\MyFile.bmp" );
Form1->Canvas->Brush->Bitmap = Bitmap;
Form1->Canvas->FillRect( Rect(0,0,100,100) );
} __finally {
Form1->Canvas->Brush->Bitmap = NULL;
Bitmap->Free();
}
Note: For C++ projects, the code assumes the target output directory is located in the project directory.

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;

To run the program


1. Select Run Run.
2. Click the button to display the image bitmap in a 100 x 100-pixel rectangle in the upper left corner of the form.
See Also
VCL Overview ( see page 36)

Drawing Straight Lines In a VCL Application ( see page 119)

Drawing Rectangles and Ellipses in a VCL Application ( see page 118)

115
Displaying a Full View Bitmap Image in a RAD Studio 2.5 VCL Procedures

Drawing a Polygon in a VCL Application ( see page 117)

Placing A Bitmap Image In a Combo Box of a VCL Application ( see page 135)

2.5.24 Displaying a Full View Bitmap Image in a VCL Forms


Application
This procedure loads a bitmap image from a file and displays it in its entirety to a VCL form. The procedure uses the Height and
Width properties of the Bitmap object to display a full view of the image.

1. Create a VCL form with a button control.


2. Provide a bitmap image.
3. Code the button's onClick event handler to load and display a bitmap image.
4. Build and run the application.

To create a VCL form and button


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Standard page of the Tool Palette, place a button component on the form.
3. In the Object Inspector, enter Full View for the Caption property and FullView for the name property.

To provide a bitmap image


2
1. Create a directory in which to store your project files.
2. Locate a bitmap image on your local drive, and copy it to your project directory.
3. Save all files in your project to your project directory.

To write the OnClick event handler


1. In the Object Inspector, double-click the Button1 OnClick event on the Events tab. The Code Editor displays with the cursor
in the TForm1.FullViewClick (Delphi) or TForm1::FullViewClick (C++) event handler block.
2. Enter the following event handling code, replacing MyFile.bmp with the name of the bitmap image in your project directory:
Bitmap := TBitmap.Create;
try
Bitmap.LoadFromFile('MyFile.bmp');
Form1.Canvas.Brush.Bitmap := Bitmap;
Form1.Canvas.FillRect(Rect(0,0,Bitmap.Width,Bitmap.Height));
finally
Form1.Canvas.Brush.Bitmap := nil;
Bitmap.Free;
end;
Graphics::TBitmap Bitmap = new Graphics::TBitmap();
try {
Bitmap->LoadFromFile( “..\\MyFile.bmp” );
Form1–>Canvas->Brush->Bitmap = Bitmap;
Form1–>Canvas->FillRect(
Rect( 0, 0, Bitmap->Width, Bitmap->Height ) );
} __finally {
Form1–>Canvas->Brush->Bitmap = NULL;
Bitmap->Free();
}
Note: For C++ projects, the code assumes the target output directory is located in the project directory.

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

To run the program


1. Choose Run Run.
2. Click the button to display the image bitmap in a rectangle in the upper left corner of the form.
See Also
VCL Overview ( see page 36)

Drawing Straight Lines In a VCL Forms Application ( see page 119)

Displaying a Bitmap Image in a VCL Forms application ( see page 114)

Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)

Drawing a Polygon in a VCL Forms Application ( see page 117)

Placing A Bitmap Image In a Combo Box of a VCL Forms Application ( see page 135)

2.5.25 Drawing a Polygon in a VCL Forms Application


This procedure draws a polygon in a VCL form.

1. Create a VCL form.


2. Code the form's OnPaint event handler to draw a polygon. 2
3. Build and run the application.

To create a VCL form


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. In the form view, click the form, if necessary, to display Form1 in the Object Inspector.

To write the OnPaint event handler


1. In the Object Inspector, click the Events tab.
2. Double-click the OnPaint event. The Code Editor displays with the cursor in the TForm1.FormPaint (Delphi) or
TForm1::FormPaint (C++) event handler block.
3. Enter the following event handling code:
Canvas.Polygon ([Point(0,0), Point(0, ClientHeight),
Point(ClientWidth, ClientHeight)]);
TPoint points[] = { Point(0,0),
Point(0, ClientHeight),
Point(ClientWidth, ClientHeight) };
Canvas->Polygon( points, 3 );

To run the program


1. Select Run Run.
2. The applications executes, displaying a right triangle in the lower left half of the form.
See Also
VCL Overview ( see page 36)

117
Drawing a Rounded Rectangle in a VCL RAD Studio 2.5 VCL Procedures

Drawing Straight Lines In a VCL Forms Application ( see page 119)

Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)

Displaying a Bitmap Image in a VCL Forms Application ( see page 114)

2.5.26 Drawing Rectangles and Ellipses in a VCL Forms


Application
This procedure draws a rectangle and ellipse in a VCL form.

1. Create a VCL form.


2. Code the form's OnPaint event handler to draw a rectangle and ellipse.
3. Build and run the application.

To create a VCL form and place an image on it


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. In the form view, click the form, if necessary, to display Form1 in the Object Inspector.

To write the OnPaint event handler


1. In the Object Inspector, double-click the Form1 OnPaint event on the Events tab. The Code Editor displays with the cursor
in the TForm1.FormPaint (Delphi) or TForm1::FormPaint (C++) event handler block.
2
2. Enter the following event handling code:
Canvas.Rectangle (0, 0, ClientWidth div 2, ClientHeight div 2);
Canvas.Ellipse (0, 0, ClientWidth div 2, ClientHeight div 2);
Canvas->Rectangle( 0, 0, ClientWidth / 2, ClientHeight / 2 );
Canvas->Ellipse( 0, 0, ClientWidth / 2, ClientHeight / 2 );

To run the program


1. Choose Run Run.
2. The applications executes, displaying a rectangle in the upper left quadrant, and an ellipse in the same area of the form.
See Also
VCL Overview ( see page 36)

Drawing a Polygon in a VCL Forms Application ( see page 117)

Displaying a Bitmap Image in a VCL Forms Application ( see page 114)

2.5.27 Drawing a Rounded Rectangle in a VCL Forms


Application
This procedure draws a rounded rectangle in a VCL form.

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

To create a VCL form


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. In the Object Inspector, click the Events tab.
3. Double-click the OnPaint event. The Code Editor displays with the cursor in the TForm1.FormPaint (Delphi) or
TForm1::FormPaint (C++) event handler block.
4. Enter the following event handling code:
Canvas.RoundRect(0, 0, ClientWidth div 2,
ClientHeight div 2, 10, 10);
Canvas->RoundRect( 0, 0, ClientWidth / 2, ClientHeight / 2, 10, 10 );

To run the program


1. Save all files in your project; then choose Run Run.
2. The application executes, displaying a rounded rectangle in the upper left quadrant of the form.
See Also
VCL Overview ( see page 36)

Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)

2.5.28 Drawing Straight Lines In a VCL Forms Application


2
This procedure draws two diagonal straight lines on an image in a VCL form.

1. Create a VCL form.


2. Code the form's OnPaint event handler to draw the straight lines.
3. Build and run the application.

To create a VCL form and place an image on it


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. In the form view, click the form, if necessary, to display Form1 in the Object Inspector.

To write the OnPaint event handler


1. In the Object Inspector, double-click the Form1 OnPaint event on the Events tab. The Code Editor displays with the cursor
in the TForm1.FormPaint event handler block.
2. Enter the following event handling code:
with Canvas do
begin
MoveTo(0,0);
LineTo(ClientWidth, ClientHeight);
MoveTo(0, ClientHeight);
LineTo(ClientWidth, 0);
end;
Canvas->MoveTo( 0, 0 );
Canvas->LineTo( ClientWidth, ClientHeight );
Canvas->MoveTo( 0, ClientHeight );
Canvas->LineTo( ClientWidth, 0 );

119
Dynamically Creating a VCL Modal Form RAD Studio 2.5 VCL Procedures

To run the program


1. Choose Run Run.
2. The applications executes, displaying a form with two diagonal crossing lines.
Tip: To change the color of the pen to green, insert this statement following the first MoveTo() statement in the event
handler code: Pen.Color := clGreen; (Delphi) Canvas->Pen->Color = clGreen; (C++). Experiment using other
canvas and pen object properties. See "Using the properties of the Canvas object" in the Delphi 7 Developer's Guide.

See Also
VCL Overview ( see page 36)

Building VCL Forms Applications With Graphics ( see page 93)

Drawing Rectangles and Ellipses in a VCL Forms Application ( see page 118)

Drawing a Polygon in a VCL Forms Application ( see page 117)

Displaying a Bitmap Image in a VCL Forms Application ( see page 114)

2.5.29 Dynamically Creating a VCL Modal Form


You may not want all your VCL application's forms in memory at once. To reduce the amount of memory required at load time,
your application can create forms only when it needs to make them available for use. A dialog box, for example, needs to be in
2 memory only during the time the user interacts with it. Using RAD Studio, the following procedure creates a modal form
dynamically. The main difference between dynamically creating a form and displaying an auto-created VCL form is that you
remove the second form's invocation at startup and write code to dynamically create the form.

Building this VCL application consists of the following steps:

1. Create the project directory.


2. Create two forms for the project.
3. Remove the second form's invocation at startup.
4. Link the forms.
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.

To create the two forms


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer displays Form1.
2. Choose File New Other Delphi Projects Delphi Files or File New Other C++Builder Files and double-click the
Form icon. The VCL Forms Designer displays Form2.

To remove Form2's invocation at startup


1. Choose Project Options Forms. The Project Options dialog displays.
2. Select Form2 in the Auto-create forms list and click [>]. Form2 is moved to the Available forms list.
3. Click OK to close the dialog.

120
2.5 VCL Procedures RAD Studio Dynamically Creating a VCL Modeless

To link Form1 to Form2


1. For Delphi, select Form1 and choose File Use Unit. For C++, select Form1 and choose File Include Unit Hdr The Uses
Unit dialog displays.
2. Select Form2 (the form that Form1 needs to reference) in the dialog.
3. Click OK. For Delphi, a uses clause containing the unit name Unit2 is placed in the implementation section of Unit1. For C++,
the #include “Unit2.h” directive is added to Unit1.h.

To display Form2 from Form1


1. Select Form1, if necessary; then, from the Standard page of the Tool Palette, place a TButton on the form.
2. In the Object Inspector with Button1 selected, double-click the OnClick event on the Events tab. The Code Editor displays
with the cursor in the TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. Enter the following event handling code:
Form2 := TForm2.Create(self);
try
Form2.ShowModal;
finally
Form2.Free;
end;
Form2 = new TForm2( this );
try {
Form2–>ShowModal();
} __finally {
Form2–>Free();
}

To build and run the application


2
1. Save all files in the project; then choose Run Run. The application executes, displaying Form1.
2. Click the button. Form2 displays.
3. Click the X in the upper right corner of the form. Form2 closes and Form1 becomes the active form.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

Dynamically Creating a VCL Modeless Form ( see page 121)

Displaying an Auto-Created VCL Form ( see page 113)

2.5.30 Dynamically Creating a VCL Modeless Form


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:

1. Create the project directory.


2. Create two forms for the project.
3. Remove the second form's invocation at startup.
4. Link the forms.

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.

To create the two forms


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer displays Form1.
2. Choose File New Other Delphi Projects Delphi Files or File New Other C++Builder Files and double-click the
Form icon. The VCL Forms Designer displays Form2.

To remove Form2's invocation at startup


1. Choose Project Options. The Project Options dialog displays.
2. Select Form2 in the Auto-create forms list and click [>]. Form2 is moved to the Available forms list.
3. Click OK to close the dialog.

To link Form1 to Form2


1. For Delphi, select Form1 and choose File Use Unit. For C++, select Form1 and choose File Include Unit Hdr. The Uses
Unit dialog displays.
2. Select Form2 (the form that Form1 needs to reference) in the dialog.
3. Click OK. For Delphi, a uses clause containing the unit name Unit2 is placed in the implementation section of Unit1. For C++,
the #include “Unit2.h” directive is added to Unit1.h.

To display Form2 from Form1


1. Select Form1, if necessary; then, from the Standard page of the Tool Palette, place a button on the form.
2 2. In the Object Inspector with Button1 selected, double-click the OnClick event on the Events tab. The Code Editor displays
with the cursor in the TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++)event handler block.
3. Enter the following event handling code:
Form2 := TForm2.Create(self);
Form2.Show;
Form2 = new TForm2( this );
Form2–>Show();
Note: If your application requires additional instances of the modeless form, declare a separate global variable for each
instance. In most cases you use the global reference that was created when you made the form (the variable name that matches
the Name property of the form).

To build and run the application


1. Save all files in the project; then choose Run Run. The application executes, displaying Form1.
2. Click the button. Form2 displays.
3. Click Form1. Form1 becomes the active form. Form2 displays until you minimize or close it.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

Displaying an Auto-Created VCL Form ( see page 113)

Dynamically Creating a VCL Modal Form ( see page 120)

122
2.5 VCL Procedures RAD Studio Iterating Through Strings in a List

2.5.31 Iterating Through Strings in a List


This VCL application first creates a list of strings. Then it iterates through the strings, changing all string characters to uppercase.
It consists of the following steps:

1. Create a VCL Form with Buttons and TListBox controls.


2. Write the code to create a string list and add strings to it.
3. Write the code to iterate through the string list to process string characters.
4. Run the application.

To create a VCL Form with TButton and TListBox controls


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
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 ToUpper for the Name and Caption properties.

To create a string list and add strings to it


1. Select the Add button on the form. 2
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.AddClick (Delphi) or TForm1::AddClick (C++) event handler block.
3. For Delphi, place the cursor before the begin reserved word; then press ENTER. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created, and type the following variable declaration:
var
MyList: TStringList;
5. Insert the cursor within the code block, and type the following code:
MyList := TStringList.Create;
try
with MyList do
begin
Add('Mice');
Add('Goats');
Add('Elephants');
Add('Birds');
ListBox1.Items.AddStrings(MyList);
end;
finally
MyList.Free;
end;
TStringList *MyList = new TStringList();
try {
MyList->Add(“Mice”);
MyList->Add(“Goats”);
MyList->Add(“Elephants”);
MyList->Add(“Birds”);
ListBox1–>Items->AddStrings( MyList );

123
Writing Cleanup Code RAD Studio 2.5 VCL Procedures

} __finally {
MyList->Free();
}

To change all characters to uppercase


1. Select the ToUpper button on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.ToUpperClick (Delphi) or TForm1::ToUpperClick (C++) event handler block.
3. For Delphi, place the cursor before the begin reserved word; then press return. This creates a new line above the code
block.
4. For Delphi, insert the cursor on the new line created and type the following variable declaration:
var
Index: Integer;
5. Insert the cursor within the code block, and type the following code:
for Index := 0 to ListBox1.Items.Count - 1 do
ListBox1.Items[Index] := UpperCase(ListBox1.Items[Index]);
for( int i = 0; i < ListBox1–>Items->Count; i++ ) {
ListBox1–>Items[i] = UpperCase( ListBox1–>Items[i] );
}

To run the application


1. Save your project files; then choose Run Run to build and run the application. The form displays with the controls.
2. Click the Add button. The strings 'Mice', 'Goats', 'Elephants', and 'Birds' display in the order listed.
3. Click the ToUpper button. The string characters display in uppercase.

2 See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

2.5.32 Building a Multithreaded Application


These are the essential steps to building a VCL Forms multithreaded application with a thread object using RAD Studio.

To drop a component on a form


1. Create a VCL form with a defined thread object.
2. Optionally initialize the thread.
3. Write the thread function.
4. Optionally write the cleanup code.
See Also
VCL Overview ( see page 36)

Defining a Thread Object ( see page 126)

Initializing a Thread ( see page 130)

Writing the Thread Function ( see page 134)

Writing Cleanup Code ( see page 125)

124
2.5 VCL Procedures RAD Studio Avoiding Simultaneous Thread Access to

2.5.33 Writing Cleanup Code


To clean up after your thread finishes executing
1. Centralize the cleanup code by placing it in the OnTerminate event handler. This ensures that the code gets executed.
2. Do not use any thread-local variables, because OnTerminate is not run as part of your thread.
3. You can safely access any objects from the OnTerminate handler.
See Also
VCL Overview ( see page 36)

Building a Multithreaded Application ( see page 124)

2.5.34 Avoiding Simultaneous Thread Access to the Same


Memory
Use these basic techniques to prevent other threads from accessing the same memory as your thread:

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.

To use a critical section


1. Create a global instance of TCriticalSection.
2. Call the Acquire method to lock out other threads while accessing global memory.
3. Call the Release method so other threads can access the memory by calling Acquire. The following code has a global
critical section variable LockXY that blocks access to the global variables X and Y. To use X or Y, a thread must surround that
use with calls to the critical section such as shown here:
LockXY.Acquire;
try
X := X + 1;
Y := sin(X);
finally
LockXY.Release
end;
LockXY->Acquire();
try {
x++;
y = sin( x );

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.

To use the multi-read exclusive-write synchronizer


1. Create a global instance of TMultiReadExclusiveWriteSynchronizer that is associated with the global memory you
want to protect.
2. Before any thread reads from the memory, it must call BeginRead.
3. At the completion of reading memory, the thread must call EndRead.
4. Before any thread writes to the memory, it must call BeginWrite.
5. At the completion of writing to the memory, the thread must call EndWrite.
Warning: The multi-read exclusive-write synchronizer only works if every thread uses it to access the associated global
memory. Otherwise, problems of simultaneous access can occur.
See Also
VCL Overview ( see page 36)

Writing the Thread Function ( see page 134)

Using the Main VCL Thread ( see page 131)

Waiting for Threads ( see page 132)

Handling Exceptions ( see page 129)


2

2.5.35 Defining the Thread Object


To define the thread object
1. Choose File New Other Delphi Projects Delphi Files or File New Other C++Builder Files and double-click the
Thread Object icon. The New Thread Object dialog displays.
2. Enter a class name, for example, TMyThread.
3. Optionally check the Named Thread check box, and enter a name for the thread, for example, MyThreadName.
Tip: Entering a name for Named Thread makes it easier to track the thread while debugging.

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

{ Important: Methods and properties of objects in visual components can only be


used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

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

{ Important: Methods and properties of objects in visual components can only be


used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

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

FThreadID: LongWord; // thread ID (-1 indicates caller thread)


FFlags: LongWord; // reserved for future use, must be zero
end;
{$ENDIF}

{ 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)

__fastcall TMyThread::TMyThread(bool CreateSuspended)


: TThread(CreateSuspended)
{
}

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)
{
}
}

void __fastcall TMyThread::Execute()


{
SetName();
//---- Place thread code here ----
}
See Also
VCL Overview ( see page 36)

Initializing the Thread ( see page 130)

Writing the Thread Function ( see page 134)

Writing Cleanup Code ( see page 125)

2.5.36 Handling Exceptions


To handle exceptions in the thread function
1. Add a try...except block to the implementation of your Execute method.
2. Code the logic such as shown here:
procedure TMyThreadExecute;
begin
try
while not Terminated do
PerformSomeTask;
except
{do something with exceptions}
end;
end;
void __fastcall TMyThread::Execute() {
try {
while( !Terminated() ) {
// perform tasks
}
} catch(...) { // catch specific exceptions first
// exception—handling code
}
}
See Also
VCL Overview ( see page 36)

129
Initializing a Thread RAD Studio 2.5 VCL Procedures

Writing the Thread Function ( see page 134)

Using the Main VCL Thread ( see page 131)

Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)

Waiting for Threads ( see page 132)

2.5.37 Initializing a Thread


To initialize a thread object
1. Assign a default thread priority.
2. Indicate when the thread is freed.

To assign a default priority


1. Assign a default priority to the thread from the values listed in the table below. Use a high-priority to handle time critical tasks,
and a low priority to perform other tasks.

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.

To indicate when a thread is freed


1. Set the FreeOnTerminate property to true, unless the thread must be coordinated with other threads.
2. If the thread requires coordination with another thread, set FreeOnTerminate to false; then explicitly free the first thread
from the second.

130
2.5 VCL Procedures RAD Studio Using the Main VCL Thread

See Also
VCL Overview ( see page 36)

Defining a Thread Object ( see page 126)

Writing the Thread Function ( see page 134)

Writing Cleanup Code ( see page 125)

2.5.38 Using the Main VCL Thread


Using the main VCL thread consists of the following basic steps:

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.

To create a separate routine


1. Write a main thread routine that handles accessing object properties and executing object methods for all objects in your
application.
2. Call the routine using the TThread.Synchronize (Delphi) or TThread::Synchronize method. The following code is an
example of how to call a method using Synchronize
procedure TMyThread.PushTheButton
begin
Button1.Click;
2
end;
procedure TMyThread.Execute;
begin
...
Synchronize(PushThebutton);
...
end;
void TMyThread::PushTheButton() { Form1–>Button1–>Click(); }
void __fastcall TMyThread::Execute() {
...
Synchronize( (TThreadMethod)&PushTheButton );
...
}
Synchronize waits for the main thread to enter the message loop and then executes the passed method.

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.

To use a thread-local variable


1. Identify variables that you want to make global to all the routines running in your thread but not shared by other instances of
the same thread class.

131
Waiting for Threads RAD Studio 2.5 VCL Procedures

2. For Delphi, declare these variables in a threadvar section, for example,


threadvar
x: integer;
For C++, declare these variables with the __thread modifier:
int __thread x;
Note: Use the threadvar

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.

Note: For C++, if you initialize a __thread

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)

Writing the Thread Function ( see page 134)

Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)

Waiting for Threads ( see page 132)

Handling Exceptions ( see page 129)

2 2.5.39 Waiting for Threads


The following are procedures that can be used to wait for threads.

• Wait for a thread to finish executing.


• Wait for a task to complete.
• Check if another thread is waiting for your thread to terminate.

To wait for a thread to finish executing


1. Use the WaitFor method of the other thread.
2. Code your logic. For example, the following code waits for another thread to fill a thread list object before accessing the
objects in the list:
if ListFillingThread.WaitFor then
begin
with ThreadList1.LockList do
begin
for I := 0 to Count - 1 do
ProcessItem(Items[I];
end;
ThreadList1.UnlockList;
end;
if( ListFillingThread->WaitFor() ) {
TList* list = ThreadList1–>LockList();
for( int i = 0; i < list->Count; i++ ) {
DoSomething( list->Items[i] );
}
ThreadList1–>UnlockList();
}

132
2.5 VCL Procedures RAD Studio Waiting for Threads

To wait for a task to complete


1. Create a TEvent object of global scope.
2. When a thread completes an operation other threads are waiting for, have the thread call TEvent.SetEvent.
3. To turn off the signal, call TEvent.ResetEvent.
The following example is an OnTerminate event handler that uses a global counter in a critical section to keep track of the
number of terminating threads. When Counter reaches 0, the handler calls the SetEvent method to signal that all
processes have terminated:
procedure TDataModule.TaskTerminateThread(Sender: TObject);
begin
...
CounterGuard.Acquire; {obtain a lock on the counter}
Dec(Counter); {decrement the global counter variable}
if Counter = 0 then
Event1.SetEvent; {signal if this is the last thread}
Counter.Release; {release the lock on the counter}
...
end;
void __fastcall TDataModule::TaskThreadTerminate( TObject *Sender ) {
...
CounterGuard->Acquire(); // lock the counter
if( ––Counter == 0 ) // decrement counter
Event1–>SetEvent(); // signal if this is the last thread
CounterGuard->Release(); // release lock
}
The main thread initializes Counter, launches the task threads, and waits for the signal that they are all done by calling the
TEvent::WaitFor method. WaitFor waits a specified time period for the signal to be set and returns one of the values in the
table below.
2
The following code example shows how the main thread launches the task threads and resumes when they have completed.
Event1.ResetEvent; {clear the event before launching the threads}
for i := 1 to Counter do
TaskThread.Create(False); {create and launch the task threads}
if Event1.WaitFor(20000) <> wrSignaled then
raise Exception;
{continue with main thread}
Event1–>ResetEvent(); // clear the event before launching threads
for( int i = 0; i < Counter; i++ ) {
new TaskThread( false );
if( Event1–>WaitFor(20000) != wrSignaled )
throw Exception;
// now continue with the main thread
Note: If you do not want to stop waiting for an event handler after a specified time period, pass the WaitFor method a
parameter value of INFINITE. Be careful when using INFINITE, because your thread will hang if the anticipated signal is never
received.

To check if another thread is waiting on your thread to terminate


1. In your Execute procedure, implement the Terminate method by checking and responding to the Terminated property.
2. This is one way to code the logic:
procedure TMyThread.Execute;
begin
while not Terminated do
PerformSomeTask;
end;
void __fastcall TMyThread::Execute() {
while( !Terminated )

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)

Writing the Thread Function ( see page 134)

Using the Main VCL Thread ( see page 131)

Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)

Handling Exceptions ( see page 129)

2.5.40 Writing the Thread Function (Procedure)


The Execute method is your thread function. You can think of it as a program that is launched by your application, except that it
2 shares the same process space. Writing the thread function is a little trickier than writing a separate program, because you must
make sure that you do not overwrite memory that is used by other processes in your application. On the other hand, because the
thread shares the same process space with other threads, you can use the shared memory to communicate between threads.

To implement Execute, coordinate thread execution by


1. Synchronizing with a main VCL thread.
2. Avoiding simultaneous access to the same memory.
3. Waiting for threads.
4. Handling exceptions.
See Also
VCL Overview ( see page 36)

Using the Main VCL Thread ( see page 131)

Avoiding Simultaneous Thread Access to the Same Memory ( see page 125)

Waiting for Threads ( see page 132)

Handling Exceptions ( see page 129)

134
2.5 VCL Procedures RAD Studio Placing A Bitmap Image in a Control in a

2.5.41 Placing A Bitmap Image in a Control in a VCL Forms


Application
This procedure adds a bitmap image to a combo box in a VCL forms application.

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.

To create a VCL form with a TComboBox component


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Win32 page of the Tool Palette, place an TImageList component on the form.
3. From the Standard page of the Tool Palette, place a TComboBox on the form.

To set the component properties


1. Select ComboBox1 in the form.
2. In the Object Inspector, set the Style property drop-down to csOwnerDrawFixed.
2
3. In the Object Inspector, click the ellipsis next to the Items property. The String List Editor displays.
4. Enter a string you would like to associate with the bitmap image, for example, MyImage; then click OK.
5. Double-click ImageList1 in the form. The ImageList editor displays.
6. Click the Add button to display the Add Images dialog.
7. Locate a bitmap image to display in the Combo box. To locate an image, you can search for *.bmp images on your local drive.
Select a very small image such as an icon. Copy it to your project directory, and click Open. The image displays in the
ImageList editor.
8. Click OK to close the editor.

To add the event handler code


1. In the VCL form view, select ComboBox1.
2. In the Object Inspector, click the Events page, and double-click the OnDrawItem event. The Code Editor displays with cursor
in the code block of the ComboBox1DrawItem (Delphi) or ComboBox1::DrawItem (C++) event handler.
3. Enter the following code for the event handler:
Combobox1.Canvas.FillRect(Rect);
ImageList1.Draw(ComboBox1.Canvas, Rect.Left, Rect.Top, Index);
Combobox1.Canvas.TextOut(Rect.Left+ImageList1.Width+2,
Rect.Top, ComboBox1.Items[Index]);
ComboBox1–>Canvas->FillRect( Rect );
ImageList1–>Draw( ComboBox1–>Canvas, Rect.Left, Rect.Top, Index );
ComboBox1–>Canvas->TextOut( Rect.Left + ImageList1–>Width + 2,
Rect.Top,
ComboBox1–>Items[Index] );

135
Renaming Files RAD Studio 2.5 VCL Procedures

To run the program


1. Choose Run Run. The applications executes, displaying a form with a combo box.
2. Click the combo box drop-down. The bitmap image and the text string display as a list item.
See Also
VCL Overview ( see page 36)

Building VCL Forms Applications With Graphics ( see page 93)

2.5.42 Reading a String and Writing It To a File


Creating this VCL application consists of the following steps:

1. Create a VCL Form with a button control.


2. Write the code to read the string and write it to a file.
3. Run the application.

To create a VCL Form


1. Create a directory in which to store your project files.
2. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.

2 3. From the Standard page of the Tool palette, place a TButton component on the form.

To read and write a string


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. For Delphi. place the cursor before the begin reserved word; then press return. This creates a new line above the code
block.
4. Type the following variable declarations:
TFileStream *fs const AnsiString str = "Hello";
5. Insert the cursor within the code block, and type the following code:
fs = new TFileStream("temp.txt", fmCreate);
fs->Write ((void*)str.c_str(), str.fmCreate);

To run the "Hello world" application


1. Save your project files; then choose Run Run to build and run the application. The form displays with a button called
Button1.
2. Click Button1.
3. Use a text editor to open the newly created file temp.txt, which is located in your project directory. The string 'Hello' displays in
the file.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

136
2.5 VCL Procedures RAD Studio Adding and Sorting Strings

2.5.43 Renaming Files


Creating this VCL application consists of the following steps:

1. Create a project directory containing a file to rename.


2. Create a VCL Form with button and label controls.
3. Write the code to rename the file.
4. Run the application.

To set up your project directory and a text file to copy


1. Create a directory in which to store your project files.
2. Either create or copy a text file to your project directory; then save it as MyFile.txt.

To create a VCL Form with a button and label


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Standard page of the Tool palette, place a TButton component on the form.
3. From the Standard page of the Tool palette, place a TLabel component on the form.

To write the rename file procedure


1. Select Button1 on the form.
2
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.Button1Click (Delphi) or TForm1::Button1Click (C++) event handler block.
3. At the cursor, type the following code:
if not RenameFile('MyFile.txt', 'YourFile.txt') then
Label1.Caption := 'Error renaming file!';
if( !RenameFile( "..\\MyFile.txt", "..\\YourFile.txt" )
Label1–>Caption = “Error renaming file”;
// the file parameters assume the target output directory is in your project directory
Note: You cannot rename (move) a file across drives using RenameFile. You would need to first copy the file and then delete
the old one. In the runtime library, RenameFile is a wrapper around the Windows API MoveFile function, so MoveFile will not
work across drives either.

To run the application


1. Save your project file; then choose Run Run to build and run the application. The form displays.
2. Click the button; If no message displays in the Label, check the file name in your project directory. MyFile.txt should is
renamed as YourFile.txt.
3. If the caption label displays the error message, recheck your event handler code.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

137
Adding and Sorting Strings RAD Studio 2.5 VCL Procedures

2.5.44 Adding and Sorting Strings


Creating this VCL application consists of the following steps:

1. Create a VCL Form with Button, Label, and TListBox controls.


2. Write the code to add and sort strings.
3. Run the application.

To create a VCL Form with Button, Label, and ListBox controls


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer displays.
2. From the Standard category of the Tool Palette, place a TButton, TLabel, and TListBox component on the form.

To write the copy stream procedure


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
TForm1.Button1Click event handler block.
3. For Delphi, place the cursor before the begin reserved word and press ENTER. This creates a new line above the code block.
4. Type the following variable declarations:
var
MyList: TStringList;
2 Index: Integer;
TStringList *MyList;
int Index;
5. Insert the cursor within the code block, and type the following code:
MyList := TStringList.Create;
try
MyList.Add('Animals');
MyList.Add('Flowers');

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.

To run the application


1. Save your project files; then choose Run Run to build and run the application. The form displays with the controls.
2. Click the Button. The strings 'Animals', 'Cars', and 'Flowers' display alphabetically in a list in the ListBox. The Label caption
displays the message string: 'Flowers has an index value of 2.'
See Also
VCL Overview ( see page 36)

2.5.45 Creating a VCL Forms ActiveX Button


Like a Delphi control, an ActiveX control generates program code when you place the component on a form or other logical
container in the IDE. The main difference between an ActiveX control and a Delphi control is that an ActiveX control is language
independent. You can create ActiveX controls for deployment to a variety of programming environments on Windows, not just
Delphi or C++Builder.

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:

Metaprocedure for Creating a VCL Forms ActiveX Button


2
1. Create an ActiveX library project for an ActiveX button control.
2. Register the ActiveX button so its icon can be displayed in the toolbar.
3. Create a package for the ActiveX button.
4. Install the package.
5. Test the ActiveX button.

To create an ActiveX library project for an ActiveX button control


1. Create a directory on your local drive for the ActiveX project. Give it a name that you can find easily, for example, ActiveX.
2. Choose File New Other and select the ActiveX page in the New Items dialog box.
3. In the ActiveX folder, double-click ActiveX Library. This creates a Dynamic Link Library [DLL] project that you can use to
host in-process ActiveX Objects.
4. Choose File New Other again.
5. On the ActiveX page, double-click ActiveX Control. The ActiveX Control Wizard displays.
6. In the Component Name drop-down, select TButton.
7. By default, ButtonX displays as the New ActiveX Name. Rename ButtonX to the name you want displayed for your ActiveX
button, for example, MyActiveXButton.
Note: Modifications you make to the name update the Implementation Unit and Project Name. Leave the remaining fields
with default values.

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

Note: If the project is not already an ActiveX library, a Warning


dialog displays and asks you if you want to start a new ActiveX library project.
9. Click OK to start the new ActiveX Library project.

To register the ActiveX button


1. Build the project and save all files to your ActiveX project directory. Dismiss the warning about debugging. The project builds
and creates an OCX file in your project directory.
2. Choose Run Register ActiveX Server to register the ActiveX button. A dialog box displays a message indicating that
registration was successful and it shows the path to the resulting OCX file.
3. Click OK.

To create a new package for the ActiveX button


1. Choose File New Other to create a new package. The New Items dialog displays.
2. Double-click Package on the New page to display the Package - package.dpk dialog and click Add.
3. On the Add unit tab of the Add dialog, browse to your project directory.
4. Select the ButtonXControl1_TLB.pas file, and click Open.
5. Click OK to add the file to the package and return to the Package - package.dpk dialog. The Package - package.dpk dialog
displays showing the files in the package and two required files: rtl.dcp and vcl.dcp.

To add the required files and install the package


1. In the Package - package.dpk dialog, select rtl.dcp, and click Add.
2. On the Add unit tab of the Add dialog, browse to the Lib directory in Delphi, select the rtl.dcp file, and click Open; then click
OK on the Add dialog.
2
3. In the Package - package.dpk dialog, select vcl.dcp, and click Add.
4. On the Add unit tab of the Add dialog, browse to the Lib directory in Delphi, select the vcl.dcp file, and click Open; then click
OK on the Add dialog.
5. In the Package - package.dpk dialog, click Compile to compile the package. A dialog displays, indicating that the package
has been installed. Click OK.
6. Click the X in the upper right corner of the Package - package.dpk dialog to close it. You are prompted to save the package.
7. Save the package to your projects directory.

To test the button


1. Choose File New Application.
2. From the ActiveX page of the Tool Palette, locate your button and place it on the form. The button displays on the form.
See Also
VCL Overview ( see page 36)

Creating a VCL Forms ActiveX Active Form ( see page 140)

2.5.46 Creating a VCL Forms ActiveX Active Form


Like a Delphi control, an ActiveX control generates program code when you place the component on a form or other logical
container in the IDE. The main difference between an ActiveX control and a Delphi control is that an ActiveX control is language
independent. You can create ActiveX controls for deployment to a variety of programming environments on Windows, not just

140
2.5 VCL Procedures RAD Studio Building a VCL Forms Web Browser

Delphi or C++Builder, for example.

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:

1. Create an ActiveX library project for an ActiveX Active Form.


2. Add controls to the Active Form.
3. Add event handling code for the controls.
4. Deploy the project to the Web.
5. Display the form and test the controls in your Web browser.

To create an Active X library project for an ActiveX Active Form


1. Create a directory on your local drive for the ActiveX project. Give it an easy to find name, for example, ActiveX.
2. Create a second directory to contain the ActiveX component and an HTML file for deploying the Active Form to your Microsoft
Internet Explorer Web browser. Name this directory ActiveX_Deploy.
3. Choose File New Other and select the ActiveX page in the New Items dialog.
4. On the ActiveX page, double-click Active Form. The Active Form Wizard displays.
5. Accept the default settings and 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.
Note: If the project is not already an ActiveX library, a Warning
dialog displays and asks you if you want to start a new ActiveX library project.
6. Click OK to start a new ActiveX library project. An ActiveX Active Form displays.

To add some functionality to the Active Form 2


1. From the Standard page of the Tool Palette, add TEdit and TButton components to the form.
2. Select the button.
3. On the Events tab in the Object Inspector, double-click the OnClick event. The Code Editor opens with the cursor in place
in the TActiveFormX.Button1Click (Delphi) or TActiveFormX::Button1Click() (C++) event handler block. Enter
the following code at the cursor:
ShowMessage(Edit1.text);
ShowMessage( Edit1–>Text )
4. Save the project files to your ActiveX directory.
Note: To deploy the Active form to your Web, use the Deployment Manager
. Click File New Other Deployment.

To test the Active Form


1. Launch your browser.
2. Choose File Open, and browse to the ActiveX_Deploy directory.
3. Double-click the HTML file to launch it in the browser window. The Active Form displays in the browser window.
4. Click the button. A pop-up dialog displays the text in the Edit box.
5. Change the text, and click the button again. The new text you entered displays in the pop-up.
See Also
VCL Overview ( see page 36)

Creating a VCL Forms ActiveX Button ( see page 139)

141
Creating an Application that Uses Ribbon RAD Studio 2.5 VCL Procedures

2.5.47 Building a VCL Forms Web Browser Application


Creating the Web browser application consists of the following steps:

1. Create a VCL Form with a button control.


2. Add a TWebBrowser component to the form.
3. Add controls to enter a URL and launch the browser.
4. Write the code to launch the browser when a button is clicked.
5. Run the application.

To create a VCL Form


1. Choose File New Other Delphi Projects or C++Builder Projects and double-click the VCL Forms Application icon. The
VCL Forms Designer is displayed.
2. From the Internet page of the Tool Palette, place a TWebBrowser component on the form.
3. With the TWebBrowser component selected on the form, drag the handles to adjust the size of the browser window. Leave
some space on the form above the TWebBrowser to add a URL entry window. If the window is not large enough to display a
browser page in its entirety, the TWebBrowser component adds scrollbars when you run the application and launch the
browser window.
4. From the Standard page of the Tool Palette, place a TMemo component on the form. With the TMemo component selected
on the form, drag the handles to adjust the size to accommodate a user-entered URL.
5. From the Standard page of the Tool Palette, place a Label component on the form.
2 6. Select the Label, and in the Object Inspector, enter URL: as the Label caption.
7. From the Standard page of the Tool Palette, place a TButton component on the form.
8. Select the Button, and in the Object Inspector, enter OK as the TButton caption.

To code a button click event that launches the browser


1. Select Button1 on the form.
2. In the Object Inspector, double-click the OnClick action on the Events tab. The Code Editor displays, with the cursor in the
Button1Click event handler block.
3. Type the following code:
WebBrowser1.Navigate(WideString(Memo1.Text));
WebBrowser1–>Navigate( WideString( Memo1–>Text ) );

To run the application


1. Choose Run Run to build and run the application.
2. Enter a URL to a Web page in the memo window; then click the button. The browser launches in the TWebBrowser window.
See Also
VCL Overview ( see page 36)

Building a VCL Forms Application ( see page 99)

142
2.5 VCL Procedures RAD Studio Adding Commands to the Ribbon

2.5.48 Creating an Application that Uses Ribbon Controls


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:

1. TRibbon: Main visual component that provides most functionality.


2. TRibbonApplicationMenuBar: Component that provides the functionality of the application menu.
3. TRibbonQuickAccessToolbar: Component that provides the functionality of the Quick Access Toolbar
4. TRibbonPage: Component that represents the page of the ribbon that is currently visible
5. TRibbonGroup: Component that all of the pages commands are displayed in. Commands must be placed in a group.

To create a new application that uses ribbon controls


1. Create a new Delphi Win32 VCL application (select New VCL Forms Application — Delphi for Win32).
2. Drop a TActionManager component onto the form.
3. Drop a TRibbon component onto the form.
4. Right-click the TRibbon component and select the Add Application Menu item.
5. Right-click the TRibbon component again and select the Add Quick Access Toolbar item.
Note: During initial configuring of the ribbon you might see a dialog saying that the current style selected in the
TActionManager.Style is not a valid ribbon style. Change the TRibbonManager.Style property to be the Ribbon – Luna. 2
Applicable styles for use with the ribbon have the Ribbon prefix. By default three ribbon styles are implemented. These ribbon
styles also work with the default ActionManager toolbar and menu bar controls. The available ribbon Styles are:
• Luna
• Obsidian
• Silver
See Also
VCL Overview ( see page 36)

Adding Commands to the Ribbon ( see page 144)

TRibbon

TRibbon

TRibbonApplicationMenuBar

Caption

TRibbonQuickAccessToolbar

TRibbonPage

TRibbonGroup

143
Adding Commands to the Ribbon RAD Studio 2.5 VCL Procedures

2.5.49 Adding Commands to the Ribbon


This topic follows in sequence the creation of a ribbon application using either the Ribbon Application Wizard or the manual
steps described in Creating an Application that Uses Ribbon Controls ( see page 143).

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

csButton Command is a button.


csComboBox Command displays an Office 2007 style combobox. See following Note.
csControl Command has a TControl descendant associated with it. An example is dropping a TEdit component
onto a ribbon Group.
csCustom User-defined.
csGallery Command is a gallery or when selected, it displays a gallery.
csMenu Command is a menu item
csSeparator Command is a separator with a text description.
csText Command only displays text and has no associated control.

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.

Additional Ribbon Component Properties

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)

Building VCL Forms Applications With Graphics ( see page 93)

Creating an Application that Uses Ribbon Controls ( see page 143)


2

146
2.6 WebSnap Procedures RAD Studio Building a WebSnap Application

2.6 WebSnap Procedures


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/.

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:

1. Create an WebSnap project.


2. Change included components (optional).
3. Set page options (optional)
4. Create additional WebSnap pages.
5. Run the application.
Note: WebSnap is being deprecated in RAD Studio.
Although WebSnap is still documented in the online help, 2
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... more ( see page
148)
Building a WebSnap "Hello World" Application ( see page 149) Though simple, the WebSnap "Hello world" application demonstrates the
essential steps for creating an WebSnap application.
Building the WebSnap "Hello world" application consists of five major steps:

1. Create a WebSnap project.


2. Accept the default included components.
3. Set the page title in the page options.
4. Modify the HTML template.
5. Run the application.
Debugging a WebSnap Application using the Web Application Debugger ( see This topic describes the essential tasks for debugging a WebSnap application
page 150) using the Web Application Debugger.
Using the HTML Tag Editor ( see page 151) When you are creating or editing an HTML file, you can use the Tag Editor
window, beneath the Form Designer, to edit the HTML tags. If you are using an
HTML Form, you can display the Tag Editor in the Designer by selecting
View 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... more ( see page 151)

147
Building a WebSnap Application RAD Studio 2.6 WebSnap Procedures

2.6.1 Building a WebSnap Application


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:

1. Create an WebSnap project.


2. Change included components (optional).
3. Set page options (optional)
4. Create additional WebSnap pages.
5. Run the application.
Note: 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/.

To create a WebSnap project


1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select WebSnap Application from the Delphi Projects WebSnap folder.
3. Click OK. The New WebSnap Application dialog appears.
2 4. Select the type of application you are creating.
5. Select your application model components.
6. In the Page Name field, enter the name of your page.
7. Select your caching type from the Caching drop-down.

To change included components (optional)


1. In the New WebSnap Application dialog, click Components. The WebApp Components dialog appears.
2. Select the components you want to include.
Tip: In most cases, the default settings will suffice.

3. Click OK.

To set page options (optional)


1. In the New WebSnap Application dialog, click Page Options. The WebApp Components dialog appears.
2. Set the page options.

To create additional WebSnap pages


1. In the New Items dialog, select WebSnap Page Module from the Delphi Projects WebSnap folder.
2. Configure the page module options and click OK.
3. Add and configure components.
See Also
Web Applications Overview ( see page 41)

148
2.6 WebSnap Procedures RAD Studio Building a WebSnap "Hello World"

Building an WebSnap "Hello world" Application ( see page 149)

2.6.2 Building a WebSnap "Hello World" Application


Though simple, the WebSnap "Hello world" application demonstrates the essential steps for creating an WebSnap application.

Building the WebSnap "Hello world" application consists of five major steps:

1. Create a WebSnap project.


2. Accept the default included components.
3. Set the page title in the page options.
4. Modify the HTML template.
5. Run the application.

To create a WebSnap project


1. Choose File New Other. The New Items dialog appears.
2. In the New Items dialog, select WebSnap Application from the Delphi Projects WebSnap or C++Builder
Projects WebSnap folder.
3. Click OK. The New WebSnap Application dialog appears.
4. Select the Web App Debugger executable radio button.
5. In the Class Name field, enter HelloWorld.
6. Select your application model components. 2
7. In the Page Name field, enter HelloWorld.
8. Select your caching type from the Caching drop-down.

To change included components (optional)


1. In the New WebSnap Application dialog, click Components. The WebApp Components dialog appears.
2. Select the components you want to include.
Tip: In most cases, the default settings will suffice.

3. Click OK.

To set the page title in the page options


1. In the New WebSnap Application dialog, click Page Options. The WebApp Components dialog appears.
2. In the Title field, enter Hello World!.

To modify the HTML template


1. Click on the HTML tab in the IDE.
2. Below the line <h2><%= Page.Title %></h2>, insert a line saying This is my first WebSnap application.
3. Save the application.

To run the "Hello world" application


1. Choose Run Run. An application window opens, and the COM server registers your WebSnap application with the Web
Application Debugger.

149
Debugging a WebSnap Application using RAD Studio 2.6 WebSnap Procedures

2. Close the application window.


3. Choose Tools Web App Debugger . The Web Application Debugger launches.
4. In the Web App Debugger, click the Start button.
5. Click on the Default URL to launch the browser.
6. In the browser, select your Hello World application from the list of applications and click Go. Your application appears in the
browser with the text Hello World! This is my first WebSnap application.
7. Close the Web browser to return to the IDE.
Note: 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/.
See Also
Web Applications Overview ( see page 41)

Building a WebSnap Application ( see page 148)

2.6.3 Debugging a WebSnap Application using the Web


Application Debugger
This topic describes the essential tasks for debugging a WebSnap application using the Web Application Debugger.

2 To debug a WebSnap Application using the Web Application Debugger


1. Register the server information application for the Web Application Debugger.
2. Register your WebSnap application with the Web Application Debugger the first time you run it.
3. Launch the Web Application Debugger.
4. Select and launch your web application.
5. Debug your web application using breakpoints and the Web Application Debugger log.

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.

To register your web application with the Debugger


1. Choose Run Run. This displays the console window of the COM server that is your Web server application.
2. Close the blank application window that opens.
Your COM server is now registered so that the Web App debugger can access it.

To launch the Web Application Debugger


1. Choose Tools Web App Debugger . The Web Application Debugger launches.
2. In the Web App Debugger, click the Start button.
3. Click on the Default URL to launch the browser.

150
2.6 WebSnap Procedures RAD Studio Using the HTML Tag Editor

To select and launch your web application


1. In the browser, select your application from the list of applications.
2. Click Go. Your application appears in the browser.
Note: 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/.
See Also
Web Applications Overview ( see page 41)

Building an WebSnap Application ( see page 148)

2.6.4 Using the HTML Tag Editor


When you are creating or editing an HTML file, you can use the Tag Editor window, beneath the Form Designer, to edit the
HTML tags. If you are using an HTML Form, you can display the Tag Editor in the Designer by selecting View 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.

To view HTML code for an individual control


1. With the Designer displayed, drag an HTML element from the Tool Palette to the Designer surface. The Tag Editor displays
the HTML code.
2. To view the individual control's code, click anywhere on the Designer surface to deselect the control. The HTML code appears
in the tag editor window, with syntax highlighting. The gray header of the tag editor now displays the higher level tag, usually
the FORM tag that defines this particular Web Form.
Note: If a control is defined using several lines of HTML code, when you select the control, the first line of the code is
displayed in the gray header of the tag editor. The additional code appears below in the tag editor window.

To view the HTML code for all controls


1. With the Designer displayed, drag several HTML elements from the Tool Palette to the Designer surface. The editor displays
the HTML code for each element as you drop them on the Designer surface.
2. Click anywhere on the Designer surface to deselect all controls. This displays the code for all the controls in the tag editor,
with syntax highlighting.

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.

To change editor properties


1. Choose Tools Options HTMLOptions.
2. Change any code editor properties.
3. Click OK. Your changes take effect immediately.

To zoom between contents of the form and the form container


1. To zoom out so that you can view the HTML form definition, click the left-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.

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.

To close the Tag Editor


2 1. Choose Tools Options HTML Options.
2. Uncheck the Display Tag Editor option.
3. Click OK.
See Also
Using the Code Editor

Customizing the Code Editor

Using Live Templates

Using Code Insight

152
2.7 Web Services Procedure RAD Studio Building a "Hello World" Web Services

2.7 Web Services Procedure


This section provides how-to information on developing and using 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.

2.7.1 Building a "Hello World" Web Services Application


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.

To build a "Hello World" Web Services application


1. Choose File New Other. The New Items dialog box appears.
2. Select WebServices folder. 2
3. Double-click the Soap Server Application icon. The SOAP Server Application wizard opens.
4. Choose the type of Web server application you want to use for your Web Service. The wizard generates a new Web server
application that includes a Web module that contains three components—HTTPSoapPascalInvoker, HTTPSoapDispatcher,
and WSDLHTMLPublish. When you exit the SOAP Server Application wizard, it asks you if you want to define an interface for
your Web Service.
5. To create a a Web Service from scratch, click Yes. The Add New Web Service wizard opens.
6. To add a new Web Service, specify the name of the invokable interface you want to expose to clients. The Add New Web
Service wizard lets you specify the name of the invokable interface and generates the code to declare and register the
interface and its implementation class.
7. To implement a Web Service that has already been defined in a WSDL document, use the WSDL importer to generate the
interfaces

To use the WSDL importer


1. Choose File New Other. A New Items dialog appears.
2. Select WebServices folder.
3. Double-click the icon labeled WSDL importer. A WSDL Import Wizard appears.
4. In that dialog box, either specify the file name of a WSDL document (or XML file) or click the ellipsis button [...] to browse for
the file.
5. If the WSDL document is on a server that requires authentication, click Options. On the Import Options dialog box, enter the
user name and password required before the wizard can retrieve the WSDL document. After completing the import options,
click OK.
6. Click Next. The WSDL importer displays the code it generates for every definition in the WSDL document that is compatible
with the Web Services framework.

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)

Using Web Services ( see page 2291)

Using Web Services (chapter index) ( see page 2289)

WSDL Import Wizard

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

3.1 C++ Reference


This section contains reference topics for the C++ library in RAD Studio.

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)

3.1.1 Command Line Utilities


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.

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:

• Explicit rules are instructions for specific files.


• Implicit rules are general instructions for files without
explicit rules.
All the rules you write follow this general format: 3
Message Options ( see page 197) Use the -w option to specify message options for the CodeGear C++ compiler:

• 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.

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:

• 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.
TDUMP.EXE, the File Dumping Utility ( see page 204) TDUMP.EXE produces a file dump that shows the structure of a file.
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... more ( see page 204)
TLIB.EXE, the Library Manager ( see page 208) TLIB is a utility that manages libraries of .OBJ (object module) files. A library is a
convenient way to deal with a collection of object modules as a unit.
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.
When TLIB modifies an existing library, TLIB creates a copy of the original library
and gives it a .BAK extension.
You can use TLIB to:

• Create a new library from a... more ( see page 208)


Using TOUCH.EXE ( see page 212) TOUCH.EXE updates a file's date stamp so that it reflects your system’s current
time and date.
TRIGRAPH ( see page 213) 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.
RC.EXE, the Microsoft SDK Resource Compiler ( see page 213) 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:
3 • BRCC32.exe, the CodeGear resource compiler
• RC.exe, the Microsoft platform SDK Resource Compiler
RC supports Unicode characters in resource files and file
names, as well as new Vista resource types such as icons
with alpha channel.
The actual filename of the RC compiler... more ( see page
213)

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)

3.1.1.1 BCC32, the C++ Command-Line Compiler


The CodeGear C++ compiler (BCC32.EXE) is a resource compiler shell. It invokes BRCC32 and RLINK32, depending on the
command-line syntax.

Command Line Syntax


bcc32 [option [option...}] <filename> [<filename>...]

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).

See the BCC32 Command Line Help for Detailed Information


To display the BCC32.exe command line help in the cmd window, include the —h command line option.

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

-U Undefine any previous definitions of name


-Vxxx Compatibility options
-Wxxx Target is a Windows application
-X Disable compiler autodependency output
-axxx Set data alignment boundary. Default is -a8; -a- means -a1
* -b Make enums integer-sized (-b- makes them short as possible)
-c Compile to object file only, do not link
-d Merge duplicate strings
-dc Put strings into the read-only data segment
-dw Put strings into the (writeable) data segment
-e Specify target executable pathname
* -ff Fast floating point
-fp Correct Pentium FDIV flaw
* -fq Use quiet floating point compare instruction (FUCOMP)
-g Stop batch compilation after n warnings (Default = 255)
-h Request help ('-h -' shows all help). Can be specific: -h -V
-i Set maximum significant identifier length (Default = 250)
-j Stop batch compilation after n errors (Default = None)
* -k Generate standard stack frames
-l Pass options to the linker; example: -ls -l-x
-m Generate makefile dependency information
-md Put dependency info in .d files, not in the object file
-mm Ignore system header files while generating dependency info
-mo Specify the output file for dependency info
-n Set output directory for object files
-o Set output filename (-o<filename> or —o <filename> supported)
-pxxx Use Pascal calling convention
-q Suppress compiler identification banner
-r Use register variables
-rd Use register variables only when register keyword is employed
-s Link using the system's non-incremental linker
-txxx An alternate name for the -Wxxx switches; there is no difference
* -u Generate underscores on symbol names
-vxxx Turn on source debugging
-w Display all warnings
-w! Return non-zero from compiler on warnings
-xxxx Enable exception handling
-y Debug line numbers on
-z Options for redefining standard segment names

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.

General Compiler Output Options

161
Command Line Utilities RAD Studio 3.1 C++ Reference

Option Description Details


-c Compiles to Compiles and assembles the named .C, .CPP, and .ASM files, but does not execute a link on the
.OBJ, no link resulting .OBJ files.

-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.

Compiler option precedence rules


The command-line compilers evaluate options from left to right, and follow these rules:

• 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.

Specifying directories in command line options


The CodeGear C++ compiler can search multiple directories for include and library files. The syntax for the library directories
option (-L) and the include directories option (-I), (like the #define option (-D)) allows multiple listings of a given option. Here is
the syntax for these options:
-L <dirname> [<dirname>;...]
-I <dirname> [<dirname>;...]
3
The parameter <dirname> used with -L and -I can be any directory or directory path. You can enter these multiple directories on
the command line in the following ways

• 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.

Using compiler configuration files (.CFG files)


If you repeatedly use a certain set of options, you can list them in a configuration file instead of continually typing them on the
command line. A configuration file is a standard ASCII text file that contains one or more command-line options. Each option
must be separated by a space or a new line.

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.

Using response files


Response files let you list both compiler options and file names in a single file (unlike configuration files, which accept only
compiler options). A response file is a standard ASCII text file that contains one or more command-line options and/or file
names, with each entry in the file separated by a space or a new line. In addition to simplifying your compile commands,
response files let you issue a longer command line than most operating systems allow.

The syntax for using a single response file is:


BCC32 @[path]respfile.txt

The syntax for using multiple response files is:


BCC32 @[path]respfile.txt @[path]otheresp.txt

Response files typically have an .RSP extension.

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)

Using Precompiled Header Files ( see page 203)

Using Module Definition Files ( see page 199)

RLINK32.DLL ( see page 204) 3


BRCC32.EXE ( see page 165)

3.1.1.2 BRC32, the Resource Shell


The Borland resource compiler (BRC32) is a resource compiler shell. It invokes BRCC32 and RLINK32, depending on the
command-line syntax.

163
Command Line Utilities RAD Studio 3.1 C++ Reference

Command Line Syntax


brc32 [options] <filename>.RC [<filename>.EXE]

To display command line help, enter:


brc32

Command Line Options

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.

Version Options (Used with —Vd.d Option)

Option Bit Resulting Look


3.1 16 Gives white background with a non 3-D look for Windows 3.1x, Windows 32s, or WinNT 3.1
4.0 16 Gives gray 3-D look for Windows 95 and WinNT 3.51
3.1 32 Gives white background with a non 3-D look for Windows 32s or WinNT 3.1
4.0 32 Gives gray 3-D look for Windows 95 and WinNT 3.51

Options for Downward Compatibility

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)

BRCC32.EXE ( see page 165)

3.1.1.3 BRCC32.EXE, the Resource Compiler


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.

Command Line Syntax


BRCC32 [<options>] <filename>

To display command line help, enter:


brcc32

Or add the help flag:


brcc32 -h

BRCC32 Command Options

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

-16 Builds a 16–bit resource.


-32 Builds a 32–bit resource.

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.

For example, the following construct can greatly speed up compilation:


#ifndef WORKSHOP_INVOKED#include “windows.h” #endif
Downward Compatibility
The following syntax and options are supported for downward compatibility:

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)

RC.EXE ( see page 213)

3.1.1.4 COFF2OMF.EXE, the Import Library Conversion Tool


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.

Command Line Syntax


Coff2Omf [<options>] InputFile OutputFile

To display command line help, enter:


coff2omf

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.

3.1.1.5 CPP32.EXE, the C Compiler Preprocessor


CPP32.EXE produces a file that lists a C or C++ program, in which all #include 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 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).

Command Line Syntax


CPP32 [<options>] <filename[s]>

To display command line help, enter:


cpp32 -h

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.

CPP32 as a Macro Preprocessor


CPP32 can be used as a macro preprocessor; the resulting .i file can then be compiled with BCC32. The following simple
program illustrates how CPP32 preprocesses a file.

167
Command Line Utilities RAD Studio 3.1 C++ Reference

Source file: HELLOFB.C


#define NAME “Frank CodeGear” #define BEGIN { #define END } main() BEGIN
printf(“%s\n”, NAME);p END

CPP32 Command Line


CPP32 HELLOFB.C

Output (written to HELLOFB.I)


/* HELLOFP.C 1: */

/* HELLOFP.C 2: */

/* HELLOFP.C 3: */

/* HELLOFP.C 4: */

/* HELLOFP.C 5: */main()

/* HELLOFP.C 6: */printf("%s\n", "Frank CodeGear");

/* HELLOFP.C 7: */}
/* HELLOFP.C 8: */}

Using MIDL with CPP32


MIDL (Microsoft Interface Definition Language) is an RPC compiler. In order to use MIDL with the C++ preprocessor
(CPP32.EXE), you must use the following MIDL command:

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.

BCC32, CPP32 and UUIDs


In some cases, CPP32 does not accept valid UUIDs. For example, a valid UUID statement is:
uuid(5630EAA0-CA48-1067-B320-00DD010662DB)
3
When CPP32 encounters 5630EAA0, it is classified as a floating-point number, and since it is an invalid floating point number,
the preprocessor emits an error. To work around this problem, enclose the UUID within quotes. When using MIDL with CPP32,
use the -ms_ext option. The UUID statement becomes:
uuid("5630EAA0-CA48-1067-B320-00DD010662DB")

and the MIDL command line becomes:


MIDL -ms_ext -cpp_cmd CPP32 -cpp_opt " -oCON {<CPP32 options>}" {<MIDL options>} {<.idl/.acf

168
3.1 C++ Reference RAD Studio Command Line Utilities

file>}

See Also
BCC32.EXE ( see page 159)

3.1.1.6 DCC32.EXE, the Delphi Command Line Compiler


DCC32 is the Delphi (Object Pascal) command line compiler.

To display command line help, enter:


dcc32
or:
dcc32 —h
or:
dcc32 —help
C:\>dcc32
CodeGear Delphi for Win32 compiler version 18.5
Copyright (c) 1983,2007 CodeGear

Syntax: dcc32 [options] filename [options]

-A <unit>=<alias> = Set unit alias


-B = Build all units
-CC = Console target
-CG = GUI target
-D<syms> = Define conditionals
-E<path> = EXE/DLL output directory
-F<offset> = Find error
-GD = Detailed map file
-GP = Map file with publics
-GS = Map file with segments
-H = Output hint messages
-I<paths> = Include directories
-J = Generate C .obj file
-JP = Generate C++ object file
-JPN = Generate C++ .obj, include namespace
-JPE = Generate C++ .obj, export all symbols
-JPH = Generate C++ .obj, export symbols, generate header .hpp files
-JPHNE = Generate C++ .obj file, .hpp file, in namespace, export all
-JL = Generate package .lib, .bpi, and all .hpp files for C++
-K<addr> = Set image base addr
-LE<path> = package .bpl output directory
-LN<path> = package .dcp output directory
-LU<package> = Use package
-M = Make modified units
-N0<package> = Use package
-M = Make modified units
-N0<path> = unit .dcu output directory
-NH<path> = unit .hpp output directory
-NO<path> = unit .obj output directory 3
-NB<path> = unit .bpi output directory
-NS<namespace> = Namespace search path
-O<paths> = Object directories
-P = look for 8.3 file names also
-Q = Quiet compile
-R<paths> = Resource directories
-U<paths> = Unit directories
-V = Debug information in EXE
-VR = Generate remote debug (RSM)

169
Command Line Utilities RAD Studio 3.1 C++ Reference

-W[+|-][warn_id] = Output warning messages


-Z = Output 'never build' DCPs
-$<dir> = Compiler directive
--help = Show this help screen
--version = Show name and version
--codepage:<cp> = specify source file encoding
--default-namespace:<namespace> = set namespace
--depends = output unit dependency information
--doc = output XML documentation
--drc = output resource string .drc file
--no-config = do not load default DCC32.CFG file
--description:<string> = set executable description
Compiler switches: -$<state> (defaults are shown below)
A8 Aligned record fields
B- Full boolean Evaluation
C+ Evaluate assertions at runtime
D+ Debug information
G+ Use imported data references
H+ Use long strings by default
I+ I/O checking
J- Writeable structured consts
L+ Local debug symbols
M- Runtime type info
O+ Optimization
P+ Open string params
Q- Integer overflow checking
R- Range checking
T- Typed @ operator
U- Pentium(tm)-safe divide
V+ Strict var-strings
W- Generate stack frames
X+ Extended syntax
Y+ Symbol reference info
Z1 Minimum size of enum types
Creating C++ Files from DCC32
If you want to generate .hpp files (and the corresponding .obj) from a .pas file, you should use -JPHNE.

You can also use -JL on the .dpk file containing the .pas file.

3.1.1.7 GREP.EXE, the text search utility


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.

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.)

Command Line Syntax


The general command-line syntax for GREP is
grep [-<options>] <searchstring> [<files(s)>...]

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
(|).

Redirecting Output from GREP


If you find that the results of your GREP are longer than one screen, you can redirect the output to a file.

For example, you could use this command:


GREP "Bob" *.txt > temp.txt
This command searches all files with the TXT extension in the current directory, then puts the results in a file called TEMP.TXT.
(You can name this file anything you like.) Use any word processor to read TEMP.TXT (the results of the search).

GREP Command Line Options


You can pass options to the GREP utility on the command line by specifying one or more single characters preceded by a
hyphen (-). Each individual character is a switch that you can turn on or off: A plus symbol (+) after a character turns the option
on; a hyphen (-) after the character turns the option off. The + sign is optional; for example, -r means the same thing as -r+. You
can list multiple options individually (like this: -i -d -l), or you can combine them (like this: -ild or -il, -d, and so on).

Here are the GREP option characters and their meanings:

Command Line Options for GREP

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.

The Search String


The value of <searchstring> defines the pattern GREP searches for. A search string can be either a regular expression or a
literal string.

• 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

Command Line Syntax


ILINK32 [@<respfile>][<options>] <startup> <myobjs>, [<exe>], [<mapfile>], [<libraries>],
[<deffile>], [<resfile>]

To display command line help, enter:


ilink32

Linker command-line options are case-sensitive.

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).

/Gk Keeps output files on error. Default is Off.


3
/Gl Generates a .LIB file.
/Gpd Generates design-time-only package. Default is: the package works at both design time and
runtime.
/Gpr Generate runtime-only package Default is: the package works at both design time and runtime.
/Gn Don't generate state files (disable incremental linking). Subsequent links will take just as long as
the first one. Default is Off.

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

/Tpe Targets a 32-bit Windows EXE file.


/Tpp Generates a package.
/t Displays time spent on link.
/w Turns all warnings on.
/w-dee Disables the warning: “.EXE module built with a .DLL or BPL extension.”
/w-dpl Disables the warning: “Duplicate symbol in library.”.
/w-dup Disables the warning: “Duplicate symbol.”
/w-exp Enables the warning: “Attempt to export non-public symbol..”
/w-nou Disables the warning: “Creating a package without any units.”
/w-rty Enables the warning: “Unable to perform incremental link - performing full link”.
/w-srd Disables the warning: “Stripping relocations from a DLL may cause it to malfunction.”
/w-snf Disables the warning: “Section not found.”
/w-uld Disables the warning: “Unable to load DLL.”
/x Suppresses creation of a MAP file.
(blank) Default map file of segments (no linker switch, map file created by default)

Linker Response Files


You can use response files with the command-line linker to specify linker options.

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

Module Definition Files


The module definition file is an ASCII text file that provides information to ILINK32 about the contents and system requirements
of a Windows application. You can create a module definition file using IMPDEF.EXE, and you can create import libraries from
module definition files using IMPLIB.EXE.

If no module definition file is specified, the following defaults are assumed:


CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE (for applications)
PRELOAD MOVEABLE SINGLE (for DLLs)
HEAPSIZE 4096
STACKSIZE 1048576
To change an application's attributes from these defaults, you need to create a module definition file.

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.

Debug Information File


If you include debug information in your final linked executable, ILINK32 will always store the debug information in a separate
.TDS file, named <Project Name>.TDS by default. The debugger should be able to read this debugger-information file. ILINK32
will always create this file. If you do not have the -v linker switch set, the TDS file is marked as invalid.

See Also
RLINK32.EXE ( see page 204)

IMPDEF.EXE ( see page 179)

Module Definition Files ( see page 199)

3.1.1.9 IMPDEF.EXE, the Module Definition Manager


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 3
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 the DLL.

Command Line Syntax


IMPDEF <options> <destination.def> <source.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

To display command line help, enter:


impdef

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)

IMPLIB.EXE ( see page 181)

Module Definition Files ( see page 199)

3.1.1.10 IMPLIB.EXE, the Import Library Tool


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).

Command Line Syntax


IMPLIB <options> <LibName> [< DefFiles>... | <DLLs>... ] [@<ResponseFile> | <sourcename> ]
[<sourcename> ...]

To display command line help, enter:


implib
3

181
Command Line Utilities RAD Studio 3.1 C++ Reference

Command Line Description


Element

<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.

<LibName> The name for the new import library.


<DefFiles> One or more existing module definition files for one or more DLLs. You must specify at least one DLL or
module definition file.
<DLLs> One or more existing DLLs. You must specify at least one DLL or one module definition file.
@<ResponseFile> An ACSII text file that contains a list of DEF and DLL files that you want to process using IMPLIB. In the
response file, separate the filenames using either spaces or new lines.
<sourcename> Either a DEF or DLL file that is to be processed by IMPLIB.

Example

implib foo.lib @respon.txt

Note: A DLL can also have an extension of .EXE or .DRV, not just .DLL.

See Also
IMPDEF.EXE ( see page 179)

3.1.1.11 Using Include Files


In C++, include files always have the file extension .h.

Include File Search Algorithms


The CodeGear C++ compiler searches for files included in your source code with the #include directive in the following ways:

• 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

Library File Search Algorithms


The library file search algorithms are similar to those for include files:

• 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.

Command Line Syntax


MAKE [<options>...][<target>[<target>]]

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 display command line help, enter:


make —? 3
or:
make —h

Command Line Element Description


[<options>] MAKE options that control how MAKE works. See “Make Command Options” in this topic.

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

Default MAKE Actions


When you issue a MAKE command, MAKE looks for the file BUILTINS.MAK, a file that you create to contain the default rules for
MAKE (use the -r option to ignore the default rules). MAKE looks for this file first in the current directory, then in the directory
where MAKE.EXE is stored. After loading BUILTINS.MAK, MAKE looks in the current directory for a file called MAKEFILE or
MAKEFILE.MAK (use the -f option to specify a file other than MAKEFILE). If MAKE can’t find the makefile, it generates an error
message.

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.

Makefiles can contain:

• Comments (precede a comment with a number sign [#])


• Explicit and implicit rules
• Macros
• Directives

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

• Do not type a line of commands after the symbolic target line.


• A symbolic target must have a unique name; it cannot be the name of a file in your current directory.
• Symbolic target names must follow the operating system rules for naming files.

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.

Here is a sample of a BUILTINS.MAK file:


#
# CodeGear C++ BUILTINS.MAK
#

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 $&

.SUFFIXES: .exe .obj .asm .c .res .rc

!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 -?.

For example, to use a file called PROJECTA.MAK as the makefile, type:


MAKE -fPROJECTA.MAK
Many of the command-line options have equivalent directives that you can use within the makefile.

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)

MAKE Directives ( see page 186)

MAKE Rules and Commands ( see page 193)

3.1.1.13 MAKE Directives


3 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:

186
3.1 C++ Reference RAD Studio Command Line Utilities

Directive Option Description/Example


(if
available)
.autodepend -a Turns on autodependency checking.
Autodependencies are the files that are automatically included in the targets you build, such
as the header files included in your C++ source code. With .autodepend on, MAKE
compares the dates and times of all the files used to build the .OBJ, including the
autodependency files. If the dates or times of the files used to build the .OBJ are newer than
the date/time stamp of the .OBJ file, the .OBJ file is recompiled. You can use .autodepend
(or -a) in place of forming linked dependencies.
.cacheautodepend -c Turns on autodependency caching.
!cmdswitches Uses + or - followed by non-string option letters to turn each option on or off. Spaces or tabs
must appear before the + or - operator, none can appear between the operator and the
option letters.
!elif Acts like a C else if.
!else Acts like a C else.
!endif Ends an !if, !ifdef, or !ifndef statement
!error Stops MAKE and prints an error message The syntax of the !error directive is: !error
<message>
MAKE stops processing and prints the following string when it encounters this directive:
Fatal makefile exit code: Error directive: <message>
Embed !error in conditional statements to abort processing and print an error message, as
shown in the following example: !if !$d(MYMACRO) #if MYMACRO isn't defined
!error MYMACRO isn't defined ! endif
If MYMACRO isn't defined, MAKE terminates and prints:

Fatal makefile 4: Error directive: MYMACRO isn't defined


Error-Checking Controls: MAKE offers four different error-checking controls:
• The .ignore directive turns off error checking for a selected portion of the makefile.
• The -i command-line option turns off error checking for the entire makefile.
• The -num prefix, which is entered as part of a rule, turns off error checking for the
related command if the exit code exceeds the specified number.
• The - prefix turns off error checking for the related command regardless of the exit code.

!if Begins a conditional statement.


!ifdef Acts like a C #ifdef, testing whether a given macro has been defined.
!ifndef Acts like a C #ifndef, testing whether a given macro is undefined.
.ignore -i MAKE ignores the return value of a command.
!include Acts like a C #include, specifying a file to include in the makefile.
This directive is like the #include preprocessor directive for the C or C++ language -- it lets
you include the text of another file in the makefile: !include <filename>
3
You can enclose the filename in quotation marks (" ") or angle brackets (< >) and nest
directives to unlimited depth, but writing duplicate !include directives in a makefile isn't
permitted -- you'll get the error message cycle in the include file.
Rules, commands, or directives must be complete within a single source file; you can't start
a command in an !include file, then finish it in the makefile. MAKE searches for !include files
in the current directory unless you've specified another directory with the -I command-line
option.

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

.nocacheautodepend Turns off autodependency caching.


c

.noIgnore Turns off .Ignore.


i

.nokeep Does not keep temporary files that MAKE creates.


K

.nosilent Displays commands before MAKE executes them.


s

.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

Using Macros in Directives


You can use the $d macro with the !if conditional directive to perform some processing if a specific macro is defined. Follow the
$d with macro name enclosed in parentheses or braces, as shown in the following example:
!if $d(DEBUG) #If DEBUG is defined,
bcc32 -v f1.cpp f2.cpp #compile with debug information;
!else #otherwise
bcc32 -v- f1.cpp f2.cpp #don't include debug information.
!endif

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

!if condition !if condition !if condition !ifdef macro


!endif !else !elif condition !endif
!endif !endif

The following expressions are equivalent:


!ifdef macro and !if $d(macro)
ifndef macro and !if !$d(macro)
These rules apply to conditional directives:

• 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:

Operator Description Operator Description


- Negation ?: Conditional expression
~ Bit complement ! Logical NOT
+ Addition >> Right shfit
- Subtraction << Left shift
* Multiplication & Bitwise AND
/ Division | Bitwise OR
% Remainder ^ Bitwise XOR
&& Logical AND >+ Greater than or equal to *
|| Logical OR <+ Less than or equal to *
> Greater than == Equality *
3 < Less than != Inequality *

• The Operator also works with string expressions.


MAKE evaluates a conditional expression as either a 32-bit signed integer or a character string.
See Also
Using MAKE.EXE ( see page 183)

MAKE Macros ( see page 191)

190
3.1 C++ Reference RAD Studio Command Line Utilities

MAKE Rules and Commands ( see page 193)

3.1.1.14 MAKE Macros


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 expands macros at various times depending on where they appear in the makefile:

• Nested macros are expanded when the outer macro is invoked.


• Macros in rules and directives are expanded when MAKE first looks at the makefile.
• Macros in commands are expanded when the command is executed.
If MAKE finds an undefined macro in a makefile, it looks for an operating system environment variable of that name (usually
defined with SET) and uses its definition as the expansion text. For example, if you wrote $(PATH) in a makefile and never
defined PATH, MAKE would use the text you defined for PATH in your AUTOEXEC.BAT. See your operating system manuals
for information on defining environment variables.
Syntax
<MacroName> = <expansion_text>

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.

String Substitution in MAKE Macros


MAKE lets you temporarily substitute characters in a previously defined macro. For example, if you define the following macro:
3
SOURCE = f1.cpp f2.cpp f3.cpp

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.

Rules for macro substitution:

• Syntax: $(MacroName:original_text=new_text)

191
Command Line Utilities RAD Studio 3.1 C++ Reference

• No space before or after the colon


• Characters in original_text must exactly match the characters in the macro definition (text is case-sensitive)
MAKE also lets you use macros within substitution macros. For example:
MYEXT=.C
SOURCE=f1.cpp f2.cpp f3.cpp
$(SOURCE:.cpp=$(MYEXT)) #Changes 'f1.cpp' to 'f1.C', etc.
The caret (^) symbol causes MAKE to interpret the next character literally. This is useful for inserting a new-line character. For
example:
MYEXT=.C
SOURCE=f1.cpp f2.cpp f3.cpp
($(SOURCE):.cpp=$(MYEXT)^
) # changes 'f1.cpp f2.cpp f3.cpp' to:
# f1.C
# f2.C
# f3.C
Here, the caret tells MAKE to change each occurrence of .cpp to .C followed by the new-line character.

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.

Macro Expands in Implicit Rule Expands in Explicit Rule


$* path\dependent file path\target file
$< path\dependent file+ext path\target file+ext
$: path for dependents path for target
$. dependent file+ext target file + ext
$& dependent file target file
3 $** path\dependent file+ext all dependents file+ext
$? path\dependent file+ext old dependents

Macro Expands to Comment


_ _MSDOS_ _ 1 If running under DOS

192
3.1 C++ Reference RAD Studio Command Line Utilities

_ _MAKE_ _ 0x0370 MAKE's hex version number


MAKE make MAKE's executable file name
MAKEFLAGS options The options typed on the command line
MAKEDIR directory Directory where MAKE.EXE is located

Modifying Default MAKE Macros


If the default macros don't give you the exact string you want, macro modifiers let you extract parts of the string to suit your
purpose. Macro modifiers are usually used with $< or $@.

To modify a default macro, use this syntax:


$(MacroName [modifier])
The following table lists macro modifiers and provides examples of their use:

Modifier Part of File Name Expanded Example Result


D Drive and directory $(<D) C:\PROJECTA\
F Base and extension $(<F) MYSOURCE.C
B Base only $(<B) MYSOURCE
R Drive, directory, and base $(<R) C:\PROJA\SOURCE

See Also
Using MAKE.EXE ( see page 183)

MAKE Directives ( see page 186)

MAKE Rules and Commands ( see page 193)

3.1.1.15 MAKE Rules (Explicit and Implicit) and Commands


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:

• Explicit rules are instructions for specific files.


• Implicit rules are general instructions for files without explicit rules.
All the rules you write follow this general format:
Dependency line
Command line
While the dependency line has a different syntax for explicit and implicit rules, the command line syntax stays the same for both
rule types.

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

rules are written for the target(s).

Explicit rules follow this syntax:


<target> [<target>...]:[:][{<path>}] [<dependent[s]>...]
[<commands>]

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

Single Targets with Multiple Rules


A single target can have more than one explicit rule. To specify more than a single explicit rule, use a double colon (::) after the
target name.

The following example shows targets with multiple rules and commands:
.cpp.obj:
bcc32 -c -ncobj $<

.asm.obj:
tasm /mx $<, asmobj\

mylib.lib :: f1.obj f2.obj #double colon specifies multiple rules


echo Adding C files
tlib mylib -+cobjf1 -+cobjf2

mylib.lib :: f3.obj f4.obj


echo Adding ASM files
tlib mylib -+asmobjf3 -+asmobjf4
3 Implicit Rule Syntax
An implicit rule specifies a general rule for how MAKE should build files that end with specific file extensions. Implicit rules start
with either a path or a period. Their main components are file extensions separated by periods. The first extension belongs to the
dependent, the second to the target.

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.

Implicit rules follow this basic syntax:

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.

Explicit Rules with Implicit Commands


A target in an explicit rule can get its command line from an implicit rule. The following example shows an implicit rule followed
by an explicit rule without a command line:
.c.obj:
bcc32 -c $< #This command uses a macro $< described later
myprog.obj: #This explicit rule uses the command: bcc32 -c myprog.c
The implicit rule command tells MAKE to compile MYPROG.C (the macro $< replaces the name myprog.obj with myprog.c).

MAKE Command Syntax


Commands immediately follow an explicit or implicit rule and must begin on a new line with a space or tab. Commands can be
any operating system command, but they can also include MAKE macros, directives, and special operators that your operating
system won’t recognize (however, note that | can't be used in commands).

Here are some sample commands:


cd..
bcc32 -c mysource.c
COPY *.OBJ C:\PROJECTA
bcc32 -c $(SOURCE) #Macros in "Using MAKE macros"
Commands follow this general syntax:
[<prefix>...] <commands>
Command Prefixes

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.

In the following example, MAKE continues processing if BCC32 returns errors:


target.exe : target.obj
target.obj : target.cpp
-bcc32 -c target.cpp
Using &

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
&copy $** 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.

MAKE Command Operators


While you can use any operating system command in a MAKE command section, you can also use the following special
operators:

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)

MAKE Macros ( see page 191)

MAKE Directives ( see page 186)

196
3.1 C++ Reference RAD Studio Command Line Utilities

3.1.1.16 Message Options


Use the -w option to specify message options for the CodeGear C++ compiler:

• 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

-wdef 8013 Possible use of '%s' before definition


* -wdig 8014 Declaration ignored
* -wdpu 8015 Declare '%s' prior to use in prototype
* -wdsz 8016 Array size for 'delete' ignored
* -wdup 8017 Redefinition of '%s' is not identical
* -weas 8018 Assigning %s to %s
* -weff 8019 Code has no effect 3
* -wext 8020 '%s' is declared as both external and static
-wexc 8101 Extern C linkage ignored
* -whch 8021 Handler for '%s' hidden by previous handler for '%s'
* -whid 8022 '%s' hides virtual function '%s'
* -wias 8023 Array variable '%s' is near
* -wibc 8024 Base class '%s' is also a base class of '%s'
* -will 8025 Ill-formed pragma
-winl 8026 Functions %s are not expanded inline
-winl 8027 Functions containing %s are not expanded inline

197
Command Line Utilities RAD Studio 3.1 C++ Reference

* -wifr 8085 Function '%s' redefined as non-inline


-wimp 8102 Implicit conversion of '%s' to '%s'
* -wlin 8028 Temporary used to initialize '%s'
* -wlvc 8029 Temporary used for parameter '%s'
* -wlvc 8030 Temporary used for parameter '%s' in call to '%s'
* -wlvc 8031 Temporary used for parameter %d
* -wlvc 8032 Temporary used for parameter %d in call to '%s'
* -wmpc 8033 Conversion to '%s' will fail for members of virtual base '%s'
* -wmpd 8034 Maximum precision used for member pointer type '%s'
* -wmsg 8035 %s
* -wmes 8095 Incorrect use of #pragma message( "string" )
* -wmcs 8096 Incorrect use of #pragma code_seg(["seg_name"[,"seg_class"]])
* -wmcc 8098 Multi-character character constant
-wnak 8036 Non-ANSI keyword used: '%s'
-wnak 8036 Non-ANSI keyword used: '%s'
* -wncf 8037 Non-const function %s called for const object
* -wnci 8038 Constant member '%s' is not initialized
* -wncl 8039 Constructor initializer list ignored
* -wnfd 8040 Function body ignored
* -wngu 8041 Negating unsigned value
* -wnin 8042 Initializer for object '%s' ignored
* -wnma 8043 Macro definition ignored
* -wnmu 8044 #undef directive ignored
-wnod 8045 No declaration for function '%s'
* -wnop 8046 Pragma option pop with no matching option push
* -wnsf 8047 Declaration of static function '%s(...)' ignored
* -wnst 8048 Use qualified name to access member type '%s'
* -wntd 8049 Use '< <' for nested templates instead of '<<'
* -wnto 8050 No type OBJ file present. Disabling external types option.
* -wnvf 8051 Non-volatile function %s called for volatile object
* -wnpp 8083 Pragma pack pop with no matching pack push
* -wobi 8052 Base initialization without a class name is now obsolete
* -wobs 8053 '%s' is obsolete
* -wofp 8054 Style of function definition is now obsolete
* -wosh 8055 Possible overflow in shift operation
* -wovf 8056 Integer arithmetic overflow
* -wonr 8097 Not all options can be restored at this time
* -wpar 8057 Parameter '%s' is never used
* -wpch 8058 Cannot create pre-compiled header: %s
* -wpck 8059 Structure packing size has changed
* -wpia 8060 Possibly incorrect assignment
-wpin 8061 Initialization is only partially bracketed
* -wpow 8062 Previous options and warnings not restored
* -wpre 8063 Overloaded prefix 'operator %s' used as a postfix operator
* -wpro 8064 Call to function with no prototype
* -wpro 8065 Call to function '%s' with no prototype
-wprc 8084 Suggest parentheses to clarify precedence
* -wpcm 8094 Incorrect use of #pragma comment( <type> [,"string"] )
* -wpsb 8099 Static `main' is not treated as an entry point
* -wrch 8066 Unreachable code
* -wret 8067 Both return and return with a value used
* -wrng 8068 Constant out of range in comparison
* -wrpt 8069 Nonportable pointer conversion
* -wrvl 8070 Function should return a value
-wsig 8071 Conversion may lose significant digits
* -wspa 8072 Suspicious pointer arithmetic
3 -wstu 8073 Undefined structure '%s'
-wstv 8074 Structure passed by value
* -wsus 8075 Suspicious pointer conversion
-wstl 8087 '%s::operator==' must be publicly visible to be contained by a '% s'
-wstl 8089 '%s::operator<' must be publicly visible to be contained by a '%s'
-wstl 8090 '%s::operator<' must be publicly visible to be used with '%s'
-wstl 8091 %s argument %s passed to '%s' is a %s iterator: %s iterator required
-wstl 8092 %s argument %s passed to '%s' is not an iterator: %s iterator required
* -wtai 8076 Template instance '%s' is already instantiated
* -wtes 8077 Explicitly specializing an explicitly specialized class member makes no sense

198
3.1 C++ Reference RAD Studio Command Line Utilities

* -wthr 8078 Throw expression violates exception specification


-wucp 8079 Mixing pointers to different 'char' types
-wuse 8080 '%s' is declared but never used
* -wvoi 8081 void functions may not return a value
* -wzdi 8082 Division by zero

3.1.1.17 Module Definition Files


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.

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

DESCRIPTION Statement (optional)


Inserts text into the application module and is typically used to embed author, date, or copyright information:
DESCRIPTION 'Text'
Text is an ASCII string delimited with single quotes.

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;

[ dll.def ] EXPORTS _sample

[ in application source file (app.cpp) ]


int _declspec(dllimport) sample;

[ 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

<SegmentName> [CLASS '<ClassName>']

[<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)

IMPDEF ( see page 179)

3.1.1.18 Using Precompiled Header Files


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

Compiler Description Details 3


Option
-H Generate When you enable this option, the compiler generates and uses precompiled headers. The
and use default file name is BC32DEF.CSM for the command-line compiler.
-Hu Use but do When you enable this option, the compiler uses preexisting precompiled header files; new
not generate precompiled header files are not generated.

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)

3.1.1.19 RLINK32.DLL, the Resource Linker (C++)


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:

• 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)

ILINK32.EXE ( see page 174)

3.1.1.20 TDUMP.EXE, the File Dumping Utility


TDUMP.EXE produces a file dump that shows the structure of a file.

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.

Command Line Syntax


TDUMP [<options>] <inputfile> [<listfile>] [<options>]

• <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?.

-r Causes TDUMP to display raw data.


-R Causes TDUMP to dump relocation tables from 32-bit PE (Win32) format images. The default is to suppress these
dumps.

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.

3 3.1.1.21 TLIB.EXE, the Library Manager


TLIB is a utility that manages libraries of .OBJ (object module) files. A library is a convenient way to deal with a collection of
object modules as a unit.

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.

You can use TLIB to:

• Create a new library from a group of object modules.


• Add object modules or other libraries to an existing library.
• Remove object modules from an existing library.
• Replace object modules from an existing library.
• Extract object modules from an existing library.
• List the contents of a new or existing library.
TLIB can also create (and include in the library file) an extended dictionary, which can be used to speed up linking.
Although TLIB is not essential for creating executable programs with the CodeGear C++ compiler, it is a useful programming
productivity tool that can be indispensable for large development projects.
Command Line Syntax
TLIB <libname> [<options>] [<operations>] [@<respfile>] [, <listfile>]

To display command line help, enter:


tlib

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.

TLIB General Command Options


TLIB recognizes five <options>:
3
• /C (case-sensitive; see further information below)
• /l (produces a listing file on standard output)
• /P (page size; see further information below)
• /0 (zero; purges comment records)
• /8 (displays warnings and messages encoded as UTF8)

209
Command Line Utilities RAD Studio 3.1 C++ Reference

TLIB /C Option: Using Case-Sensitive Symbols in a Library


When you add a module to a library, TLIB maintains a dictionary of all public symbols defined in the modules of the library. All
symbols in the library must be distinct. If you try to add a module to the library that duplicates a symbol, TLIB displays an error
message and doesn't add the module.

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.

TLIB /P option: Setting the Page Size to Create a Large Library


The library page size determines the maximum combined size of all object modules in the library, which cannot exceed 65,536
pages. The default (and minimum) page size of 16 bytes allows a library of about 1 MB in size. To create a larger library, use the
/P option to increase the page size. The page size must be a power of 2, and it cannot be smaller than 16 or larger than 32,768.

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.

TLIB Default Action Options


The default action options allow you to specify an action or several actions that are used for every subsequent module that does
not have an explicit command specified, or until a different action flag is set. Using the default action options enables you to
specify modules in a TLIB command without having to prefix each module with a command or action symbol. The TLIB default
action options perform actions similar to those performed by the TLIB operation flags described in TLIB Operations List.

TLIB Default Action Options

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.

TLIB Operations List


The operation list describes the actions you want TLIB to do and consists of a sequence of operations given one after the other.
3 Each operation consists of a one- or two-character action symbol followed by a file or module name.:
<symbol> modulename
You can put whitespace around either the action symbol or the file or module name, but not in the middle of a two-character
action or in a name. You can put as many operations as you like on the command line, up to DOS's COMMAND.COM-imposed
line-length limit of 127 characters. The order of the operations is not important. TLIB always applies the operations in a specific
order:

To replace a module, remove it, then add the replacement module.

210
3.1 C++ Reference RAD Studio Command Line Utilities

1. All extract operations are done first.


2. All remove operations are done next.
3. All add operations are done last.
TLIB finds the name of a module by stripping any drive, path, and extension information from the given file name.
Note that TLIB always assumes reasonable defaults. For example, to add a module that has an .OBJ extension from the current
directory, you need to supply only the module name, not the path and .OBJ extension.
Wildcards are never allowed in file or module names.
TLIB recognizes three action symbols (*, +, -), which you can use singly or combined in pairs for a total of five distinct operations.
The order of the characters is not important for operations that use a pair of characters.
To create a library, you add modules to a library that does not yet exist.
TLIB Action Symbols

Symbol Name Description


+ Add TLIB adds the named file to the library. If the file has no extension, TLIB assumes an extension of .OBJ. If
the file is itself a library (with a .LIB extension), then the operation adds all of the modules in the named
library to the target library.
If a module being added already exists, TLIB displays a message and does not add the new module.
— Remove TLIB removes the named module from the library. If the module does not exist in the library, TLIB displays
a message.
A remove operation needs only a module name. TLIB lets you enter a full path name with drive and
extension included, but ignores everything except the module name.
* Extract TLIB creates the named file by copying the corresponding module from the library to the file. If the module
does not exist, TLIB displays a message and does not create a file. If the named file already exists, it is
overwritten.
You can't directly rename modules in a library. To rename a module, extract and remove it, rename the file
just created, then add it back into the library.
—* or Extract TLIB copies the named module from the library to the file. If the module does not exist, TLIB displays a
*— and message and does not create a file. If the named file already exists, it is overwritten. TLIB removes the file
remove name and then removes it from the library.
—+ or Replace TLIB replaces the named module with the corresponding file.
+—

Using TLIB Response Files


A response file is an ASCII text file that contains all or part of a TLIB command. Using TLIB response files, you can build TLIB
commands that are longer than one command line. If you need to perform a large number of operations or perform operations
several times, response files can make your job easier.

Response files can:

• 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 get a listing in CS.LST of an existing library CS.LIB, type:


tlib cs, cs.lst
Example 4

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

3.1.1.22 Using TOUCH.EXE


TOUCH.EXE updates a file's date stamp so that it reflects your system’s current time and date.

Command Line Syntax


touch [<options>] <filename> [<filename>...]

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

-s Recurses through subdirectories.


t<hh>:<mm>:<ss>- Sets the time of the file to the specified time.
-v Verbose mode. Shows each file that has been TOUCHed.

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.

Command Line Syntax


trigraph [-u] <filename> [...]

TRIGRAPH Options
TRIGRAPH has three command options:

• -nXXX writes output files to the directory named in XXX.


• -u means to Undo insert trigraphs.
• -xXXX creates output files with the extension XXX.
The following table shows the trigraph sequences the TRIGRAPH recognizes:
TRIGRAPH Character Sequences
The following table shows the trigraph sequences the TRIGRAPH recognizes:

Trigraph Character
??= #
??( [
??) ]
??/ \
??' ^
??< {
??> }
??- ~

3.1.1.24 RC.EXE, the Microsoft SDK Resource Compiler 3

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:

• BRCC32.exe, the CodeGear resource compiler

213
Command Line Utilities RAD Studio 3.1 C++ Reference

• RC.exe, the Microsoft platform SDK Resource Compiler


RC supports Unicode characters in resource files and file names, as well as new Vista resource types such as icons with alpha
channel.
The actual filename of the RC compiler in the RAD Studio environment is ERC.exe.
Differences Between BRCC32 and RC
If you choose to use RC, several differences between BRCC32 and RC need to be addressed in existing .RC files, as follows:

• 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)

Microsoft Resouce Compiler

Using RC Compiler to Build Resources

Compiling Resources with RC - From Digital Mars

Resource Compiler Options

3.1.1.25 WSDLIMP.EXE, the Command Line WSDL Import Tool


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
3 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 that use SOAP or document literal encoding.

Borland WSDLIMP Version 2.3 - $Rev: 16699 $


Copyright (c) 2008 Borland Software Corporation
Usage: WSDLIMP [options] <WSDL[File|URL]|UDDI BindingKey>

214
3.1 C++ Reference RAD Studio Command Line Utilities

Code Generation Options:


-C Generate C++ code -P Generate Pascal code
[ -option{+|-} default shown ]
-Oa- Process optional/nillable elements -Op+ Process inc/imported schemas
-Od+ Generate Complex Type Destructors -Oq- Quiet mode (Suppress Headers)
-Of- Process Faults -Og- Use OLE GUIDs for interface
-Oi- Ignore Schema errors -Os- Generate Server skeleton code
-Ok- Map pure collections to classes -Ot- Output unused types
-Ol- Generate Literal types -Ou+ Unwrap Literal Parameters
-Om- Allow out parameters -Ov+ Verbose Info. in file
-On- Declare Types in Namespace -Ow+ Map strings to WideStrings
-Oo+ One out param becomes return -Ox+ Strong class Aliases
Other options:
-D<path> Output directory path -=+ Output filename after'=' in URL
-U<url of UDDI Registry> UDDI Registry [NOTE: input must be UDDI bindingkey(s)

@<Resp> Response file with list of WSDL|UDDIBindingKey to import

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.

WSDLIMP Command Line Syntax


The command-line syntax for WSDLIMP is:
WSDLIMP [<options>] <Inputfile|URL>
<Inputfile> is a physical WSDL document to import.

<URL> is the URL for accessing a WSDL document that is published on the Web.

<options> stand for any of the WSDLIMP command-line options.

WSDLIMP Command Line Options


The following table lists the command-line options for WSDLIMP:

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)

3.1.2 C++ Compiler Errors And Warnings (C++)


This section describes the RAD Studio C++ compiler error and warning messages.

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:

• 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.... more ( see page 286)
F1010: Unable to open 'filename' (C++) ( see page 286) This error occurs if the specified file can't be opened.
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.
E2000: 286/287 instructions not enabled (C++) ( see page 286) Use the -2 command-line compiler option to enable 286/287 opcodes. Be aware
that the resulting code cannot be run on 8086- and 8088-based machines.
Abnormal program termination (C++) ( see page 286) The program called abort because there wasn't enough memory to execute.
This message can be caused by memory overwrites.
E2009: Attempt to grant or reduce access to 'identifier' (C++) ( see page 286) A C++ derived class can modify the access rights of a base class member, but
only by restoring it to the rights in the base class.
It can't add or reduce access rights.
E2011: Illegal to take address of bit field (C++) ( see page 286) It is not legal to take the address of a bit field, although you can take the address
of other kinds of fields.
E2010: Cannot add or subtract relocatable symbols (C++) ( see page 287) The only arithmetic operation that can be performed on a relocatable symbol in
an assembler operand is addition or subtraction of a constant.
Variables, procedures, functions, and labels are relocatable symbols.
E2013: 'function1' cannot be distinguished from 'function2' (C++) ( see page The parameter type lists in the declarations of these two functions do not differ
287) enough to tell them apart.
Try changing the order of parameters or the type of a parameter in one 3
declaration.

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:

• define ( see page 690)


• else ( see page 688)
• endif
• if
• ifdef ( see page 688)
• ifndef ( see page 688)
• include ( see page 692)
• line ( see page 693)
• pragma
• undef ( see page 692)
E2046: Bad file name format in include directive OR Bad file name format in line Include and line directive file names must be surrounded by quotes ("filename.h")
directive (C++) ( see page 294) or angle brackets (<filename.h>).
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.
E2051: Invalid use of dot (C++) ( see page 294) An identifier must immediately follow a period operator (.). This is a rare message
that can only occur in some specialized inline assembly statements.
Example
E2053: Misplaced elif directive (C++) ( see page 294) The compiler encountered an #elif directive without any matching #if,
#ifdef, or #ifndef directive.
E2054: Misplaced else (C++) ( see page 294) The compiler encountered an else statement without a matching if statement.
Possible Causes

• An extra "else" statement


• An extra semicolon 3
• Missing braces
• Some syntax error in a previous "if" statement
E2055: Misplaced else directive (C++) ( see page 294) The compiler encountered an #else directive without any matching #if,
#ifdef, or #ifndef directive.
E2056: Misplaced endif directive (C++) ( see page 295) The compiler encountered an #endif directive without any matching #if,
#ifdef, or #ifndef directive.
E2059: Unknown language, must be C or C++ (C++) ( see page 295) In the C++ construction

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

• shift (SHL, SHR)


• bitwise Boolean (AND, OR, XOR, NOT)
• conditional (? :)
• indirection (*)
• certain others
The compiler found a floating-point operand with one of
these prohibited operators.
E2061: Friends must be functions or classes (C++) ( see page 295) A friend of a C++ class must be a function or another class.
E2062: Invalid indirection (C++) ( see page 295) The indirection operator (*) requires a pointer as the operand.
Example
E2063: Illegal initialization (C++) ( see page 296) Initializations must be one of the following:

• 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:

• the field-selection dot (.)


• dot-star (.*)
• double colon (::)
• conditional expression (?:)
The preprocessor operators (# and ##) are not C or C++
language operators and thus can't be overloaded.
Other non-operator punctuation, such as semicolon (;), can't
be overloaded.
E2080: 'function' must be declared with one parameter (C++) ( see page 298) This C++ operator function was incorrectly declared with more than one
parameter.
E2077: 'operator' must be declared with one or no parameters (C++) ( see When operator ++ or operator -- is declared as a member function, it must be
page 298) declared to take either:

• No parameters (for the prefix version of the operator), or


• One parameter of type int (for the postfix version)
E2079: 'function' must be declared with no parameters (C++) ( see page 298) This C++ operator function was incorrectly declared with parameters.
E2078: 'operator' must be declared with one or two parameters (C++) ( see When operator ++ or operator -- is declared as a non-member function, it must
page 298) be declared to take either:

• one parameter (for the prefix version of the operator), or


• two parameters (for the postfix version)
E2081: 'function' must be declared with two parameters (C++) ( see page 298) This C++ operator function was incorrectly declared with other than two
parameters.
E2082: 'identifier' must be a member function or have a parameter of class type Most C++ operator functions must have an implicit or explicit parameter of class
(C++) ( see page 298) type.
This operator function was declared outside a class and does not have an explicit
parameter of class type.
E2083: Last parameter of 'operator' must have type 'int' (C++) ( see page 299) When a postfix operator ++ or operator -- is overloaded, the last parameter must
be declared with the type int.
E2084: Parameter names are used only with a function body (C++) ( see page When declaring a function (not defining it with a function body), you must use
299) either empty parentheses or a function prototype.
A list of parameter names only is not allowed.
Example declarations
E2085: Invalid pointer addition (C++) ( see page 299) Your source file attempted to add two pointers together.
E2086: Illegal pointer subtraction (C++) ( see page 299) This is caused by attempting to subtract a pointer from a non-pointer.
E2087: Illegal use of pointer (C++) ( see page 299) Pointers can only be used with these operators:

• 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:

• two consecutive operators


• mismatched or missing parentheses
• a missing semicolon on the previous statement.
Solutions
If the line where the error occurred looks syntactically
correct, look at the line directly above for errors.
Try moving the line with the error to a different location in the
file and recompiling.
If the error still occurs at the moved statement, the syntax
error is occurring somewhere in that statement.
If the error occurred... more ( see page 310)
E2190: Unexpected closing brace (C++) ( see page 311) An extra right brace was encountered where none was expected. Check for a
missing closing brace.
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.
E2189: extern variable cannot be initialized (C++) ( see page 311) The storage class extern applied to a variable means that the variable is being
declared but not defined here--no storage is being allocated for it.
Therefore, you can't initialize the variable as part of the declaration.
E2344: Earlier declaration of 'identifier' (C++) ( see page 311) This error message only shows up after the messages "Multiple declaration for
'identifier'" and "Type mismatch in redeclaration of 'identifier'". It tells you where
the previous definition of the identifier in question was found by the compiler, so
you don't have to search for it.
E2192: Too few parameters in call (C++) ( see page 311) This error message occurs when a call to a function with a prototype (via a
function pointer) had too few arguments. Prototypes require that all parameters
be given. Make certain that your call to a function has the same parameters as
the function prototype.
E2193: Too few parameters in call to 'function' (C++) ( see page 311) A call to the named function (declared using a prototype) has too few arguments.
Make certain that the parameters in the call to the function match the parameters 3
of the function prototype.
E2194: Could not find file 'filename' (C++) ( see page 311) The compiler is unable to find the file supplied on the command line.
E2197: File name too long (C++) ( see page 311) The file name given in an #include directive was too long for the compiler to
process.
File names in DOS must be no more than 79 characters long.

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:

• Divide by 0 means the result is +INF or -INF exactly, such


as 1.0/0.0.
• Domain means the result is NAN (not a number), like
0.0/0.0.
• Overflow means the result is +INF (infinity) or -INF with
complete loss of precision, such as assigning
1e200*1e200 to a double.
Floating point error: Stack fault (C++) ( see page 312) The floating-point stack has been overrun. This error may be due to assembly
code using too many registers or due to a misdeclaration of a floating-point
function.
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.
Floating point error: Partial loss of precision OR Floating point error: Underflow These exceptions are masked by default, because underflows are converted to
(C++) ( see page 312) zero and losses of precision are ignored.
E2201: Too much global data defined in file (C++) ( see page 313) The sum of the global data declarations exceeds 64K bytes. This includes any
data stored in the DGROUP (all global variables, literal strings, and static locals).
Solutions
Check the declarations for any array that might be too large. You can also
remove variables from the DGROUP.
Here's how:

• Declare the variables as automatic. This uses stack


space.
• Dynamically allocate memory from the heap using calloc,
malloc, or farmalloc for the variables. This requires the
use of pointers.
Literal strings are also put in the DGROUP. Get the file
farstr.zip from our BBS to extract literal strings into their
own segment.... more ( see page 313)
E2203: Goto bypasses initialization of a local variable (C++) ( see page 313) In C++, it is illegal to bypass the initialization of a local variable.
This error indicates a goto statement that can transfer control past this local
variable.
E2204: Group overflowed maximum size: 'name' (C++) ( see page 313) The total size of the segments in a group (for example, DGROUP) exceeded 64K.
E2206: Illegal character 'character' (0x'value') (C++) ( see page 313) The compiler encountered some invalid character in the input file.
The hexadecimal value of the offending character is printed.
This can also be caused by extra parameters passed to a function macro.
3 E2207: Implicit conversion of 'type1' to 'type2' not allowed (C++) ( see page When a member function of a class is called using a pointer to a derived class,
313) the pointer value must be implicitly converted to point to the appropriate base
class.
In this case, such an implicit conversion is illegal.
E2208: Cannot access an inactive scope (C++) ( see page 313) You have tried to evaluate or inspect a variable local to a function that is currently
not active. (This is an integrated debugger expression evaluation message.)

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

• The named file does not exist.


• An #include file included itself.
• You do not have FILES set in CONFIG.SYS on your root
directory.
Solutions
• Verify that the named file exists.
• Set FILES = 20 in CONFIG.SYS.
E2210: Reference member 'member' is not initialized (C++) ( see page 314) References must always be initialized, in the constructor for the class.
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.
E2212: Function defined inline after use as extern (C++) ( see page 314) Functions can't become inline after they have already been used.
Either move the inline definition forward in the file or delete it entirely.
The compiler encountered something like:
E2211: Inline assembly not allowed in inline and template functions (C++) ( see The compiler can't handle inline assembly statements in a C++ inline or template
page 314) function.
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.
F1001: Internal code generator error (C++) ( see page 315) An error has occurred in the internal logic of the code generator. Contact
CodeGear technical support.
E2413: Invalid template declaration (C++) ( see page 315) After the declarator of a template member, either a semicolon, an initialization, or
a body was expected, but some other, illegal token was found. This message
appears when a template member is declared outside of the template, but the
syntax was wrong.
E2070: Invalid use of namespace 'identifier' (C++) ( see page 315) A namespace identifier was used in an illegal way, for example, in an expression.
E2214: Cannot have a 'non-inline function/static data' in a local class (C++) ( All members of classes declared local to a function must be entirely defined in
see page 315) the class definition.
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.
E2215: Linkage specification not allowed (C++) ( see page 315) Linkage specifications such as extern "C" are only allowed at the file level.
Move this function declaration out to the file level.
E2216: Unable to create turboc.$ln (C++) ( see page 315) The compiler cannot create the temporary file TURBOC.$LN because it cannot
access the disk or the disk is full.
E2218: Templates can only be declared at namespace or class scope (C++) ( Templates cannot be declared inside classes or functions. They are only allowed
see page 315) in the global scope, or file level.
For example:
E2217: Local data exceeds segment size limit (C++) ( see page 316) The local variables in the current function take up more than 64K.
E2219: Wrong number of arguments in call of macro 'macro' (C++) ( see page Your source file called the named macro with an incorrect number of arguments.
316)
E2220: Invalid macro argument separator (C++) ( see page 316) In a macro definition, arguments must be separated by commas.
The compiler encountered some other character after an argument name.
This is correct:
E2221: Macro argument syntax error (C++) ( see page 316) An argument in a macro definition must be an identifier.
The compiler encountered some non-identifier character where an argument was
expected.
E2222: Macro expansion too long (C++) ( see page 316) A macro can't expand to more than 4,096 characters.
E2223: Too many decimal points (C++) ( see page 316) The compiler encountered a floating-point constant with more than one decimal 3
point.
E2224: Too many exponents (C++) ( see page 316) The compiler encountered more than one exponent in a floating-point constant.
E2225: Too many initializers (C++) ( see page 316) The compiler encountered more initializers than were allowed by the declaration
being initialized.
E2226: Extra parameter in call (C++) ( see page 317) A call to a function, via a pointer defined with a prototype, had too many
arguments.
E2227: Extra parameter in call to function (C++) ( see page 317) A call to the named function (which was defined with a prototype) had too many
arguments given in the call.
E2228: Too many error or warning messages (C++) ( see page 317) There were more errors or warnings than allowed.

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:

• in a list of parameters in an old-style function header


• after the reserved words struct or union when the braces
are not present, and
• 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.
E2275: Opening brace expected (C++) ( see page 322) A left brace was expected at the start of a block or initialization.
E2276: ( expected (C++) ( see page 322) A left parenthesis was expected before a parameter list.
E2274: < expected (C++) ( see page 322) The keyword template was not followed by <.
Every template declaration must include the template formal parameters
enclosed within < >, immediately following the template keyword.
E2277: Lvalue required (C++) ( see page 322) The left side of an assignment operator must be an addressable expression.
Addressable expressions include the following:

• numeric or pointer variables


3
• structure field references or indirection through a pointer
• a subscripted array element
E2278: Multiple base classes not supported for Delphi classes (C++) ( see Delphi style classes cannot have multiple base classes.
page 322)
E2280: Member identifier expected (C++) ( see page 322) The name of a structure or C++ class member was expected here, but not found.
The right side of a dot (.) or arrow (->) operator must be the name of a member in
the structure or class on the left of the operator.

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:

• 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.
E2291: brace expected (C++) ( see page 324) A right brace was expected at the end of a block or initialization.
E2292: Function should return a value (C++) ( see page 324) 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.
E2293: ) expected (C++) ( see page 325) A right parenthesis was expected at the end of a parameter list.
E2294: Structure required on left side of . or .* (C++) ( see page 325) The left side of a dot (.) operator (or C++ dot-star operator, .*) must evaluate to a
structure type. In this case it did not.
3 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'.
E2312: 'constructor' is not an unambiguous base class of 'class' (C++) ( see A C++ class constructor is trying to call a base class constructor 'constructor.'
page 325) This error can also occur if you try to change the access rights of
'class::constructor.'
Check your declarations.
E2313: Constant expression required (C++) ( see page 325) Arrays must be declared with constant size.
This error is commonly caused by misspelling a #define constant.
E2296: Templates not supported (C++) ( see page 325) An error has occurred while using the command-line utility H2ASH. See the
online file "tsm_util.txt" for further information about this utility.

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:

• 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.
E2304: 'Constant/Reference' variable 'variable' must be initialized (C++) ( see This C++ object is declared constant or as a reference, but is not initialized.
page 327) It must be initialized at the point of declaration.
E2305: Cannot find 'class::class' ('class'&) to copy a vector OR Cannot find When a C++ class 'class1' contains a vector (array) of class 'class2', and you
'class'::operator=('class'&) to copy a vector (C++) ( see page 327) want to construct an object of type 'class1' from another object of type 'class 1',
you must use this constructor:
3
E2306: Virtual base classes not supported for Delphi classes (C++) ( see page Delphi style classes cannot be derived virtually, not even from other Delphi style
328) classes.
E2308: do statement must have while (C++) ( see page 328) Your source file contained a do statement that was missing the closing while
keyword.
E2322: Incorrect number format (C++) ( see page 328) The compiler encountered a decimal point in a hexadecimal number.
E2324: Numeric constant too large (C++) ( see page 328) String and character escape sequences larger than hexadecimal or octal 77 can't
be generated.
Two-byte character constants can be specified by using a second backslash. For
example,

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

• 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.
E2327: Operators may not have default argument values (C++) ( see page 329) It is illegal for overloaded operators to have default argument values.
E2330: Operator must be declared as function (C++) ( see page 329) An overloaded operator was declared with something other than function type.
For example:
E2333: Class member 'member' declared outside its class (C++) ( see page C++ class member functions can be declared only inside the class declaration.
329) Unlike nonmember functions, they can't be declared multiple times or at other
locations.
E2335: Overloaded 'function name' ambiguous in this context (C++) ( see page The only time an overloaded function name can be used or assigned without
329) actually calling the function is when a variable or parameter of the correct
function pointer type is initialized or assigned the address of the overload
function.
In this case, an overloaded function name has been used in some other context,
for example, the following code will generate this error:
E2339: Cannot overload 'main' (C++) ( see page 330) You cannot overload main.
E2336: Pointer to overloaded function 'function' doesn't match 'type' (C++) ( A variable or parameter is assigned (or initialized with) the address of an
see page 330) overloaded function.
However, the type of the variable or parameter doesn't match any of the
overloaded functions with the specified name.
E2337: Only one of a set of overloaded functions can be "C" (C++) ( see page C++ functions are by default overloaded, and the compiler assigns a new name
330) to each function.
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.)
E2338: Overlays only supported in medium, large, and huge memory models The compiler no longer issues this error.
(C++) ( see page 330)
E2340: Type mismatch in parameter 'number' (C++) ( see page 330) The function called, via a function pointer, was declared with a prototype.
However, the given parameter number (counting left to right from 1) 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.
E2341: Type mismatch in parameter 'number' in call to 'function' (C++) ( see Your source file declared the named function with a prototype, and the given
page 331) parameter number (counting left to right from 1) 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.
E2342: Type mismatch in parameter 'parameter' (C++) ( see page 331) Your source file declared the function called via a function pointer with a
3 prototype.
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.

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

• Actual declaration of identifier has been commented out.


• Misspelling, either at this point or at the declaration.
• An error in the declaration of the identifier.
• The header file in which the identifier is declared was not
included using #include
Tools to help track down the problem:
GREP ( see page 170)
E2453: Size of the type 'identifier' is unknown or zero (C++) ( see page 340) This type was used in a context where its size was needed.
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.
Rearrange your declarations so that the size of this type is available.
E2452: Size of the type is unknown or zero (C++) ( see page 341) This error message indicates that an array of unspecified dimension nested
within another structure is initialized and the -A (ANSI) switch is on. For example:
E2454: union cannot be a base type (C++) ( see page 341) A union can't be used as a base type for another class type.
E2455: union cannot have a base type (C++) ( see page 341) In general, a C++ class can be of union type, but such a class can't be derived
from any other class.
E2456: Union member 'member' is of type class with 'constructor' (or destructor, A union can't contain members that are of type class with user-defined
or operator =) (C++) ( see page 341) constructors, destructors, or operator =.
E2461: '%s' requires run-time initialization/finalization (C++) ( see page 341) This message is issued when a global variable that is declared as __thread (a
Win32-only feature) or a static data member of a template class is initialized with
a non-constant initial value.
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.
E2464: 'virtual' can only be used with member functions (C++) ( see page 341) A data member has been declared with the virtual specifier.
3 Only member functions can be declared virtual.
For example:
E2465: unions cannot have virtual member functions (C++) ( see page 342) A union can't have virtual functions as its members.
E2466: void & is not a valid type (C++) ( see page 342) A reference always refers to an object, but an object cannot have the type void.
Thus, the type void is not allowed.
E2467: 'Void function' cannot return a value (C++) ( see page 342) A function with a return type void contains a return statement that returns a
value; for example, an int.
Default = displayed

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:

• the right side of an assignment


• an argument of a function
• the controlling expression of an if, for, or while statement.
E2469: Cannot use tiny or huge memory model with Windows (C++) ( see The compiler no longer issues this error.
page 342)
E2006: CodeGuarded programs must use the large memory model and be The compiler no longer issues this error.
targeted for Windows (C++) ( see page 342)
E2269: The function 'function' is not available (C++) ( see page 342) You tried to call a function that is known to the evaluator, but which was not
present in the program being debugged, for example, an inline function.
E2124: Invalid function call (C++) ( see page 343) A requested function call failed because the function is not available in the
program, a parameter cannot be evaluated, and so on. The evaluator issues this
message.
E2213: Invalid 'expression' in scope override (C++) ( see page 343) The evaluator issues this message when there is an error in a scope override in
an expression you are watching or inspecting. You can specify a symbol table, a
compilation unit, a source file name, etc. as the scope of the expression, and the
message will appear whenever the compiler cannot access the symbol table,
compilation unit, or whatever.
E2236: Missing 'identifier' in scope override (C++) ( see page 343) The syntax of a scope override is somehow incomplete. The evaluator issues this
message.
Pure virtual function called (C++) ( see page 343) This is a runtime error. It is generated if the body of a pure virtual function was
never generated and somehow the compiler tried to call it.
E2095: String literal not allowed in this context (C++) ( see page 343) This error message is issued by the evaluator when a string literal appears in a
context other than a function call.
Unexpected termination during compilation [Module Seg#:offset] OR Unexpected If either of these errors occur, it indicates a catastrophic failure of the CodeGear
termination during linking [Module Seg#:offset] (C++) ( see page 343) tools. You should contact CodeGear to report the problem and to find a potential
work around for your specific case. By isolating the test case as well as possible,
you will increase the chance for either CodeGear or yourself to find a work
around for the problem.
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... more ( see page 343)
E2012: Cannot take address of 'main' (C++) ( see page 344) In C++, it is illegal to take the address of the main function.
E2016: Ambiguous override of virtual base member 'base_function': A virtual function in a virtual base class was overridden with two or more different
'derived_function' (C++) ( see page 344) functions along different paths in the inheritance hierarchy. For example,
E2021: Array must have at least one element (C++) ( see page 344) ANSI C and C++ require that an array be defined to have at least one element
(objects of zero size are not allowed).
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
E2023: Array of references is not allowed (C++) ( see page 344) It is illegal to have an array of references, because pointers to references are not
allowed and array names are coerced into pointers.
E2032: Illegal use of closure pointer (C++) ( see page 344) A closure pointer variable is used incorrectly. Closure variables have limited
usage. For instance, you can assign a function to a closure variable, and execute
that function through the closure variable, but you cannot use a closure variable
like a pointer variable.
E2040: Declaration terminated incorrectly (C++) ( see page 345) A declaration has an extra or incorrect termination symbol, such as a semicolon
placed after a function body. 3
A C++ member function declared in a class with a semicolon between the header
and the opening left brace also generates this error.
E2047: Bad 'directive' directive syntax (C++) ( see page 345) A macro definition starts or ends with the ## operator, or contains the # operator
that is not followed by a macro argument name.
An example of this might be:
E2049: Class type 'type' cannot be marked as __declspec(delphireturn) (C++) ( Classes marked as delphireturn are special classes that the compiler needs to
see page 345) recognize by name. These classes are predefined in the headers.
Some of the delphireturn classes are Variant, AnsiString, and Currency.
You cannot mark user-defined classes as delphireturn.

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:

• CAUSE: Floating point set to None. You set the


floating-point option to None when it should... more ( see
page 361)

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:

• a decimal constant greater than 32,767 or


• an octal, hexadecimal, or decimal constant greater than
65,535 without a letter l or L following it
The constant is treated as a long.
W8008: Condition is always true OR W8008 Condition is always false (C++) ( (Command-line option to suppress warning: -w-ccc)
see page 363) 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.
For example:
W8012: Comparing signed and unsigned values (C++) ( see page 364) (Command-line option to suppress warning: -w-csu)
3 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.

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

• cast the constant to unsigned--for example, (unsigned)


65535, or
• append a letter u or U to the constant--for example,
65535u.
Whenever this message is issued, the compiler still
generates code to do the comparison.
If this code ends up always giving the same result (such as
comparing a char... more ( see page 365)
W8016: Array size for 'delete' ignored (C++) ( see page 365) (Command-line option to suppress warning: -w-dsz)
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.
This warning lets older code compile.
W8082: Division by zero (C++) ( see page 365) (Command-line option to suppress warning: -w-zdi)
A divide or remainder expression had a literal zero as a divisor.
W8018: Assigning 'type' to 'enumeration' (C++) ( see page 365) (Command-line option to suppress warning: -w-eas)
Assigning an integer value to an enum type.
This is an error in C++, but is reduced to a warning to give existing programs a
chance to work.
W8006: Initializing 'identifier' with 'identifier' (C++) ( see page 366) (Command-line option to suppress warning: -w-bei)
You're trying to initialize an enum variable to a different type.
For example, the following initialization will result in this warning, because 2 is of
type int, not type enum count: 3
W8001: Superfluous & with function (C++) ( see page 366) (Command-line option to display warning: -wamp)
An address-of operator (&) is not needed with function name; any such operators
are discarded.
W8020: 'identifier' is declared as both external and static (C++) ( see page 366) (Command-line option to suppress warning: -w-ext)
This identifier appeared in a declaration that implicitly or explicitly marked it as
global or external, and also in a static declaration.
The identifier is taken as static.
You should review all declarations for this identifier.

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:

• a re-declaration of an enum has a different underlying


type
• a scoped enum is re-declared as an unscoped enum 3
• an unscoped enum is re-declared as a scoped enum
For more information, see Strongly Typed Enums ( see
page 498).
E2533: Parameter mismatch (wanted typename) (C++) ( see page 382) This error occurs when a parameter passed to a type trait function is not the
correct type.

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.

This compiler error message is deprecated.

256
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.2 E2525: You must define _PCH_STATIC_CONST before


including xstring to use this feature (C++)
You attempted to use a feature defined in xstring, part of the Dinkumware 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.

3.1.2.3 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 as either the getter or setter of another property.

3.1.2.4 E2008: Published property access functions must use


__fastcall calling convention (C++)
The calling convention for access functions of a property (read, write, and stored) declared in a __published section must be
__fastcall. This also applies to hoisted properties.

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};

3.1.2.5 E2122: Function call terminated by unhandled exception


'value' at address 'addr' (C++)
This message is emitted when an expression you are evaluating while debugging includes a function call that terminates with an
unhandled exception. For 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.

3.1.2.6 E2506: Explicit specialization of 'specifier' is ambiguous:


must specify template arguments (C++)
In the following code, explicit template arguments are necessary:
3
template<class T> void foo(T);
template<class T> void foo(T *);
template<> void foo(int *); // error, must say 'foo<int>' or 'foo<int *>'

257
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.7 E2483: Array dimension 'specifier' could not be determined


(C++)
If, during instantiation of a type, an array dimension cannot be 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.

3.1.2.8 E2509: Value out of range (C++)


The inline assembler has detected a numeric overflow in one of your expressions. Make sure all of your numbers can fit in 32
bits.

3.1.2.9 E2510: Operand size mismatch (C++)


Help is not available for this item.

3.1.2.10 E2050: __declspec(delphireturn) class 'class' must have


exactly one data member (C++)
This is an internal compiler error. A class marked as a delphireturn class has more than one non-static data member.

3.1.2.11 E2530: Unrecognized option, or no help available (C++)


You have entered a command element that the C++ compiler cannot parse, or the option you entered has no associated help.
Try again.

3.1.2.12 E2527: Option 'name' cannot be set via 'name' (C++)


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.

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++)

3.1.2.14 E2074: Value after -g or -j should be between 0 and 255


inclusive (C++)
Both the -g and the -j command line options can be followed by an optional number. The compiler expects this number to be
between 0 and 255 inclusive.

3.1.2.15 E2492: Properties may only be assigned using a simple


statement, e.g. \"prop = value;\" (C++)
Assignments to properties should be made in simple assignment statements. If 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:
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
}

3.1.2.16 E2505: Explicit instantiation requires an elaborated type


specifier (i.e.,"class foo<int>") (C++)
The following code is illegal:
template<class T> class foo;
template foo<int>; // missing `class' keyword
See Also
Implicit And Explicit Template Functions ( see page 434)

3.1.2.17 E2100: Invalid template declarator list (C++)


It is illegal for a declarator list to follow a template class declaration. For example: 3
template<class T>
class foo {
} object_name; // This causes an error

259
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.18 E2102: Cannot use template 'template' without specifying


specialization parameters (C++)
The generic form of a template must be referenced using specialization parameters. For example, for a template class named
foo, taking two template parameters, then a legal reference might have the form
foo<int, char>
Referring to the template as just foo is legal in only two circumstances:

• When passing the template name as a template template argument


• While declaring the members of that class template, to refer to the enclosing template type
For example:
template<class T>
class foo
{
public:
foo(); // legal use of bare template name
foo& operator=(const foo&);
};
foo<foo> x; // error: not a template template argument
foo y; // error: needs specialization parameters

3.1.2.19 E2107: Invalid use of template 'template' (C++)


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:
template<template<class T> class U>
class foo;
template<template<class T> class U>
class bar
{
U x;// error: not a specialization
U<U> y;// ok: used as a specialization, and as a
// template template argument
U<bar> z;// ok: used to reference a specialization
};

3.1.2.20 E2105: 'template' qualifier must specify a member template


name (C++)
When parsing code that depends in some way upon a template parameter, it is 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,
3 or as a regular less-than operator:
template<class T>
void foo(T a)
{
a.member<10>();
}
Although it may be apparent to the reader what is meant, the compiler does not know that "member" refers to a member
template function, and it will parse the line of code as follows:

260
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

a.member < (10>());


In order to tell the compiler that the less-than character begins a template argument list, the 'template' qualifier is needed:
a.template member<10>(); // "member" must be a member template
If the 'template' qualifier is used in a situation where "member" does not resolve to a member template, the above error will result.

3.1.2.21 E2066: Information not available (C++)


Help is not available for this item.

3.1.2.22 E2471: pragma checkoption failed: options are not as


expected (C++)
You can use #pragma checkoption to check that certain switches are in the state 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:


#pragma checkoption <options>
For example:
#pragma checkoption -O2
OR
#pragma checkoption -C -O2
The compiler will check if the option(s) are turned on. If all are turned on, nothing happens. If at least one is not turned on, this
error is displayed.

3.1.2.23 E2504: 'dynamic' can only be used with non-template


member functions (C++)
You tried to use dynamic with a template member function. Dynamic functions 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.

3.1.2.24 E2191: '__far16' may only be used with '__pascal' or


'__cdecl' (C++)
3
This is an internal compiler error. The compiler emits this message if the keyword __far16 is mixed with one of the keywords
__pascal or __cdecl, all in the same declaration.

261
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.25 E2199: Template friend function 'function' must be


previously declared (C++)
Not used

3.1.2.26 E2502: Error resolving #import: problem (C++)


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 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.1.2.27 E2501: Unable to open import file 'filename' (C++)


This error occurs when you use:
#import "somefile.h"

3 and the file you are trying to import doesn't exist or can't be found by the compiler.

3.1.2.28 E2494: Unrecognized __declspec modifier (C++)


A _declspec modifier was given that is not valid.

262
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.29 E2493: Invalid GUID string (C++)


The GUID string does not have the form of a Globally Unique Identifier.

3.1.2.30 E2499: Invalid __declspec(uuid(GuidString)) format (C++)


This error happens when you used the wrong format to define your GuidString. GUIDs are defined for structs in the following
way:
class __declspec(uuid("19a76fe0-7494-11d0-8816-00a0c903b83c")) foo{};
You would get the above mentioned error for instance from:
class __declspec(uuid(19a76fe0-7494-11d0-8816-00a0c903b83c)) foo{}; //Missing quotes
or
class __declspec(uuid"7494-11d0-8816-00a0c903b83c")) foo{}; // Missing left parentheses

3.1.2.31 E2496: Invalid call to uuidof(struct type|variable) (C++)


The uuidof operator was given an incorrect argument.

3.1.2.32 E2511: Unterminated macro argument (C++)


A macro argument that was started on the line listed has not been properly terminated

3.1.2.33 E2489: Maximum option context replay depth exceeded;


check for recursion (C++)
If this error is triggered, it means that recursive template instantiation has gone too deep. Check for compile-time recursion in
your program, and limit it to no more than 256 levels.

3.1.2.34 E2488: Maximum token reply depth exceeded; check for


recursion (C++)
If this error is triggered, it means that recursive template instantiation has gone too deep. Check for compile-time recursion in
your program, and limit it to no more than 256 levels.
3
3.1.2.35 E2491: Maximum VIRDEF count exceeded; check for
recursion (C++)
Too many VIRDEF symbols were allocated. The compiler imposes a limit to the 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.

263
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.36 E2230: In-line data member initialization requires an integral


constant expression (C++)
Static const class members, which are initialized in the body of the class, have to be initialized with a constant expression of
integral type.

3.1.2.37 E2241: VCL style classes need virtual destructors (C++)


Destructors defined in VCL style classes have to be virtual.

Example
struct__declspec(delphiclass) vclclass1
{
~vclclass1() {} // Error
};
struct__declspec(delphiclass) vclclass2
{
virtual ~vclclass2() {} // OK
};

3.1.2.38 E2524: Anonymous structs/unions not allowed to have


anonymous members in C++ (C++)
The C++ compiler requires that the members of an anonymous struct or union be named.

3.1.2.39 E2246: x is not abstract public single inheritance class


hierarchy with no data (C++)
Internal compiler error. In some cases, the compiler will enforce restrictions on a class hierarchy. In this case, the restrictions
would be that all classes are abstract classes, and all classes only have one parent.

3.1.2.40 E2249: = expected (C++)


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.

3 3.1.2.41 E2267: First base must be VCL class (C++)


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.

264
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.42 E2472: Cannot declare a member function via instantiation


(C++)
If a declaration within a template class acquires a function type through a type 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:
template<class T>
struct A {
static T t;
};
typedef int function();
A<function> a;// error: would declare A<function>::t
// as a static member function
Another example:

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>;

3.1.2.43 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 example, the following code is illegal:
template<typename T>
class foo {
template<typename U>
class bar {
};
};
template<typename T>
template<>
class foo<T>::bar<char> {
};
The second declaration in the example is an error, because it tries to explicitly specialize bar<char> within foo<T>.

3.1.2.44 E2474: 'function' cannot be declared as static or inline (C++)


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. 3
For example, this error is displayed in the following cases:
static int main() // This causes an error
{}
or
inline int main() { return 0; }

265
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.45 E2498: Need previously defined struct GUID (C++)


This happens when you use the __uuidof operator without including a header that defines the GUID struct. So the following
program code would display this error:
class __declspec(uuid("19a76fe0-7494-11d0-8816-00a0c903b83c")) foo{};
int main()
{
__uuidof(foo);
return 0;
}
And you would fix it as follows:
#include <windows.h> // Will pull in struct GUID
class __declspec(uuid("19a76fe0-7494-11d0-8816-00a0c903b83c")) foo{};
int main()
{
__uuidof(foo);
return 0;
}

3.1.2.46 E2295: Too many candidate template specializations from


'specifier' (C++)
When reference a class template specialization, it is possible that more than one 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:
template<class T, class U>
class foo;
template<class T>
class foo<T, T *>;
template<class T>
class foo<T *, T>;
foo<int *, int *> x; // error: which partial specialization to use?
In this example, both partial specializations are equally valid, and neither is more specialized than the other, so an error would
result.

3.1.2.47 E2475: 'function' cannot be a template function (C++)


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:

3 template <class T> int main() // This causes an error


{}
See Also
Function Templates ( see page 433)

266
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.48 E2299: Cannot generate template specialization from


'specifier' (C++)
This error will result if an attempt is made to reference a template class or function in a manner which yields no possible
candidate specializations. For example:
template<class T>
class foo;
foo<10> x; // error: arguments aren't valid for 'foo'

3.1.2.49 E2300: Could not generate a specialization matching type


for 'specifier' (C++)
This error is no longer generated by the compiler.

3.1.2.50 E2497: No GUID associated with type:'type' (C++)


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)).

3.1.2.51 E2522: Non-const function 'function' called for const object


(C++)
Data type mismatch resulting in an erroneous function call. The object of the call (a non-const function) should be a const object.

3.1.2.52 E2523: Non-volatile function 'name' called for volatile object


(C++)
Data type mismatch. The error is the result of an erroneous function call. The object of the call (a non-volatile function) should be
a volatile object.

3.1.2.53 E2513: Cannot emit RTTI for 'parameter' in 'function' (C++)


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.
3

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

3.1.2.55 E2507: 'class' is not a direct base class of 'class' (C++)


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.

3.1.2.56 E2529: Path 'path' exceeds maximum size of 'n' (C++)


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.

3.1.2.57 E2495: Redefinition of uuid is not identical (C++)


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:
class __declspec(uuid("19a76fe0-7494-11d0-8816-00a0c903b83c")) foo;
class __declspec(uuid("00000000-7494-11d0-8816-00a0c903b83c")) foo{}

3.1.2.58 E2500: __declspec(selectany) is only for initialized and


externally visible variables (C++)
You cannot use __declspec(selectany) with static variables, unitialized variables, etc.

3.1.2.59 E2482: String constant expected (C++)


The compiler expected a string constant at this location but did not receive one.

This error is no longer generated by the compiler.

3.1.2.60 E2481: Unexpected string constant (C++)


There are times when the compiler does not expect a string constant to appear in the source input. For example:
class foo { "Hello"; };

3.1.2.61 E2386: Cannot involve parameter 'parameter' in a complex


3
partial specialization expression (C++)
When declaring or defining a template class partial specialization, it is illegal to involve any of the non-type template parameters
in complex expressions. They may only be referenced by name. For example:
template<class T, int U>
class foo;
template<int U>
class foo<char, U * 3>;// error: "U * 3" is a complex expression
template<int U>
class foo<char, U>;// OK: "U" is a simple, by-name expression

268
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.62 E2387: Partial specializations may not specialize dependent


non-type parameters ('parameter') (C++)
A partial specialization may not use a template parameter in its specialization argument list which is dependent on another type
parameter. For example:
template<class T, int U>
class foo;
template<class T, T U>
class foo<T *, U>; // error: 'U' is type-dependent

3.1.2.63 E2388: Argument list of specialization cannot be identical to


the parameter list of primary template (C++)
When declaring a partial specialization, its specialization argument list must differ in some way from its basic parameter list. For
example:

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

3.1.2.64 E2389: Mismatch in kind of substitution argument and


template parameter 'parameter' (C++)
When referencing a template specialization, all type parameters must be satisfied 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:
template<class T, int U, template<class V> class W>
class foo;
foo<char, 10, foo> x; // OK: all parameter kinds match
foo<10, char, int> y; // error: no parameter kinds match at all!

3.1.2.65 E2480: Cannot involve template parameters in complex


partial specialization arguments (C++)
A partial specialization cannot reference other template parameters in a nonvalue argument expression, unless it is simply a
direct reference to the template parameter. For example:
template<int A, int B, int C> class foo; 3
template<int A> class foo<A+5, A, A+10>;
The partial specialization has two illegal arguments. 'A+5' is a complex expression because it uses 'A' in a manner other than as
merely a direct argument. The reference to plain 'A' in the second argument is fine, but the third argument is also illegal because
it references 'A' in a complex manner as well.

269
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.66 E2392: Template instance 'template' is already instantiated


(C++)
There are two ways to trigger this error. If –A is enabled (ANSI compliant mode), 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:
template<class T>
class foo;
foo<char> x; // causes implicit instantiation of "foo<char>"
template<>
class foo<char> { }; // error: "foo<char>" already instantiated
template class foo<char>; // error in –A mode, otherwise a warning

3.1.2.67 E2393: Cannot take the address of non-type, non-reference


template parameter 'parameter' (C++)
A template parameter has no address, and is not associated with any real "object". Therefore, to take its address, or attempt to
assign to it, has no meaning. For example:
template<int U>
void foo()
{
int *x = &U;// error: cannot take address of parameter
}

3.1.2.68 E2399: Cannot reference template argument 'arg' in


template class 'class' this way (C++)
The compiler no longer generates this error.

3.1.2.69 E2397: Template argument cannot have static or local


linkage (C++)
Only integral constant expressions, and the address of global variables with external linkage, may be used as template
arguments. For example:
template<char *x>
class foo;
const char *p = "Hello";
extern char *q;
3 foo<p> x;// OK: "p" is visible to the outside
foo<q> y;// OK: "q" is also globally visible
foo<"Hello"> z;// error: string literal has static linkage

270
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.70 E2485: Cannot use address of array element as non-type


template argument (C++)
Non-type template arguments may only be of integral type, or the address of a global variable. They cannot be the address of an
array element. For example:
int x[100];
template<int T>
class foo;
foo<&x[0]> y;// error: not an integral or global address

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

3.1.2.72 E2403: Dependent call specifier yields non-function 'name'


(C++)
The compiler no longer generates this error.

3.1.2.73 E2404: Dependent type qualifier 'qualifier' has no member


type named 'name' (C++)
If a template declaration references a member of a dependent type, it is only possible to alert the user to the non-existence of
this member during type instantiation for a given set of template arguments. For example:
template<class T>
class foo
{
typename T::A x; // we expect that "A" is a member type
};
struct bar { };
foo<bar> y;// error: "bar" has no member type named "A"

3.1.2.74 E2405: Dependent template reference 'identifier' yields 3


non-template symbol (C++)
If a template specialization reference within a template declaration yields a reference to a non-template during type instantiation,
the above error will result. For example:
template<class T>
class foo
{

271
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

typename T::template A<int> x; // "A" must be a member template


};
struct bar {
struct A { };
};
foo<bar> y;// error: bar::A is a non-template class!

3.1.2.75 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 non-struct member qualification at instantiation time, the
above error will result. For example:
template<class T>
class foo
{
typename T::A x; // we expect that "A" is a member type
};
foo<int> y;// error: "int" cannot be qualified; not a class

3.1.2.76 E2407: Dependent type qualifier 'qualifier' has no member


symbol named 'name' (C++)
If a template declaration references a member of a dependent type, it is only possible to alert the user to the non-existence of
this member during type instantiation for a given set of template arguments. For example:
template<class T>
class foo
{
foo(int *a = T::A); // we expect that "A" is a data member
};
struct bar { };
foo<bar> y;// error: "bar" has no member named "A"

3.1.2.77 E2408: Default values may be specified only in primary


class template declarations (C++)
Template functions, and class partial specializations, may not use default expressions in their template parameter lists. Only
primary template declarations may do this. For example:
template<class T = int>
class foo;// OK: primary class template
template<class T = int>
void bar();// error: template function
template<class T = int>
class foo<T *>;// error: partial specialization
3
3.1.2.78 E2409: Cannot find a valid specialization for 'specifier' (C++)
This error is no longer generated by the compiler.

272
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.79 E2410: Missing template parameters for friend template


'template' (C++)
If a friend template is declared, but no template parameters are specified, this error will result. For example:
template<class T>
class foo;
class bar {
friend class foo;// error: forgot template parameters!
};

3.1.2.80 E2486: Cannot use address of class member as non-type


template argument (C++)
Non-type template arguments may only be of integral type, or the address of a global variable. They cannot be the address of a
class member. For example:
struct bar {
int x;
} y;
template<int T>
class foo;
foo<&y.x> z;// error: not an integral or global address

3.1.2.81 E2411: Declaration of member function default parameters


after a specialization has already been expanded (C++)
If a member function of a class template is declared, and then a specialization of that class implicitly instantiated, and later that
member function defined with default parameters specified, the above error will result. For example:
template<int i>
class foo {
void method(int a, int b = i);
};
foo<10> x;
template<int i>
void foo<i>::method(int a = i, int b); // error!

3.1.2.82 E2412: Attempting to bind a member reference to a


dependent type (C++)
The compiler no longer generates this error.

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

};

3.1.2.84 E2473: Invalid explicit specialization of 'specifier' (C++)


Attempting to explicitly specialize a static data member or any non-template will cause this error.

3.1.2.85 E2490: Specialization within template classes not yet


implemented (C++)
Explicit and partial specialization of member template classes and functions within template classes and nested template
classes, is not supported.

3.1.2.86 E2416: Invalid template function declaration (C++)


The compiler no longer generates this error.

3.1.2.87 E2417: Cannot specify template parameters in explicit


specialization of 'specifier' (C++)
The compiler no longer generates this error.

3.1.2.88 E2418: Maximum instantiation depth exceeded; check for


recursion (C++)
The compiler only supports 256 levels of instantiation before it will trigger this 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:
template<int T>
class foo {
public:
static const int x = foo<T – 1>::x;
};
template<int T>
class foo<1> {
public:
static const int x = 1;
};
int main() {
int y = foo<100000>::x;// error: instantiation depth exceeded
3 }

3.1.2.89 E2420: Explicit instantiation can only be used at global


scope (C++)
Explicit instantiation cannot be specified at any level other than namespace or global scope. For example:
template<class T>

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
}

3.1.2.90 E2422: Argument kind mismatch in redeclaration of


template parameter 'parameter' (C++)
If a template is declared at one point in the translation unit, and then redeclared with template parameters of a different kind at
another location, this error will result. For example:
template<class T>
class foo;
// ? time passes ?
template<int T>
class foo;// error: type vs. non-type parameter

3.1.2.91 E2423: Explicit specialization or instantiation of


non-existing template 'template' (C++)
Attempting to explicit specialize or instantiate a template which does not exist is clearly illegal. For example:
template<class T>
class foo;
template class bar<char>;// error: what is "bar"??
template<>
class bar<int> { };// error: there's that "bar" again?

3.1.2.92 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 example:
void foo();// error: there is a template class named "foo"
template<class T>
class foo;

3.1.2.93 E2484: The name of template class 'class' cannot be


overloaded (C++)
Attempting to declare a function that overrides the name of a template class will cause this error. For example:
template<class T>
class foo;
void foo();// error: there is a template class named "foo" 3

3.1.2.94 E2426: Explicit specialization of 'specifier' requires


'template<>' declaration (C++)
According to the standard, explicit specialization of any template now always require the "template<>" declarator syntax. For
example:

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

3.1.2.95 E2487: Cannot specify default function arguments for


explicit specializations (C++)
An explicit specialization of a function may not declare default function arguments. For example:
template<class T>
void foo(T a);
template<>
void foo<int>(int a = 10);// error: default value not allowed

3.1.2.96 E2427: 'main' cannot be a template function (C++)


'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.

This error message should not occur because it has been replaced with another one (E2475).

3.1.2.97 E2429: Not a valid partial specialization of 'specifier' (C++)


Internal compiler error.

3.1.2.98 E2430: Number of template parameters does not match in


redeclaration of 'specifier' (C++)
If a template is redeclared with a different number of template parameters, this error will result. For example:
template<class T>
class foo;
template<class T, int U>
class foo;// error: parameter count mismatch!

3.1.2.99 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 outer declaration uses a different number of
template parameters than the parent class, this error will result. For example:
3
template<class T, class U>
class foo {
void method();
};
template<class T>
void foo<T>::method() { }// error: too few template parameters!

276
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.100 E2478: Too many template parameters were declared for


template 'template' (C++)
If a member declaration or definition occurs outside of a template class, and that outer declaration uses a different number of
template parameters than the parent class, this error will result. For example:
template<class T, class U>
class foo {
void method();
};
template<class T, class U, class V>
void foo<T, U, V>::method() { }// error: too many parameters!

3.1.2.101 E2431: Non-type template parameters cannot be of floating


point, class, or void type (C++)
Non-type template parameters are restricted as to what type they may be. Floating point, class and void types are illegal. For
example:
template<float U>
class foo;// error: "U" cannot be of "float" type

3.1.2.102 E2434: Template declaration missing template parameters


('template<...>') (C++)
In a context where at least one template parameter is clearly required, if none are found this error will result. For example:
template<class T, template<> class U>
class foo;// error: template template parameters require
// at least one actual parameter to be declared

3.1.2.103 E2435: Too many template parameter sets were specified


(C++)
If a member template is being defined outside of its parent class, and too many template parameter sets are declared, this error
will result. For example:
template<class T>
class foo
{
template<class U>
void method(U a);
};
template<class T> template<class U> template<class V> 3
void foo<T>::method(U a);// error: too many parameter sets!

3.1.2.104 E2436: Default type for template template argument 'arg'


does not name a primary template class (C++)
If a template template parameter is to have a default type, that type must either be a generic template class name, or another
template template parameter.

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

3.1.2.105 E2437: 'typename' should be followed by a qualified,


dependent type name (C++)
Whenever the "typename" keyword is used in a template declaration or definition, it should always name a dependent type. For
example:
struct bar { };
template<class T>
class foo {
typename T::A *x;// OK: names a qualified type
typename T y;// error: not a qualified type
typename bar z;// error: not a dependent type
};

3.1.2.106 E2438: Template template arguments must name a class


(C++)
A template template parameter must always declare a new class name. For example:
template<template<class T> int U>
class foo;// error: "U" is not a class tag name
template<template<class T> class V>
class bar;// OK: "V" is a class tag name

3.1.2.107 E2439: 'typename' is only allowed in template declarations


(C++)
The "typename" keyword must only be used within template declarations and definitions.

3.1.2.108 E2440: Cannot generate specialization from 'specifier'


because that type is not yet defined (C++)
The compiler no longer generates this error.

3 3.1.2.109 E2441: Instantiating 'specifier' (C++)


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.

278
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.110 E2503: Missing or incorrect version of TypeLibImport.dll


(C++)
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.

3.1.2.111 E2470: Need to include header <typeinfo> to use typeid


(C++)
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:


int func()
{
char * name = typeid(int).name(); // This causes an error
}

3.1.2.112 E2514: Cannot (yet) use member overload resolution


during template instantiation (C++)
You are trying to overload a member during template instantiation. You cannot have calls to overloaded constant functions within
array bounds initializers, for example.

3.1.2.113 E2508: 'using' cannot refer to a template specialization


(C++)
The using keyword cannot refer to a template specialization.

3.1.2.114 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 member template functions.

Consider a test case with the following code:


template <class T>
class myTemplateClass
{ 3
virtual int func1(); // This is fine
template <class T> virtual int func2(); // This causes an error
};
class myClass
{
virtual int func1(); // This is fine
template <class T> virtual int func2(); // This causes an error
};

279
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.115 W8086: Incorrect use of #pragma alias


"aliasName"="substituteName" (C++)
The directive #pragma alias is used to tell the linker that two identifier names are 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:
#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)

3.1.2.116 W8099: Static main is not treated as an entry point (C++)


The main function has been created as static, and as such cannot be used as a valid entry point.

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.

3.1.2.117 W8093: Incorrect use of #pragma codeseg [seg_name]


["seg_class"] [group] (C++)
The #pragma codeseg directive can be used to set or reset the name, class, and 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:


#pragma codeseg
#pragma codeseg foo
#pragma codeseg foo "bar"
#pragma codeseg foo "bar" foobar
But these are not:
#pragma codeseg ###
#pragma codeseg "foo" "bar"
3 #pragma codeseg foo "bar" foobar morefoobar

3.1.2.118 W8094: Incorrect use of #pragma comment( <type>


[,"string"] ) (C++)
The directive #pragma comment can be used to emit linker comment records.

In this message, <type> can be any of the following:

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.

3.1.2.119 W8085: Function 'function' redefined as non-inline (C++)


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.1.2.120 W8105: %s member '%s' in class without constructors


(C++)
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.

3.1.2.121 W8095: Incorrect use of #pragma message( "string" ) (C++)


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
#pragma message( "hi there" )
is correct, but the following code would generate the warning:
#pragma message( badly formed )

3.1.2.122 W8098: Multi-character character constant (C++)


This warning is issued when the compiler detects a multi-character integer constant, such as:
int foo = 'abcd';
The problem with this construct is that the byte order of the characters is implementation dependent.

3.1.2.123 W8096: Incorrect use of #pragma


code_seg(["seg_name"[,"seg_class"]]) (C++)
3
Pragma code_seg is similar to pragma codeseg, but with this one you can only 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:


#pragma code_seg()
#pragma code_seg("foo")
#pragma code_seg("foo", "bar")
However, the following incorrect examples will all produce the warning:

281
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

#pragma code_seg(foo)
#pragma code_seg(foo, bar)

3.1.2.124 W8083: Pragma pack pop with no matching pack push


(C++)
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:
#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.

3.1.2.126 W8084: Suggest parentheses to clarify precedence (C++)


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:
int j, k, l;
int main()
{
return j < k & l; // This causes an error
}
3 //

3.1.2.127 W8092: 'type' argument 'specifier' passed to 'function' is


not an iterator: 'type' iterator required (C++)
An argument that is not an iterator is being used with an STL algorithm that requires an iterator.

282
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.128 W8087: 'operator::operator==' must be publicly visible to


be contained by a 'type' (C++)
A type that is being used with an STL container has a private 'operator=='.

3.1.2.129 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 type you're trying to use must be made public.

3.1.2.130 W8089: 'type::operator<' must be publicly visible to be


contained by a 'type' (C++)
The type that is being used for an STL container has a private 'operator<'. The 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:
'blah::operator<' must be publicly visible to be contained by a 'vector'

3.1.2.131 W8091: 'type' argument 'specifier' passed to 'function' is a


'iterator category' iterator: 'iterator category' iterator required (C++)
An incorrect iterator category is being used with an STL algorithm.

3.1.2.132 W8076: Template instance 'specifier' is already instantiated


(C++)
You are trying to explicitly instantiate a template that was already implicitly 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.

3.1.2.133 W8077: Explicitly specializing an explicitly specialized


class member makes no sense (C++) 3
Internal error. This warning is no longer generated by the compiler.

The following code is illegal:


template<class T> class foo { int x; }
template<> class foo<int> { int y; }
template<> int foo<int>::y; // error: cannot explicitly specialize of 'foo<int>::x'

283
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.134 Informational messages (C++)


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:
[C++] Compiling: D:\Program Files\Borland\CBuilder\Bin\Unit1.cpp
You may also see a message such as
[C++] Including clx.h instead of clx.h due to -Hr switch
This message indicates that the IDE-managed precompiled header file was replaced due to additional CLX classes being
included in the project. It does not indicate a failure condition. Sometimes the header file name being included may be the same
if it is being included with a different #define statement.

3.1.2.135 E2196: Cannot take address of member function 'function'


(C++)
An expression takes the address of a class member function, but this member function was not found in the program being
debugged. The evaluator issues this message.

3.1.2.136 F1002: Unable to create output file 'filename' (C++)


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.

3.1.2.137 F1003: Error directive: 'message' (C++)


This message is issued when an #error directive is processed in the source file.

'message' is the text of the #error directive.

3.1.2.138 F1004: Internal compiler error (C++)


3
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.

3.1.2.139 F1006: Bad call of intrinsic function (C++)


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.

284
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.140 F1007: Irreducible expression tree (C++)


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.

3.1.2.141 F1009: Unable to open input file 'filename' (C++)


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.

3.1.2.142 F1011: Register allocation failure (C++)


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.

3.1.2.143 F1012: Compiler stack overflow (C++)


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.

3.1.2.144 F1013: Error writing output file (C++)


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.

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

3.1.2.146 F1005: Include files nested too deep (C++)


This message flags (directly or indirectly) recursive #include directives.

3.1.2.147 F1008: Out of memory (C++)


The total working storage is exhausted.

This error can occur in the following circumstances:

• 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.

3.1.2.148 F1010: Unable to open 'filename' (C++)


This error occurs if the specified file can't be opened.

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.

3.1.2.149 E2000: 286/287 instructions not enabled (C++)


Use the -2 command-line compiler option to enable 286/287 opcodes. Be aware that the resulting code cannot be run on 8086-
and 8088-based machines.

3.1.2.150 Abnormal program termination (C++)


The program called abort because there wasn't enough memory to execute.

This message can be caused by memory overwrites.

3.1.2.151 E2009: Attempt to grant or reduce access to 'identifier'


(C++)
A C++ derived class can modify the access rights of a base class member, but only by restoring it to the rights in the base class.
3
It can't add or reduce access rights.

3.1.2.152 E2011: Illegal to take address of bit field (C++)


It is not legal to take the address of a bit field, although you can take the address of other kinds of fields.

286
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.153 E2010: Cannot add or subtract relocatable symbols (C++)


The only arithmetic operation that can be performed on a relocatable symbol in an assembler operand is addition or subtraction
of a constant.

Variables, procedures, functions, and labels are relocatable symbols.

3.1.2.154 E2013: 'function1' cannot be distinguished from 'function2'


(C++)
The parameter type lists in the declarations of these two functions do not differ enough to tell them apart.

Try changing the order of parameters or the type of a parameter in one declaration.

3.1.2.155 E2014: Member is ambiguous: 'member1' and 'member2'


(C++)
You must qualify the member reference with the appropriate base class name.

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.

3.1.2.156 E2015: Ambiguity between 'function1' and 'function2' (C++)


Both of the named overloaded functions could be used with the supplied parameters.

This ambiguity is not allowed.

3.1.2.157 E2017: Ambiguous member name 'name' (C++)


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. 3
For example:
struct A
{
int a;
int b;
};
...
asm ax,.a;

287
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.158 E2019: 'identifier' cannot be declared in an anonymous


union (C++)
The compiler found a declaration for a member function or static member in an anonymous union.

Such unions can only contain data members.

3.1.2.159 E2020: Global anonymous union not static (C++)


In C++, a global anonymous union at the file level must be static.

3.1.2.160 E2022: Array size too large (C++)


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:
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

3.1.2.161 E2024: Cannot modify a const object (C++)


This indicates an illegal operation on an object declared to be const, such as an assignment to the object.

3.1.2.162 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 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:
this = malloc(n);

3 3.1.2.163 E2026: Assembler statement too long (C++)


Inline assembly statements can't be longer than 480 bytes.

288
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.164 E2001: Constructors and destructors not allowed in


__automated section (C++)
Only member function declarations are allowed in __automated sections.

Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
clxclass() {}// Error
};

3.1.2.165 E2002: Only __fastcall functions allowed in __automated


section (C++)
The calling convention for functions declared in an __automated section must be __fastcall.

Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
int__cdecl barInt(int);// Error
};

3.1.2.166 E2003: Data member definition not allowed in __automated


section (C++)
Only member function declarations are allowed in __automated sections.

Example
struct__declspec(delphiclass) clxclass
{
__automated:
int__fastcall fooInt(int);// OK
intmemInt;// Error
};

3.1.2.167 E2004: Only read or write clause allowed in property


declaration in __automated section (C++)
Storage specifiers stored, default, and nodefault are not allowed in property declarations in __automated sections. 3
Example
struct__declspec(delphiclass) clxclass
{
int __fastcall Get(void);
__automated:
int __property ip1 = { read = Get }; // OK
int __property ip2 = { read = Get, default = 42 }; // Error
};

289
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.168 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. Property hoisting is not allowed.

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
};

3.1.2.169 E2027: Must take address of a memory location (C++)


Your source file used the address-of operator (&) with an expression that can't be used that way; for example, a register variable.

3.1.2.170 E2028: operator -> must return a pointer or a class (C++)


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.

3.1.2.171 E2029: 'identifier' must be a previously defined class or


struct (C++)
You are attempting to declare 'identifier' to be a base class, but either it is not a class or it has not yet been fully defined.

Correct the name or rearrange the declarations.

3.1.2.172 E2030: Misplaced break (C++)


The compiler encountered a break statement outside a switch or looping construct.
3 You can only use break statements inside of switch statements or loops.

3.1.2.173 E2031: Cannot cast from 'type1' to 'type2' (C++)


A cast from type 'ident1' to type 'ident2' is not allowed.

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

• A pointer can be cast to an integral type or to another pointer.


• An integral type can be cast to any integral, floating, or pointer type.
• A floating type can be cast to an integral or floating type.
Structures and arrays can't be cast to or from.
You usually can't cast from a void type.
In C++
User-defined conversions and constructors are checked for. If one can't be found, the preceding rules apply (except for pointers
to class members).
Among integral types, only a constant zero can be cast to a member pointer.
A member pointer can be cast to an integral type or to a similar member pointer.
A similar member pointer points to a data member (or to a function) if the original does. The qualifying class of the type being
cast to must be the same as (or a base class of) the original.

3.1.2.174 E2033: Misplaced continue (C++) 3


The compiler encountered a continue statement outside a looping construct.

3.1.2.175 E2034: Cannot convert 'type1' to 'type2' (C++)


An assignment, initialization, or expression requires the specified type conversion to be performed, but the conversion is not

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.

In cases where this is what is intended, performing a typecast is necessary:


myex( int );
typedef int ( *ffp )( float );
test()
{
ffp fp = (ffp)myex; //ok
}

3.1.2.176 E2036: Conversion operator cannot have a return type


specification (C++)
This C++ type conversion member function specifies a return type different from the type itself.

A declaration for conversion function operator can't specify any return type.

3.1.2.177 E2037: The constructor 'constructor' is not allowed (C++)


Constructors of the form
X(X); //{ Error
};
are not allowed.

This is the correct way to write a copy constructor:


class X {
X(const X&);// Copy constructor
};

3.1.2.178 E2039: Misplaced decimal point (C++)


The compiler encountered a decimal point in a floating-point constant as part of the exponent.
3

3.1.2.179 E2041: Incorrect use of default (C++)


The compiler found no colon after the default keyword.

292
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.180 E2042: Declare operator delete (void*) or (void*, size_t)


(C++)
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.

3.1.2.181 E2044: operator delete must return void (C++)


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.

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.

The name of the destructor must be same as the class name.

In your source file, the ~ preceded some other name.

3.1.2.183 E2048: Unknown preprocessor directive: 'identifier' (C++)


The compiler encountered a # character at the beginning of a line. The directive name that followed the # was not one of the
following:

• define ( see page 690)


3
• else ( see page 688)
• endif
• if
• ifdef ( see page 688)
• ifndef ( see page 688)
• include ( see page 692)

293
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

• line ( see page 693)


• pragma
• undef ( see page 692)

3.1.2.184 E2046: Bad file name format in include directive OR Bad


file name format in line directive (C++)
Include and line directive file names must be surrounded by quotes ("filename.h") or angle brackets (<filename.h>).

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.

3.1.2.185 E2051: Invalid use of dot (C++)


An identifier must immediately follow a period operator (.). This is a rare message that can only occur in some specialized inline
assembly statements.

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;
}

3.1.2.186 E2053: Misplaced elif directive (C++)


The compiler encountered an #elif directive without any matching #if, #ifdef, or #ifndef directive.

3.1.2.187 E2054: Misplaced else (C++)


The compiler encountered an else statement without a matching if statement.

Possible Causes

• An extra "else" statement

3 • An extra semicolon
• Missing braces
• Some syntax error in a previous "if" statement

3.1.2.188 E2055: Misplaced else directive (C++)


The compiler encountered an #else directive without any matching #if, #ifdef, or #ifndef directive.

294
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.189 E2056: Misplaced endif directive (C++)


The compiler encountered an #endif directive without any matching #if, #ifdef, or #ifndef directive.

3.1.2.190 E2059: Unknown language, must be C or C++ (C++)


In the C++ construction
extern "name" type func( /*...*/ );
the given "name" must be "C" or "C++" (use the quotes); other language names are not recognized.

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( /*...*/ );

3.1.2.191 E2060: Illegal use of floating point (C++)


Floating-point operands are not allowed in these operators

• shift (SHL, SHR)


• bitwise Boolean (AND, OR, XOR, NOT)
• conditional (? :)
• indirection (*)
• certain others
The compiler found a floating-point operand with one of these prohibited operators.

3.1.2.192 E2061: Friends must be functions or classes (C++)


A friend of a C++ class must be a function or another class.

3.1.2.193 E2062: Invalid indirection (C++)


The indirection operator (*) requires a pointer as the operand.

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

3.1.2.194 E2063: Illegal initialization (C++)


Initializations must be one of the following:

• constant expressions
• the address of a global extern or static variable plus or minus a constant

3.1.2.195 E2064: Cannot initialize 'type1' with 'type2' (C++)


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.

3.1.2.196 E2068: 'identifier' is not a non-static data member and can't


be initialized here (C++)
Only data members can be initialized in the initializers of a constructor.

This message means that the list includes a static member or function member.

Static members must be initialized outside of the class, for example:


class A { static int i; };
int A::i = -1;

3.1.2.197 E2069: Illegal use of member pointer (C++)


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:
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 will compile:


class A {
public:
myex();
};
typedef int (A::*Amfptr)();
foo()
{
A a;
Amfptr mmyex = &A::myex;
return (a.*mmyex)();
}

3.1.2.198 E2071: operator new must have an initial parameter of type


size_t (C++)
E2071 Operator new[] must have an initial parameter of type size_tCompiler error

Operator new can be declared with an arbitrary number of parameters.

It must always have at least one, the amount of space to allocate.

3.1.2.199 E2072: Operator new[] must return an object of type void


(C++)
This C++ overloaded operator new was declared in some other way.

3.1.2.200 E2075: Incorrect 'type' option: option (C++)


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.

3.1.2.201 E2076: Overloadable operator expected (C++)


Almost all C++ operators can be overloaded.

These are the only ones that can't be overloaded:

• the field-selection dot (.)


• dot-star (.*) 3
• double colon (::)
• conditional expression (?:)
The preprocessor operators (# and ##) are not C or C++ language operators and thus can't be overloaded.
Other non-operator punctuation, such as semicolon (;), can't be overloaded.

297
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.202 E2080: 'function' must be declared with one parameter


(C++)
This C++ operator function was incorrectly declared with more than one parameter.

3.1.2.203 E2077: 'operator' must be declared with one or no


parameters (C++)
When operator ++ or operator -- is declared as a member function, it must be declared to take either:

• No parameters (for the prefix version of the operator), or


• One parameter of type int (for the postfix version)

3.1.2.204 E2079: 'function' must be declared with no parameters


(C++)
This C++ operator function was incorrectly declared with parameters.

3.1.2.205 E2078: 'operator' must be declared with one or two


parameters (C++)
When operator ++ or operator -- is declared as a non-member function, it must be declared to take either:

• one parameter (for the prefix version of the operator), or


• two parameters (for the postfix version)

3.1.2.206 E2081: 'function' must be declared with two parameters


(C++)
This C++ operator function was incorrectly declared with other than two parameters.

3.1.2.207 E2082: 'identifier' must be a member function or have a


parameter of class type (C++)
3
Most C++ operator functions must have an implicit or explicit parameter of class type.

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++)

3.1.2.208 E2083: Last parameter of 'operator' must have type 'int'


(C++)
When a postfix operator ++ or operator -- is overloaded, the last parameter must be declared with the type int.

3.1.2.209 E2084: Parameter names are used only with a function


body (C++)
When declaring a function (not defining it with a function body), you must use either empty parentheses or a function prototype.

A list of parameter names only is not allowed.

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 */

3.1.2.210 E2085: Invalid pointer addition (C++)


Your source file attempted to add two pointers together.

3.1.2.211 E2086: Illegal pointer subtraction (C++)


This is caused by attempting to subtract a pointer from a non-pointer.

3.1.2.212 E2087: Illegal use of pointer (C++)


Pointers can only be used with these operators:

• 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

3.1.2.213 E2088: Bad syntax for pure function definition (C++)


Pure virtual functions are specified by appending "= 0" to the declaration, like this:
class A { virtual void f () = 0;}
class B : public A { void f () {}; }
You wrote something similar, but it was not correct.

3.1.2.214 E2089: Identifier 'identifier' cannot have a type qualifier


(C++)
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).

3.1.2.215 E2090: Qualifier 'identifier' is not a class or namespace


name (C++)
The C++ qualifier in the construction qual::identifier is not the name of a struct or class.

3.1.2.216 E2092: Storage class 'storage class' is not allowed here


(C++)
The given storage class is not allowed here.

Probably two storage classes were specified, and only one can be given.

3.1.2.217 E2096: Illegal structure operation (C++)


Structures can only be used with dot (.), address-of (&) or assignment (=) operators, or be passed to or from a function as
parameters.

3 The compiler encountered a structure being used with some other operator.

3.1.2.218 E2104: Invalid use of template keyword (C++)


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.

300
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.219 E2108: Improper use of typedef 'identifier' (C++)


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.

3.1.2.220 E2109: Not an allowed type (C++)


Your source file declared some sort of forbidden type; for example, a function returning a function or array.

3.1.2.221 E2110: Incompatible type conversion (C++)


The cast requested can't be done.

3.1.2.222 E2113: Virtual function 'function1' conflicts with base class


'base' (C++)
A virtual function has the same argument types as one in a base class, but differs in one or more of the following:

• Return type
• Calling convention
• Exception specification (throw list)

3.1.2.223 E2114: Multiple base classes require explicit class names


(C++)
In a C++ class constructor, if there is more than one immediate base class, each base class constructor call in the constructor
header must include the base class name.

3.1.2.224 E2115: Bit field too large (C++)


This error occurs when you supply a bit field with more than 16 bits.

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.

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.

301
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.226 W8005: Bit fields must be signed or unsigned int (C++)


In ANSI C, bit fields may only be signed or unsigned int (not char or long, for example).

3.1.2.227 E2119: User break (C++)


You typed a Ctrl+Break while compiling in the IDE.

(This is not an error, just a confirmation.)

3.1.2.228 E2111: Type 'typename' may not be defined here (C++)


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.1.2.229 E2121: Function call missing ) (C++)


The function call argument list had some sort of syntax error, such as a missing or mismatched right parenthesis.

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.

3.1.2.231 E2126: Case bypasses initialization of a local variable


(C++)
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.

3.1.2.232 E2127: Case statement missing : (C++)


3
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.

3.1.2.233 E2128: Case outside of switch (C++)


The compiler encountered a case statement outside a switch statement.

302
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

This is often caused by mismatched braces.

3.1.2.234 E2129: Character constant too long (or empty) (C++)


Character constants can only be one or two characters long.

3.1.2.235 E2133: Unable to execute command 'command' (C++)


The linker or assembler cannot be found, or possibly the disk is bad.

3.1.2.236 E2134: Compound statement missing closing brace (C++)


The compiler reached the end of the source file and found no closing brace.

This is most commonly caused by mismatched braces.

3.1.2.237 E2137: Destructor for 'class' required in conditional


expression (C++)
If the compiler must create a temporary local variable in a conditional expression, 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.

3.1.2.238 E2135: Constructor/Destructor cannot be declared 'const'


or 'volatile' (C++)
A constructor or destructor has been declared as const or volatile.

This is not allowed.

3.1.2.239 E2138: Conflicting type modifiers (C++)


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. 3

3.1.2.240 E2136: Constructor cannot have a return type specification


(C++)
C++ constructors have an implicit return type used by the compiler, but you can't declare a return type or return a value.

303
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.241 E2038: Cannot declare or define 'identifier' here: wrong


namespace (C++)
You tried to declare a template in an illegal place or a namespace member outside of its namespace.

3.1.2.242 E2154: Cannot define 'identifier' using a namespace alias


(C++)
You cannot use a namespace alias to define a namespace member outside of its namespace.

3.1.2.243 E2421: Cannot use local type 'identifier' as template


argument (C++)
A local type was used in an actual template type argument, which is illegal.

3.1.2.244 E2035: Conversions of class to itself or base class not


allowed (C++)
You tried to define a conversion operator to the same class or a base class.

3.1.2.245 E2139: Declaration missing ; (C++)


Your source file contained a struct or union field declaration that was not followed by a semicolon.

Check previous lines for a missing semicolon.

3.1.2.246 E2140: Declaration is not allowed here (C++)


Declarations can't be used as the control statement for while, for, do, if, or switch statements.

3.1.2.247 E2141: Declaration syntax error (C++)


Your source file contained a declaration that was missing a symbol or had an extra symbol added to it.
3
Check for a missing semicolon or parenthesis on that line or on previous lines.

3.1.2.248 E2142: Base class 'class' contains dynamically


dispatchable functions (C++)
This error occurs when a class containing a DDVT function attempts to inherit DDVT functions from multiple parent classes.

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.

3.1.2.249 E2143: Matching base class function 'function' has


different dispatch number (C++)
If a DDVT function is declared in a derived class, the matching base class function must have the same dispatch number as the
derived function.

3.1.2.250 E2144: Matching base class function 'function' is not


dynamic (C++)
If a DDVT function is declared in a derived class, the matching base class function must also be dynamic.

3.1.2.251 E2145: Functions 'function1' and 'function2' both use the


same dispatch number (C++)
This error indicates a dynamically dispatched virtual table (DDVT) problem.

3.1.2.252 E2146: Need an identifier to declare (C++)


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.

3.1.2.253 E2147: 'identifier' cannot start a parameter declaration


(C++)
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.

3.1.2.254 E2150: Type mismatch in default argument value (C++)


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.

305
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.255 E2152: Default expression may not use local variables


(C++)
A default argument expression is not allowed to use any local variables or other parameters.

3.1.2.256 E2153: Define directive needs an identifier (C++)


The first non-whitespace character after a #define must be an identifier.

The compiler found some other character.

3.1.2.257 E2155: Too many default cases (C++)


The compiler encountered more than one default statement in a single switch.

3.1.2.258 E2156: Default outside of switch (C++)


The compiler encountered a default statement outside a switch statement.

This is most commonly caused by mismatched braces.

3.1.2.259 E2158: Operand of 'delete' must be non-const pointer (C++)


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:
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.

3.1.2.266 E2165: Destructor cannot have a return type specification


(C++)
C++ destructors never return a value, and you can't declare a return type or return a value.

3.1.2.267 E2166: Destructor for 'class' is not accessible (C++)


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.

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

3.1.2.269 E2168: Division by zero (C++)


Your source file contains a divide or remainder in a constant expression with a zero divisor.

3.1.2.270 E2169: 'identifier' specifies multiple or duplicate access


(C++)
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.

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.

3.1.2.272 E2171: Body has already been defined for function


'function' (C++)
A function with this name and type was previously supplied a function body.

A function body can only be supplied 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() {}

3.1.2.273 E2172: Duplicate case (C++)


3 Each case of a switch statement must have a unique constant expression value.

3.1.2.274 E2175: Too many storage classes in declaration (C++)


A declaration can never have more than one storage class, either Auto, Register, Static, or Extern.

308
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.275 E2176: Too many types in declaration (C++)


A declaration can never have more than one basic type. Examples of basic types are:

• char
• class
• int
• float
• double
• struct
• union
• enum
• typedef name

3.1.2.276 E2179: virtual specified more than once (C++)


The C++ reserved word "virtual" can appear only once in one member function declaration.

3.1.2.277 E2007: Dispid only allowed in __automated sections (C++)


The definition of dispids is only permitted in __automated sections.

Example
struct__declspec(delphiclass) clxclass
{
int __fastcall foo1(void) __dispid(42);// Error
__automated:
int __fastcall foo2(void) __dispid(43);// OK
};

3.1.2.278 Divide error (C++)


You tried to divide an integer by zero, which is illegal.

3.1.2.279 E2182: Illegal parameter to __emit__ (C++)


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__.


3

3.1.2.280 E2183: File must contain at least one external declaration


(C++)
This compilation unit was logically empty, containing no external declarations.

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.281 E2184: Enum syntax error (C++)


An enum declaration did not contain a properly formed list of identifiers.

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.

3.1.2.283 E2186: Unexpected end of file in comment started on line


'number' (C++)
The source file ended in the middle of a comment.

This is normally caused by a missing close of comment (*/).

3.1.2.284 E2187: Unexpected end of file in conditional started on line


'number' (C++)
The source file ended before the compiler (or MAKE) encountered #endif.

The #endif either was missing or misspelled.

Every #if statement needs a matching #endif statement.

3.1.2.285 E2188: Expression syntax (C++)


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:

• two consecutive operators


• mismatched or missing parentheses
• a missing semicolon on the previous statement.
3 Solutions
If the line where the error occurred looks syntactically correct, look at the line directly above for errors.
Try moving the line with the error to a different location in the file and recompiling.
If the error still occurs at the moved statement, the syntax error is occurring somewhere in that statement.
If the error occurred in another statement, the syntax error is probably in the surrounding code.

310
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.286 E2190: Unexpected closing brace (C++)


An extra right brace was encountered where none was expected. Check for a missing closing brace.

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.

3.1.2.287 E2189: extern variable cannot be initialized (C++)


The storage class extern applied to a variable means that the variable is being declared but not defined here--no storage is being
allocated for it.

Therefore, you can't initialize the variable as part of the declaration.

3.1.2.288 E2344: Earlier declaration of 'identifier' (C++)


This error message only shows up after the messages "Multiple declaration for 'identifier'" and "Type mismatch in redeclaration
of 'identifier'". It tells you where the previous definition of the identifier in question was found by the compiler, so you don't have to
search for it.

3.1.2.289 E2192: Too few parameters in call (C++)


This error message occurs when a call to a function with a prototype (via a function pointer) had too few arguments. Prototypes
require that all parameters be given. Make certain that your call to a function has the same parameters as the function prototype.

3.1.2.290 E2193: Too few parameters in call to 'function' (C++)


A call to the named function (declared using a prototype) has too few arguments.

Make certain that the parameters in the call to the function match the parameters of the function prototype.

3.1.2.291 E2194: Could not find file 'filename' (C++)


The compiler is unable to find the file supplied on the command line.

3.1.2.292 E2197: File name too long (C++) 3

The file name given in an #include directive was too long for the compiler to process.

File names in DOS must be no more than 79 characters long.

311
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.293 E2195: Cannot evaluate function call (C++)


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.

3.1.2.294 E2198: Not a valid expression format type (C++)


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).

3.1.2.295 E2200: Functions may not be part of a struct or union


(C++)
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++.

3.1.2.296 Floating point error: Divide by 0 OR Floating point error:


Domain OR Floating point error: Overflow (C++)
These fatal errors result from a floating-point operation for which the result is not finite:

• Divide by 0 means the result is +INF or -INF exactly, such as 1.0/0.0.


• Domain means the result is NAN (not a number), like 0.0/0.0.
• Overflow means the result is +INF (infinity) or -INF with complete loss of precision, such as assigning 1e200*1e200 to a
double.

3.1.2.297 Floating point error: Stack fault (C++)


The floating-point stack has been overrun. This error may be due to assembly code using too many registers or due to a
misdeclaration of a floating-point function.

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

3.1.2.298 Floating point error: Partial loss of precision OR Floating


point error: Underflow (C++)
These exceptions are masked by default, because underflows are converted to zero and losses of precision are ignored.

312
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.299 E2201: Too much global data defined in file (C++)


The sum of the global data declarations exceeds 64K bytes. This includes any data stored in the DGROUP (all global variables,
literal strings, and static locals).

Solutions

Check the declarations for any array that might be too large. You can also remove variables from the DGROUP.

Here's how:

• Declare the variables as automatic. This uses stack space.


• Dynamically allocate memory from the heap using calloc, malloc, or farmalloc for the variables. This requires the use of
pointers.
Literal strings are also put in the DGROUP. Get the file farstr.zip from our BBS to extract literal strings into their own segment.

3.1.2.300 E2203: Goto bypasses initialization of a local variable


(C++)
In C++, it is illegal to bypass the initialization of a local variable.

This error indicates a goto statement that can transfer control past this local variable.

3.1.2.301 E2204: Group overflowed maximum size: 'name' (C++)


The total size of the segments in a group (for example, DGROUP) exceeded 64K.

3.1.2.302 E2206: Illegal character 'character' (0x'value') (C++)


The compiler encountered some invalid character in the input file.

The hexadecimal value of the offending character is printed.

This can also be caused by extra parameters passed to a function macro.

3.1.2.303 E2207: Implicit conversion of 'type1' to 'type2' not allowed


(C++)
When a member function of a class is called using a pointer to a derived class, the pointer value must be implicitly converted to
point to the appropriate base class. 3
In this case, such an implicit conversion is illegal.

3.1.2.304 E2208: Cannot access an inactive scope (C++)


You have tried to evaluate or inspect a variable local to a function that is currently not active. (This is an integrated debugger
expression evaluation message.)

313
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.305 E2209: Unable to open include file 'filename' (C++)


The compiler could not find the named file.

Possible Causes

• The named file does not exist.


• An #include file included itself.
• You do not have FILES set in CONFIG.SYS on your root directory.
Solutions
• Verify that the named file exists.
• Set FILES = 20 in CONFIG.SYS.

3.1.2.306 E2210: Reference member 'member' is not initialized (C++)


References must always be initialized, in the constructor for the class.

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.

3.1.2.307 E2212: Function defined inline after use as extern (C++)


Functions can't become inline after they have already been used.

Either move the inline definition forward in the file or delete it entirely.

The compiler encountered something like:


myex();
twoex() { myex(); }
inline myex() { return 2; } // error
and already used the function as an extern before it saw that it was specified as inline. This would be correct:
myex();
inline myex() { return 2; }
twoex() { myex(); }
or better:
inline myex();
inline myex() { return 2; }
twoex() { myex(); }
3
3.1.2.308 E2211: Inline assembly not allowed in inline and template
functions (C++)
The compiler can't handle inline assembly statements in a C++ inline or template function.

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++)

3.1.2.309 F1001: Internal code generator error (C++)


An error has occurred in the internal logic of the code generator. Contact CodeGear technical support.

3.1.2.310 E2413: Invalid template declaration (C++)


After the declarator of a template member, either a semicolon, an initialization, or a body was expected, but some other, illegal
token was found. This message appears when a template member is declared outside of the template, but the syntax was wrong.

3.1.2.311 E2070: Invalid use of namespace 'identifier' (C++)


A namespace identifier was used in an illegal way, for example, in an expression.

3.1.2.312 E2214: Cannot have a 'non-inline function/static data' in a


local class (C++)
All members of classes declared local to a function must be entirely defined in the class definition.

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.

3.1.2.313 E2215: Linkage specification not allowed (C++)


Linkage specifications such as extern "C" are only allowed at the file level.

Move this function declaration out to the file level.

3.1.2.314 E2216: Unable to create turboc.$ln (C++)


The compiler cannot create the temporary file TURBOC.$LN because it cannot access the disk or the disk is full.

3.1.2.315 E2218: Templates can only be declared at namespace or


class scope (C++)
Templates cannot be declared inside classes or functions. They are only allowed in the global scope, or file level.
3
For example:
void func()
{
template <class T> myClass { // Error
T i;
};
}

315
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.316 E2217: Local data exceeds segment size limit (C++)


The local variables in the current function take up more than 64K.

3.1.2.317 E2219: Wrong number of arguments in call of macro


'macro' (C++)
Your source file called the named macro with an incorrect number of arguments.

3.1.2.318 E2220: Invalid macro argument separator (C++)


In a macro definition, arguments must be separated by commas.

The compiler encountered some other character after an argument name.

This is correct:
#define tri_add(a, b, c) ((a) + (b) + (c))
This is incorrect:
#define tri_add(a b. c) ((a) + (b) + (c))

3.1.2.319 E2221: Macro argument syntax error (C++)


An argument in a macro definition must be an identifier.

The compiler encountered some non-identifier character where an argument was expected.

3.1.2.320 E2222: Macro expansion too long (C++)


A macro can't expand to more than 4,096 characters.

3.1.2.321 E2223: Too many decimal points (C++)


The compiler encountered a floating-point constant with more than one decimal point.

3.1.2.322 E2224: Too many exponents (C++)


3
The compiler encountered more than one exponent in a floating-point constant.

3.1.2.323 E2225: Too many initializers (C++)


The compiler encountered more initializers than were allowed by the declaration being initialized.

316
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.324 E2226: Extra parameter in call (C++)


A call to a function, via a pointer defined with a prototype, had too many arguments.

3.1.2.325 E2227: Extra parameter in call to function (C++)


A call to the named function (which was defined with a prototype) had too many arguments given in the call.

3.1.2.326 E2228: Too many error or warning messages (C++)


There were more errors or warnings than allowed.

3.1.2.327 E2233: Cannot initialize a class member here (C++)


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.

3.1.2.328 E2232: Constant/Reference member 'member' in class


without constructors (C++)
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.

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.

3.1.2.330 E2234: Memory reference expected (C++)


The built-in assembler requires a memory reference.
3
You probably forgot to put square brackets around an index register operand.

317
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.331 E2231: Member 'member' cannot be used without an object


(C++)
This means that you have written class::member where 'member' is an ordinary (non-static) member, and there is no class to
associate with that member.

For example, it is legal to write this:


obj.class::member
but not to write this:
class::member

3.1.2.332 E2235: Member function must be called or its address


taken (C++)
A reference to a member function must be called, or its address must be taken with & operator.

In this case, a member function has been used in an illegal context.

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.

3.1.2.334 E2238: Multiple declaration for 'identifier' (C++)


3 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

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.

3.1.2.335 E2239: 'identifier' must be a member function (C++)


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.

3.1.2.336 E2240: Conversion of near pointer not allowed (C++)


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.

3.1.2.337 E2243: Array allocated using 'new' may not have an


initializer (C++)
When initializing a vector (array) of classes, you must use the constructor that has no arguments.

This is called the default constructor, which means that you can't supply constructor arguments when initializing such a vector.

3.1.2.338 E2244: 'new' and 'delete' not supported (C++) 3

The integrated debugger does not support the evaluation of the new and delete operators.

3.1.2.339 E2245: Cannot allocate a reference (C++)


You have attempted to create a reference using the new operator.

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.

3.1.2.340 E2309: Inline assembly not allowed (C++)


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.

3.1.2.341 E2250: No base class to initialize (C++)


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.

3.1.2.342 E2254: : expected after private/protected/private (C++)


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.

3.1.2.343 E2255: Use :: to take the address of a member function


(C++)
If f is a member function of class c, you take its address with the syntax
&c::f
Note the use of the class type name (not the name of an object) and the :: separating the class name from the function name.

(Member function pointers are not true pointer types, and do not refer to any particular instance of a class.)

3.1.2.344 E2256: No : following the ? (C++)


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.

3.1.2.345 E2257: , expected (C++)


A comma was expected in a list of declarations, initializations, or parameters.
3 This problem is often caused by a missing syntax element earlier in the file or one of its included headers.

3.1.2.346 E2258: Declaration was expected (C++)


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.

320
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.347 E2259: Default value missing (C++)


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.

3.1.2.348 E2260: Default value missing following parameter


'parameter' (C++)
All parameters following the first parameter with a default value must also have defaults specified.

3.1.2.349 E2263: Exception handling not enabled (C++)


A 'try' block was found with the exception handling disabled.

3.1.2.350 E2264: Expression expected (C++)


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.

3.1.2.351 E2266: No file names given (C++)


The command line contained no file names. You must specify a source file name.

3.1.2.352 E2265: No file name ending (C++)


The file name in an #include statement was missing the correct closing quote or angle bracket.

3.1.2.353 E2271: Goto statement missing label (C++)


The goto keyword must be followed by an identifier.

3
3.1.2.354 E2272: Identifier expected (C++)
An identifier was expected here, but not found.

In C, an identifier is expected in the following situations:

• in a list of parameters in an old-style function header


• after the reserved words struct or union when the braces are not present, and

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.

3.1.2.355 E2275: Opening brace expected (C++)


A left brace was expected at the start of a block or initialization.

3.1.2.356 E2276: ( expected (C++)


A left parenthesis was expected before a parameter list.

3.1.2.357 E2274: < expected (C++)


The keyword template was not followed by <.

Every template declaration must include the template formal parameters enclosed within < >, immediately following the template
keyword.

3.1.2.358 E2277: Lvalue required (C++)


The left side of an assignment operator must be an addressable expression.

Addressable expressions include the following:

• numeric or pointer variables


• structure field references or indirection through a pointer
• a subscripted array element

3.1.2.359 E2278: Multiple base classes not supported for Delphi


classes (C++)
Delphi style classes cannot have multiple base classes.

Example
struct__declspec(delphiclass) base1 {};
struct__declspec(delphiclass) base2 {};
3 structderived : base1, base2 {}; // Error

3.1.2.360 E2280: Member identifier expected (C++)


The name of a structure or C++ class member was expected here, but not found. The right side of a dot (.) or arrow (->) operator
must be the name of a member in the structure or class on the left of the operator.

322
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.361 E2279: Cannot find default constructor to initialize member


'identifier' (C++)
When the following occurs

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.

3.1.2.362 E2310: Only member functions may be 'const' or 'volatile'


(C++)
Something other than a class member function has been declared const or volatile.

3.1.2.363 E2311: Non-virtual function 'function' declared pure (C++)


Only virtual functions can be declared pure, because derived classes must be able to override them.

3.1.2.364 E2283: Use . or -> to call 'function' (C++)


You attempted to call a member function without providing an object. This is required to call a member function.
class X {
member func() {}
};
X x;
X*xp = new X;
X.memberfunc();
Xp-> memberfunc();

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.

3.1.2.366 E2285: Could not find a match for 'argument(s)' (C++)


No C++ function could be found with parameters matching the supplied arguments. Check parameters passed to function or

323
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

overload function for parameters that are being passed.

3.1.2.367 E2286: Overloaded function resolution not supported (C++)


In integrated debugger expression evaluation, resolution of overloaded functions or operators is not supported, not even to take
an address.

3.1.2.368 E2287: Parameter 'number' missing name (C++)


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.)

3.1.2.369 E2288: Pointer to structure required on left side of -> or ->*


(C++)
Nothing but a pointer is allowed on the left side of the arrow (->) in C or C++.

In C++ a -> operator is allowed.

3.1.2.370 E2290: 'code' missing ] (C++)


This error is generated if any of the following occur:

• 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.1.2.371 E2291: brace expected (C++)


A right brace was expected at the end of a block or initialization.

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++)

3.1.2.373 E2293: ) expected (C++)


A right parenthesis was expected at the end of a parameter list.

3.1.2.374 E2294: Structure required on left side of . or .* (C++)


The left side of a dot (.) operator (or C++ dot-star operator, .*) must evaluate to a structure type. In this case it did not.

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'.

3.1.2.375 E2312: 'constructor' is not an unambiguous base class of


'class' (C++)
A C++ class constructor is trying to call a base class constructor 'constructor.'

This error can also occur if you try to change the access rights of 'class::constructor.'

Check your declarations.

3.1.2.376 E2313: Constant expression required (C++)


Arrays must be declared with constant size.

This error is commonly caused by misspelling a #define constant.

3.1.2.377 E2296: Templates not supported (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.

3.1.2.378 E2314: Call of nonfunction (C++)


The name being called is not declared as a function.

This is commonly caused by incorrectly declaring the function or misspelling the function name.

3.1.2.379 E2321: Declaration does not specify a tag or an identifier 3

(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

3.1.2.380 E2297: 'this' can only be used within a member function


(C++)
In C++, "this" is a reserved word that can be used only within class member functions.

3.1.2.381 E2316: 'identifier' is not a member of 'struct' (C++)


You are trying to reference 'identifier' as a member of 'struct', but it is not a member.

Check your declarations.

3.1.2.382 E2317: 'identifier' is not a parameter (C++)


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.

3.1.2.383 E2319: 'identifier' is not a public base class of 'classtype'


(C++)
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.

3.1.2.384 E2320: Expression of scalar type expected (C++)


The !, ++, and -- operators require an expression of scalar type.

Only these types are allowed:

• char
• short
• int
• long

3 • enum
• float
• double
• long double
• pointer

326
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.385 E2302: No type information (C++)


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.

3.1.2.386 E2303: Type name expected (C++)


One of these errors has occurred:

• 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.

3.1.2.387 E2304: 'Constant/Reference' variable 'variable' must be


initialized (C++)
This C++ object is declared constant or as a reference, but is not initialized.

It must be initialized at the point of declaration.

3.1.2.388 E2305: Cannot find 'class::class' ('class'&) to copy a vector


OR Cannot find 'class'::operator=('class'&) to copy a vector (C++)
When a C++ class 'class1' contains a vector (array) of class 'class2', and you want to construct an object of type 'class1' from
another object of type 'class 1', you must use this constructor:
class2::class2(class2&)
so that the elements of the vector can be constructed.

The constructor, called a copy constructor, takes just one parameter (which is a reference to its class).

Usually, the compiler supplies a copy constructor automatically.

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.

This is because these two can't be distinguished:


class2::class2(class2&)
class2::class2(class2&, int = 1) 3
You must redefine this constructor so that not all parameters have default values.

You can then define a reference constructor or let the compiler create one.

Cannot find class::operator= ...

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.

Usually, the compiler automatically supplies this operator.

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.

3.1.2.389 E2306: Virtual base classes not supported for Delphi


classes (C++)
Delphi style classes cannot be derived virtually, not even from other Delphi style classes.

Example
struct __declspec(delphiclass) base {};
struct derived : virtual base {}; // Error

3.1.2.390 E2308: do statement must have while (C++)


Your source file contained a do statement that was missing the closing while keyword.

3.1.2.391 E2322: Incorrect number format (C++)


The compiler encountered a decimal point in a hexadecimal number.

3.1.2.392 E2324: Numeric constant too large (C++)


String and character escape sequences larger than hexadecimal or octal 77 can't be generated.

Two-byte character constants can be specified by using a second backslash. For example,
\\
represents a two-byte constant.

A numeric literal following an escape sequence should be broken up like this:


printf("\x0A" "12345");
This prints a carriage return followed by 12345.

3.1.2.393 E2282: Namespace name expected (C++)


3
The name of a namespace symbol was expected.

3.1.2.394 E2334: Namespace member 'identifier' declared outside its


namespace (C++)
Namespace members must be declared inside their namespace. You can only use explicit qualification to define a namespace

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.

3.1.2.395 E2325: Illegal octal digit (C++)


The compiler found an octal constant containing a non-octal digit (8 or 9).

3.1.2.396 E2329: Invalid combination of opcode and operands (C++)


The built-in assembler does not accept this combination of operands.

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.

3.1.2.397 E2327: Operators may not have default argument values


(C++)
It is illegal for overloaded operators to have default argument values.

3.1.2.398 E2330: Operator must be declared as function (C++)


An overloaded operator was declared with something other than function type.

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.

3.1.2.399 E2333: Class member 'member' declared outside its class


(C++)
C++ class member functions can be declared only inside the class declaration.

Unlike nonmember functions, they can't be declared multiple times or at other locations.
3

3.1.2.400 E2335: Overloaded 'function name' ambiguous in this


context (C++)
The only time an overloaded function name can be used or assigned without actually calling the function is when a variable or
parameter of the correct function pointer type is initialized or assigned the address of the overload function.

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){}
};

3.1.2.401 E2339: Cannot overload 'main' (C++)


You cannot overload main.

3.1.2.402 E2336: Pointer to overloaded function 'function' doesn't


match 'type' (C++)
A variable or parameter is assigned (or initialized with) the address of an overloaded function.

However, the type of the variable or parameter doesn't match any of the overloaded functions with the specified name.

3.1.2.403 E2337: Only one of a set of overloaded functions can be


"C" (C++)
C++ functions are by default overloaded, and the compiler assigns a new name to each function.

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.)

3.1.2.404 E2338: Overlays only supported in medium, large, and


huge memory models (C++)
The compiler no longer issues this error.

3.1.2.405 E2340: Type mismatch in parameter 'number' (C++)


The function called, via a function pointer, was declared with a prototype.

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++)

3.1.2.406 E2341: Type mismatch in parameter 'number' in call to


'function' (C++)
Your source file declared the named function with a prototype, and the given parameter number (counting left to right from 1)
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.

3.1.2.407 E2342: Type mismatch in parameter 'parameter' (C++)


Your source file declared the function called via a function pointer with a prototype.

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.

3.1.2.408 E2343: Type mismatch in parameter 'parameter' in call to


'function' (C++)
Your source file declared the named function with a prototype, and 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.

3.1.2.409 E2345: Access can only be changed to public or protected


(C++)
A C++ derived class can modify the access rights of a base class member, but only to public or protected.

A base class member can't be made private.

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

3.1.2.411 E2350: Cannot define a pointer or reference to a reference


(C++)
It is illegal to have a pointer to a reference or a reference to a reference.

3.1.2.412 E2352: Cannot create instance of abstract class 'class'


(C++)
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:
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

3.1.2.413 E2354: Two operands must evaluate to the same type


(C++)
The types of the expressions on both sides of the colon in the conditional expression operator (?:) must be the same, except for
3
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.

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.

3.1.2.414 E2355: Recursive template function: 'x' instantiated 'y'


(C++)
The compiler has detected a recursive template function instance. For example:
template<class T> void f(T x)
{
f((T*)0); // recursive template function!
}
void main()
{
f(0);
}
The compiler issue one message for each nesting of the recursive instantiation, so it is usually obvious where the recursion has
occurred. To fix a recursive template, either change the dependencies or provide a specialized version that will stop the
recursion. For example, adding the following function definition to the above program will remove the endless recursion:
void f(int **)
{
}

3.1.2.415 E2356: Type mismatch in redeclaration of 'identifier' (C++)


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.

3.1.2.416 E2357: Reference initialized with 'type1', needs lvalue of


type 'type2' (C++)
A reference variable that is not declared constant must be initialized with an 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.
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.

This requires the compiler to create a temporary for the initialization.

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.

3.1.2.418 E2360: Invalid register combination (e.g. [BP+BX]) (C++)


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.

3.1.2.419 E2361: 'specifier' has already been included (C++)


This type specifier occurs more than once in this declaration.

Delete or change one of the occurrences.

3.1.2.420 E2362: Repeat count needs an lvalue (C++)


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:
i++,10d
x = y, 10m

3.1.2.421 E2363: Attempting to return a reference to local variable


'identifier' (C++)
This C++ function returns a reference type, and you are trying to return a 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.
3

3.1.2.422 E2364: Attempting to return a reference to a local object


(C++)
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.

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.

3.1.2.423 E2365: Member pointer required on right side of .* or ->*


(C++)
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.

3.1.2.424 E2366: Can't inherit non-RTTI class from RTTI base OR


E2367 Can't inherit RTTI class from non-RTTI base (C++)
When virtual functions are present, the RTTI attribute of all base classes must match that of the derived class.

3.1.2.425 E2368: RTTI not available for expression evaluation (C++)


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.

3.1.2.426 E2371: sizeof may not be applied to a bit field (C++)


sizeof returns the size of a data object in bytes, which does not apply to a bit field.

3.1.2.427 E2372: sizeof may not be applied to a function (C++)


sizeof can be applied only to data objects, not functions.

You can request the size of a pointer to a function.

3.1.2.428 E2373: Bit field cannot be static (C++)


Only ordinary C++ class data members can be declared static, not bit fields.

3.1.2.429 E2374: Function 'function' cannot be static (C++)


3
Only ordinary member functions and the operators new and delete can be declared static.

Constructors, destructors and other operators must not be static.

3.1.2.430 Stack overflow (C++)


This error is reported when you compile a function with the Test Stack Overflow option on, but there is not enough stack space to

335
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

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 the stack project
• a large array in a function

3.1.2.431 E2376: statement missing (C++)


In a do, for, if, switch, or while statement, the compiler found no left parenthesis after the while keyword or test expression.

3.1.2.432 E2377: statement missing ) (C++)


In a do, for, if, switch, or while statement, the compiler found no right parenthesis after the while keyword or test expression.

3.1.2.433 E2378: do-while or for statement missing ; (C++)


In a do or for statement, the compiler found no semicolon after the right parenthesis.

3.1.2.434 E2379: Statement missing ; (C++)


The compiler encountered an expression statement without a semicolon following it.

3.1.2.435 E2380: Unterminated string or character constant (C++)


The compiler found no terminating quote after the beginning of a string or character constant.

3.1.2.436 E2381: Structure size too large (C++)


Your source file declared a structure larger than 64K.

3.1.2.437 E2382: Side effects are not allowed (C++)


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.
3

3.1.2.438 E2383: Switch selection expression must be of integral


type (C++)
The selection expression in parentheses in a switch statement must evaluate to an integral type (char, short, int,
long, enum).

336
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

You might be able to use an explicit cast to satisfy this requirement.

3.1.2.439 E2433: Specialization after first use of template (C++)


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.

3.1.2.440 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 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.

3.1.2.441 E2390: Type mismatch in parameter 'number' in template


class name 'template' (C++)
The actual template argument value supplied for the given parameter did not 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.

3.1.2.442 E2391: Type mismatch in parameter 'parameter' in template


class name 'template' (C++)
The actual template argument value supplied for the given parameter did not 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.

3.1.2.443 E2394: Too few arguments passed to template 'template' 3


(C++)
A template class name was missing actual values for some of its formal parameters.

337
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.444 E2395: Too many arguments passed to template 'template'


(C++)
A template class name specified too many actual values for its formal parameters.

3.1.2.445 E2396: Template argument must be a constant expression


(C++)
A non-type template class argument must be a constant expression of the appropriate type.

This includes constant integral expressions and addresses of objects or functions with external linkage or members.

3.1.2.446 E2401: Invalid template argument list (C++)


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.

3.1.2.447 E2400: Nontype template argument must be of scalar type


(C++)
A nontype formal template argument must have scalar type; it can have an integral, enumeration, or pointer type.

3.1.2.448 E2415: Template functions may only have 'type-arguments'


(C++)
A function template was declared with a non-type argument.

This is not allowed with a template function, as there is no way to specify the value when calling it.

3.1.2.449 E2425: 'member' is not a valid template type member (C++)


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.
3

3.1.2.450 E2428: Templates must be classes or functions (C++)


The declaration in a template declaration must specify either a class type or a function.

338
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.451 E2432: 'template' qualifier must name a template class or


function instance' (C++)
When defining a template class member, the actual arguments in the template class name used as the left operand for the ::
operator must match the formal arguments of the template class.

3.1.2.452 E2442: Two consecutive dots (C++)


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.

3.1.2.453 E2443: Base class 'class' is initialized more than once


(C++)
In a C++ class constructor, the list of initializations following the constructor header includes base class 'class' more than once.

3.1.2.454 E2444: Member 'member' is initialized more than once


(C++)
In a C++ class constructor, the list of initializations following the constructor header includes the same member name more than
once.

3.1.2.455 E2445: Variable 'identifier' is initialized more than once


(C++)
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).

3.1.2.456 E2446: Function definition cannot be a typedef'ed


declaration (C++)
In ANSI C, a function body cannot be defined using a typedef with a function Type.

Redefine the function body.


3

3.1.2.457 E2132: Templates and overloaded operators cannot have C


linkage (C++)
You tried to use a linkage specification with a template or overloaded operator. The most common cause for this error message
is having the declaration wrapped in an extern "C" linkage specification.

339
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.458 E2447: 'identifier' must be a previously defined


enumeration tag (C++)
This declaration is attempting to reference 'ident' as the tag of an enum type, but it has not been so declared.

Correct the name, or rearrange the declarations.

3.1.2.459 E2448: Undefined label 'identifier' (C++)


The named label has a goto in the function, but no label definition.

3.1.2.460 E2449: Size of 'identifier' is unknown or zero (C++)


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.

3.1.2.461 E2450: Undefined structure 'structure' (C++)


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.

3.1.2.462 E2451: Undefined symbol 'identifier' (C++)


The named identifier has no declaration.

Possible Causes

• Actual declaration of identifier has been commented out.


• Misspelling, either at this point or at the declaration.
• An error in the declaration of the identifier.
• The header file in which the identifier is declared was not included using #include
Tools to help track down the problem:
GREP ( see page 170)
3

3.1.2.463 E2453: Size of the type 'identifier' is unknown or zero (C++)


This type was used in a context where its size was needed.

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++)

Rearrange your declarations so that the size of this type is available.

3.1.2.464 E2452: Size of the type is unknown or zero (C++)


This error message indicates that an array of unspecified dimension nested within another structure is initialized and the -A
(ANSI) switch is on. For example:
struct
{
char a[]; //Size of 'a' is unknown or zero
}
b = { "hello" }; //Size of the type is
//unknown or zero

3.1.2.465 E2454: union cannot be a base type (C++)


A union can't be used as a base type for another class type.

3.1.2.466 E2455: union cannot have a base type (C++)


In general, a C++ class can be of union type, but such a class can't be derived from any other class.

3.1.2.467 E2456: Union member 'member' is of type class with


'constructor' (or destructor, or operator =) (C++)
A union can't contain members that are of type class with user-defined constructors, destructors, or operator =.

3.1.2.468 E2461: '%s' requires run-time initialization/finalization


(C++)
This message is issued when a global variable that is declared as __thread (a Win32-only feature) or a static data member of a
template class is initialized with a non-constant initial value.

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.

3.1.2.469 E2464: 'virtual' can only be used with member functions


(C++) 3
A data member has been declared with the virtual specifier.

Only member functions can be declared virtual.

For example:
class myclass
{
public:

341
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

virtual int a; //error


};

3.1.2.470 E2465: unions cannot have virtual member functions (C++)


A union can't have virtual functions as its members.

3.1.2.471 E2466: void & is not a valid type (C++)


A reference always refers to an object, but an object cannot have the type void.

Thus, the type void is not allowed.

3.1.2.472 E2467: 'Void function' cannot return a value (C++)


A function with a return type void contains a return statement that returns a value; for example, an int.

Default = displayed

3.1.2.473 E2468: Value of type void is not allowed (C++)


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:

• the right side of an assignment


• an argument of a function
• the controlling expression of an if, for, or while statement.

3.1.2.474 E2469: Cannot use tiny or huge memory model with


Windows (C++)
The compiler no longer issues this error.

3.1.2.475 E2006: CodeGuarded programs must use the large


memory model and be targeted for Windows (C++)
The compiler no longer issues this error.
3

3.1.2.476 E2269: The function 'function' is not available (C++)


You tried to call a function that is known to the evaluator, but which was not present in the program being debugged, for
example, an inline function.

342
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.477 E2124: Invalid function call (C++)


A requested function call failed because the function is not available in the program, a parameter cannot be evaluated, and so
on. The evaluator issues this message.

3.1.2.478 E2213: Invalid 'expression' in scope override (C++)


The evaluator issues this message when there is an error in a scope override in an expression you are watching or inspecting.
You can specify a symbol table, a compilation unit, a source file name, etc. as the scope of the expression, and the message will
appear whenever the compiler cannot access the symbol table, compilation unit, or whatever.

3.1.2.479 E2236: Missing 'identifier' in scope override (C++)


The syntax of a scope override is somehow incomplete. The evaluator issues this message.

3.1.2.480 Pure virtual function called (C++)


This is a runtime error. It is generated if the body of a pure virtual function was never generated and somehow the compiler tried
to call it.

3.1.2.481 E2095: String literal not allowed in this context (C++)


This error message is issued by the evaluator when a string literal appears in a context other than a function call.

3.1.2.482 Unexpected termination during compilation [Module


Seg#:offset] OR Unexpected termination during linking [Module
Seg#:offset] (C++)
If either of these errors occur, it indicates a catastrophic failure of the CodeGear tools. You should contact CodeGear to report
the problem and to find a potential work around for your specific case. By isolating the test case as well as possible, you will
increase the chance for either CodeGear or yourself to find a work around for the problem.

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

3.1.2.483 E2012: Cannot take address of 'main' (C++)


In C++, it is illegal to take the address of the main function.

3.1.2.484 E2016: Ambiguous override of virtual base member


'base_function': 'derived_function' (C++)
A virtual function in a virtual base class was overridden with two or more different functions along different paths in the
inheritance hierarchy. For example,
struct VB
{
virtual f();
};
struct A:virtual VB
{
virtual f();
};
//{
struct B:virtual VB
virtual f();
}

3.1.2.485 E2021: Array must have at least one element (C++)


ANSI C and C++ require that an array be defined to have at least one element (objects of zero size are not allowed).

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 */

3.1.2.486 E2023: Array of references is not allowed (C++)


It is illegal to have an array of references, because pointers to references are not allowed and array names are coerced into
pointers.
3

3.1.2.487 E2032: Illegal use of closure pointer (C++)


A closure pointer variable is used incorrectly. Closure variables have limited usage. For instance, you can assign a function to a
closure variable, and execute that function through the closure variable, but you cannot use a closure variable like a pointer
variable.

344
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.488 E2040: Declaration terminated incorrectly (C++)


A declaration has an extra or incorrect termination symbol, such as a semicolon placed after a function body.

A C++ member function declared in a class with a semicolon between the header and the opening left brace also generates this
error.

3.1.2.489 E2047: Bad 'directive' directive syntax (C++)


A macro definition starts or ends with the ## operator, or contains the # operator that is not followed by a macro argument name.

An example of this might be:


Bad ifdef directive syntax
Note that an #ifdef directive must contain a single identifier (and nothing else) as the body of the directive.

Another example is:


Bad undef directive syntax
An #undef directive must also contain only one identifier as the body of the directive.

3.1.2.490 E2049: Class type 'type' cannot be marked as


__declspec(delphireturn) (C++)
Classes marked as delphireturn are special classes that the compiler needs to recognize by name. These classes are predefined
in the headers.

Some of the delphireturn classes are Variant, AnsiString, and Currency.

You cannot mark user-defined classes as delphireturn.

3.1.2.491 E2052: Dynamic function 'function' conflicts with base


class 'class' (C++)
Some of the modifiers of this dynamic function conflict with the definition of the 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)
3
• __fastcall

3.1.2.492 E2057: Exception specification not allowed here (C++)


Function pointer type declarations are not allowed to contain exception specifications.

345
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.493 E2058: Exception handling variable may not be used here


(C++)
An attempt has been made to use one of the exception handling values that are restricted to particular exception handling
constructs, such as GetExceptionCode().

3.1.2.494 E2065: Using namespace symbol 'symbol' conflicts with


intrinsic of the same name (C++)
If you define a function in a namespace, which has a name that might be 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__".

3.1.2.495 E2067: 'main' must have a return type of int (C++)


In C++, function main has special requirements, one of which is that it cannot be declared with any return type other than int.

3.1.2.496 E2073: Nothing allowed after pragma option pop (C++)


The #pragma option pop can only be followed by comments, blanks, or end of line.

3.1.2.497 E2091: Functions cannot return arrays or functions (C++)


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.

3.1.2.498 E2093: Operator 'operator' not implemented in type 'type'


for arguments of the same type (C++)
The operator you are calling is not defined in this class. When you have an expression: x + x, where x is of type class X, the
3 operator + has to be defined in class X and be accessible.

3.1.2.499 E2094: Operator 'operator' not implemented in type 'type'


for arguments of type 'type' (C++)
The operator you are calling is not defined in this class. When you have an expression: x + x, where x is of type class X, the
operator + has to be defined in class X and be accessible.

346
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.500 E2097: Explicit instantiation only allowed at file or


namespace scope (C++)
The explicit instantiation operator "template" can only be used within global or namespace scope. It cannot be used to qualify a
local class or a class member, for example.

3.1.2.501 E2098: Explicit specialization declarator "template<>" now


required (C++)
When specializing a function, such as providing the definition for "foo<int>", so that foo behaves specially which called for the
"int" argument, now requires that the declaration begin with an explicit specialization operator.

3.1.2.502 E2099: Explicit specialization only allowed at file or


namespace scope (C++)
The explicit specialization operator template<> can only be used within global or namespace scope. It cannot be used to qualify
a local class or a class member, for example.

3.1.2.503 E2101: 'export' keyword must precede a template


declaration (C++)
The 'export' keyword can only occur before the keyword "template" ina template declaration. It cannot be used anywhere else.

3.1.2.504 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 templates. It cannot be used with non-templates.

3.1.2.505 E2106: Explicit specialization must be used with a template


class or function (C++)
The explicit specialization operator template<> can only be used in front of a template class or function. Using it with a normal
class means nothing, and hence generates an error.
3

3.1.2.506 E2112: Unknown unit directive: 'directive' (C++)


You cannot use this name as a unit directive. Instead use one of the following unit directives: weak, smart_init, or deny.

347
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.507 E2118: Bit fields must have integral type (C++)


In C++, bit fields must have an integral type. This includes enumerations.

3.1.2.508 E2120: Cannot call 'main' from within the program (C++)
C++ does not allow recursive calls of main( ).

3.1.2.509 E2125: Compiler could not generate copy constructor for


class 'class' OR Compiler could not generate default constructor for
class 'class' OR Compiler could not generate operator = for class
'class' (C++)
Sometimes the compiler is required to generate a member function for the user.

Whenever such a member function can't be generated due to applicable language rules, the compiler issues one of these error
messages.

3.1.2.510 E2130: Circular property definition (C++)


Indicates that a property definition relies directly or indirectly on itself.

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.

3.1.2.511 E2131: Objects of type 'type' cannot be initialized with { }


(C++)
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.
3

3.1.2.512 E2148: Default argument value redeclared for parameter


'parameter' (C++)
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.

348
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.513 E2149: Default argument value redeclared (C++)


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.

3.1.2.514 E2151: Type mismatch in default value for parameter


'parameter' (C++)
The default parameter value given could not be converted to the type of the 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.

3.1.2.515 E2157: Deleting an object requires exactly one conversion


to pointer operator (C++)
If a person uses the 'delete' operator on an object (note: not a pointer to an 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:
char *a = new char[10];
class foo {
public:
operator char *() { return a; }
};

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.

3.1.2.516 E2173: Duplicate handler for 'type1', already had 'type2'


(C++)
It is not legal to specify two handlers for the same type.
3

3.1.2.517 E2174: The name handler must be last (C++)


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).

349
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.518 E2177: Redeclaration of #pragma package with different


arguments (C++)
You can have multiple #pragma package statements in a source file as long as they have the same arguments. This error occurs
if the compiler encounters more than one #pragma package with different arguments in each.

3.1.2.519 E2178: VIRDEF name conflict for 'function' (C++)


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.

3.1.2.520 E2180: Dispid number already used by identifier (C++)


Dispids must be unique and the compiler checks for this.

Example
struct__declspec(delphiclass) clxclass
{
__automated:
int __fastcall foo1(void) __dispid(42);// OK
int __fastcall foo2(void) __dispid(42);// Error
};

3.1.2.521 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 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.

3.1.2.522 E2202: Goto into an exception handler is not allowed (C++)


It is not legal to jump into a try block, or an exception handler that is attached to a try block.

3.1.2.523 E2205: Illegal type type in __automated section (C++)


3 Only certain types are allowed in __automated sections.

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++)

3.1.2.524 E2242: Specifier requires Delphi style class type (C++)


The stored, default, and nodefault storage specifiers are only allowed within property declarations of Delphi style class types.

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
};

3.1.2.525 E2247: 'member' is not accessible (C++)


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 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.

3.1.2.526 E2248: Cannot find default constructor to initialize array


element of type 'class' (C++) 3
When declaring an array of a class that has constructors, you must either 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.

351
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.527 E2251: Cannot find default constructor to initialize base


class 'class' (C++)
Whenever a C++ derived class 'class2' is constructed, each base class 'class1' 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.
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
};

3.1.2.528 E2252: 'catch' expected (C++)


In a C++ program, a 'try' block must be followed by at least one 'catch' block.

3.1.2.529 E2253: Calling convention must be attributed to the


function type, not the closure (C++)
The calling convention is in the wrong place in the closure declaration. For example,
int __fastcall (__closure * x)()
will compile, but
3
int (__fastcall __closure * x)()
will not.

352
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.530 E2261: Use of dispid with a property requires a getter or


setter (C++)
This property needs either a getter or a setter.

3.1.2.531 E2262: '__except' or '__finally' expected following '__try'


(C++)
In C, a '__try block' must be followed by a '__except' or '__finally' handler block.

3.1.2.532 E2270: > expected (C++)


A new-style cast (for example, dynamic_cast) was found with a missing closing ">".

3.1.2.533 E2273: 'main' cannot be declared as static or inline (C++)


You cannot make main static or inline. For example, you cannot use static int main() or inline int main().

3.1.2.534 E2281: Identifier1 requires definition of Identifier2 as a


pointer type (C++)
To use Identifier1, there needs to be a definition for Identifier2, which is a type.

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
}

3.1.2.535 E2289: __published or __automated sections only


supported for Delphi classes (C++)
3
The compiler needs to generate a special kind of vtable for classes containing __published and __automated sections.
Therefore, these sections are only supported for Delphi style classes.

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 };
};

3.1.2.536 E2298: Cannot generate 'function' from template function


'template' (C++)
A call to a template function was found, but a matching template function cannot be generated from the function template.

3.1.2.537 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 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.

Example
typedef my_class<int> mci;
typedef void (__closure * func) (const mci& object);

3.1.2.538 E2307: Type 'type' is not a defined class with virtual


functions (C++)
A dynamic_cast was used with a pointer to a class type that is either undefined, or doesn't have any virtual member functions.

3.1.2.539 E2315: 'Member' is not a member of 'class', because the


type is not yet defined (C++)
The member is being referenced while the class has not been fully defined yet. This can happen if you forward declare class X,
declare a pointer variable to X, and reference a member through that pointer; for example:
class X;
X * oneX;
int test() { return oneX->i; }

3.1.2.540 E2318: 'type' is not a polymorphic class type (C++)


3 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

354
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.541 E2323: Illegal number suffix (C++)


A numeric literal is followed by a suffix that is not recognized by the compiler.

Example
int i = 1234i15; // Error: no i15 suffix
int j = 1234i16; // OK

3.1.2.542 E2326: Use __declspec(spec1[, spec2]) to combine


multiple __declspecs (C++)
When you want to use several __declspec modifiers, the compiler will complain if you don't combine them into one __declspec.
For example:
int __declspec(__import) __declspec(delphiclass) X
will give an error. Use the following instead:
int __declspec(__import, delphiclass) X

3.1.2.543 E2328: Classes with properties cannot be copied by value


(C++)
This error occurs if you attempt to use the default assignment operator. For example, the following code generates this error
given two labels on a form:
*Label1->Font = *Label2->Font;

3.1.2.544 E2331: Number of allowable option contexts exceeded


(C++)
You have interspersed too many source-code option changes (using #pragma option) between template declarations. For
example:
#pragma option -x
template<class T> class foo1 { };
#pragma option -a3
template<class T> class foo2 { };
#pragma option -b
template<class T> class foo3 { };
#pragma option -k-
You need to break your source code into smaller files.

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.

This variable is never assigned a value and has no stack location.

355
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.546 E2476: Cannot overload 'function' (C++)


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.

3.1.2.547 E2346: 'x' access specifier of property 'property' must be a


member function (C++)
Only member functions or data members are allowed in access specifications of properties.

Example
int GlobalGetter(void)
{
return 0;
}
struct pbase
{
intMemberGetter(void) {return 1;}
int __property ip1 = { read = GlobalGetter }; // Error
int __property ip2 = { read = MemberGetter }; // OK
};

3.1.2.548 E2347: Parameter mismatch in access specifier 'specifier'


of property 'property' (C++)
The parameters of the member function used to access a property don't match the expected parameters.

Example
structpbase
{
voidSetter1(void){}
voidSetter2(int){}
int __property ip1 = { write = Setter1 }; // Error
int __property ip2 = { write = Setter2 }; // OK
};

3.1.2.549 E2348: Storage specifier not allowed for array properties


(C++)
Array properties cannot have a storage specification.

3 Example
struct pbase
{
int __property ap[char *] =
{ stored = false }; // Error
};

356
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

3.1.2.550 E2351: Static data members not allowed in __published or


__automated sections (C++)
Only nonstatic data members and member functions are allowed in __published or __automated sections.

Example
struct__declspec(delphiclass) clxclass
{
__published:
static intstaticDataMember;// Error
};

3.1.2.551 E2353: Class 'classname' is abstract because of 'member =


0' (C++)
This message is issued immediately after the "Cannot create instance of abstract class 'classname' error message and is
intended to make it easier to figure out why a particular class is considered abstract by the compiler.

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'

3.1.2.552 E2359: Reference member 'member' initialized with a


non-reference parameter (C++)
3
An attempt has been made to bind a reference member to a constructor parameter. Since the parameter will cease to exist the
moment the constructor returns to its caller, this will not work correctly.

357
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.553 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 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.

3.1.2.554 E2370: Simple type name expected (C++)


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.

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
};

3.1.2.555 E2398: Template function argument 'argument' not used in


argument types (C++)
The given argument was not used in the argument list of the function.

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.

3.1.2.556 E2419: Error while instantiating template 'template' (C++)


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.
3

3.1.2.557 E2424: Template class nesting too deep: 'class' (C++)


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

358
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

makes it easy to spot the recursion.

This error message is always followed by the fatal error "Out of memory".

3.1.2.558 E2457: Delphi style classes must be caught by reference


(C++)
You can only catch a Delphi style object by pointer.

Example
void foo(TObject *p)
{
try
{
throw(p);
}
catch (TObject o) // Error
{
}
catch (TObject *op) // OK
{
}
}

3.1.2.559 E2458: Delphi classes have to be derived from Delphi


classes (C++)
You cannot derive a Delphi style class from a non-Delphi style class.

Example
struct base// base not a Delphi style class
{
intbasemem;
};
struct __declspec(delphiclass) derived : base // or
{
intderivedmem;
};

3.1.2.560 E2459: Delphi style classes must be constructed using


operator new (C++)
Delphi style classes cannot be statically defined. They have to be constructed on the heap.

Example
voidfoo(void) 3
{
Tobject o1; // Error;
Tobject *o2 = new TObject();
}

359
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.561 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 exception handling (compiler option -x-) when
compiling your source code.

3.1.2.562 E2463: 'base' is an indirect virtual base class of 'class'


(C++)
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.

3.1.2.563 Null pointer assignment (C++)


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 computer up in
the large, compact, and huge memory models).

You can use the integrated debugger to track down null pointers.

3.1.2.564 E2268: Call to undefined function 'function' (C++)


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.

3.1.2.565 E2375: Assembler stack overflow (C++)


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.

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.

3.1.2.567 <name> is not a valid identifier (C++)


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.

3.1.2.568 Example for "Temporary used ..." error messages (C++)


In this example, function f requires a reference to an int, and c is a char:
f(int&);
char c;
f(c);
Instead of calling f with the address of c, the compiler generates code equivalent to the C++ source code:
int X = c, f(X);

3.1.2.569 Application is running (C++)


The application you tried to run is already running.

For Windows, make sure the message loop of the program has properly terminated.
PostQuitMessage(0);

3.1.2.570 Printf/Scanf floating-point formats not linked (C++)


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 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:

• 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

3.1.2.571 W8000: Ambiguous operators need parentheses (C++)


(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.

3.1.2.572 W8060: Possibly incorrect assignment (C++)


(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


if (a = b) ...
should be rewritten as
if ((a = b) != 0) ...

3.1.2.573 W8002: Restarting compile using assembly (C++)


(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

3.1.2.574 W8003: Unknown assembler instruction (C++)


(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.


3

3.1.2.575 W8052: Base initialization without a class name is now


obsolete (C++)
(Command-line option to suppress warning: -w-obi)

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++)

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
derived::derived(int i) : (i, 10) { ... }
New way
derived::derived(int i) : base(i, 10) { ... }

3.1.2.576 E2117: Bit fields must be signed or unsigned int (C++)


(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.

3.1.2.577 W8064: Call to function with no prototype (C++)


(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.

3.1.2.578 W8065: Call to function 'function' with no prototype (C++)


This message is given if the "Prototypes required" warning is enabled and you call function 'function' without first giving a
prototype for that function.

3.1.2.579 W8009: Constant is long (C++)


(Command-line option to display warning: -wcln)

The compiler encountered one of the following:

• a decimal constant greater than 32,767 or


• an octal, hexadecimal, or decimal constant greater than 65,535 without a letter l or L following it
The constant is treated as a long.

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' */
{
...
}
}

3.1.2.581 W8012: Comparing signed and unsigned values (C++)


(Command-line option to suppress warning: -w-csu)

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;
}

3.1.2.582 W8010: Continuation character \ found in // comment (C++)


(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 next
comment line with // also.

The warning can be disabled altogether with #pragma warn -com.

3.1.2.583 W8080: 'identifier' is declared but never used (C++)


(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.
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++)

3.1.2.584 W8014: Declaration ignored (C++)


(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

3.1.2.585 W8068: Constant out of range in comparison (C++)


(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

• cast the constant to unsigned--for example, (unsigned) 65535, or


• append a letter u or U to the constant--for example, 65535u.
Whenever this message is issued, the compiler still generates code to do the comparison.
If this code ends up always giving the same result (such as comparing a char expression to 4000), the code will still perform the
test.

3.1.2.586 W8016: Array size for 'delete' ignored (C++)


(Command-line option to suppress warning: -w-dsz)

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.

This warning lets older code compile.

3.1.2.587 W8082: Division by zero (C++)


(Command-line option to suppress warning: -w-zdi)

A divide or remainder expression had a literal zero as a divisor.

3
3.1.2.588 W8018: Assigning 'type' to 'enumeration' (C++)
(Command-line option to suppress warning: -w-eas)

Assigning an integer value to an enum type.

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

3.1.2.589 W8006: Initializing 'identifier' with 'identifier' (C++)


(Command-line option to suppress warning: -w-bei)

You're trying to initialize an enum variable to a different type.

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.

3.1.2.590 W8001: Superfluous & with function (C++)


(Command-line option to display warning: -wamp)

An address-of operator (&) is not needed with function name; any such operators are discarded.

3.1.2.591 W8020: 'identifier' is declared as both external and static


(C++)
(Command-line option to suppress warning: -w-ext)

This identifier appeared in a declaration that implicitly or explicitly marked it as global or external, and also in a static declaration.

The identifier is taken as static.

You should review all declarations for this identifier.

3.1.2.592 W8007: Hexadecimal value contains more than three digits


(C++)
(Command-line option to suppress warning = -w-big)

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.

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++)

3.1.2.594 W8022: 'function1' hides virtual function 'function2' (C++)


(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.

3.1.2.595 W8023: Array variable 'identifier' is near (C++)


(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 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.

3.1.2.596 W8061: Initialization is only partially bracketed (C++)


(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.

3.1.2.597 W8038: constant member 'identifier' is not initialized (C++)


(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.

3.1.2.598 W8071: Conversion may lose significant digits (C++) 3

(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.

367
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.599 W8043: Macro definition ignored (C++)


(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.

3.1.2.600 W8017: Redefinition of 'x' is not identical (C++)


(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.

3.1.2.601 W8079: Mixing pointers to different 'char' types (C++)


(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.)

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.

This is legal C, but almost always generates an error.

Possibly a return statement was omitted from the end of the function.

3.1.2.603 W8048: Use qualified name to access member type


'identifier' (C++)
(Command-line option to suppress warning: -w-nst)

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.

3.1.2.604 W8039: Constructor initializer list ignored (C++)


(Command-line option to suppress warning: -w-ncl)

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.

3.1.2.605 W8040: Function body ignored (C++)


(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.

3.1.2.606 W8042: Initializer for object 'x' ignored (C++)


(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.

3.1.2.607 W8044: #undef directive ignored (C++)


(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.

3.1.2.608 W8037: Non-const function 'function' called for const


object (C++)
(Command-line option to suppress warning = -w-ncf)

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.)

3.1.2.609 W8051: Non-volatile function 'function' called for volatile


object (C++)
(Command-line option to suppress warning: -w-nvf)

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

it is legal to call vcvar.f(), but not to call vcvar.g().

3.1.2.610 W8019: Code has no effect (C++)


(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


a + b;
has no effect on either variable.

The operation is unnecessary and probably indicates a bug.

3.1.2.611 W8057: Parameter 'parameter' is never used (C++)


(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.

3.1.2.612 W8070: Function should return a value (C++)


(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.

3.1.2.613 W8047: Declaration of static function function ignored


(C++)
(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
3 this utility.

3.1.2.614 W8041: Negating unsigned value (C++)


(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.

370
3.1 C++ Reference RAD Studio C++ Compiler Errors And Warnings (C++)

Example
#pragma warn +ngu
unsignedfoo(unsigned u)
{
return-u;
}

3.1.2.615 W8054: Style of function definition is now obsolete (C++)


(Command-line option to suppress warning = -w-ofp)

In C++, this old C style of function definition is illegal:


int func(p1, p2) int p1, p2; { /* ... */ }
This practice might not be allowed by other C++ compilers.

3.1.2.616 W8025: Ill-formed pragma (C++)


(Command-line option to suppress warning: -w-ill)

A pragma does not match one of the pragmas expected by the compiler.

3.1.2.617 W8063: Overloaded prefix operator 'operator' used as a


postfix operator (C++)
(Command-line option to suppress warning: -w-pre)

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.

3.1.2.618 W8015: Declare 'type' prior to use in prototype (C++)


(Command-line option to suppress warning: -w-dpu)

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.

3.1.2.619 W8069: Nonportable pointer conversion (C++)


(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.

3.1.2.620 W8066: Unreachable code (C++)


(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.

3.1.2.621 W8029: Temporary used for parameter '???' (C++)


(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:


f(int &amp);
char c;
f(c);
Instead of calling f with the address of c, the compiler generates code equivalent to the C++ source code:
int X = c, f(X);

3.1.2.622 W8031: Temporary used for parameter 'parameter' OR


W8029 Temporary used for parameter 'number' OR W8030
3
Temporary used for parameter 'parameter' in call to 'function' OR
W8032 Temporary used for parameter 'number' in call to 'function'
(C++)
(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.

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.

3.1.2.623 W8032: Temporary used for parameter 2 in call to '???'


(C++)
(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:


f(int &amp);
char c;
f(c);
Instead of calling f with the address of c, the compiler generates code equivalent to the C++ source code:
int X = c, f(X);

3.1.2.624 W8028: Temporary used to initialize 'identifier' (C++)


(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:


f(int&);
char c;
f(c);
Instead of calling f with the address of c, the compiler generates code equivalent to the C++ source code:
int X = c, f(X); 3

3.1.2.625 W8074: Structure passed by value (C++)


(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.

373
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

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.

3.1.2.626 W8011: Nonportable pointer comparison (C++)


(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.

3.1.2.627 W8075: Suspicious pointer conversion (C++)


(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:
#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;

3.1.2.628 W8059: Structure packing size has changed (C++)


(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.


3

3.1.2.629 W8045: No declaration for function 'function' (C++)


(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

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.

3.1.2.630 W8073: Undefined structure 'structure' (C++)


(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.

3.1.2.631 W8013: Possible use of 'identifier' before definition (C++)


(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.

3.1.2.632 W8004: 'identifier' is assigned a value that is never used


(C++)
(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.

3.1.2.633 W8081: Void functions may not return a value (C++)


(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. 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

3.1.2.634 W8078: Throw expression violates exception specification


(C++)
(Command-line option to suppress warning: -w-thr)

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:


int foo() throw(char*) // I promise to only throw char*s
{
throw 5; // Oops, I threw an integer
return 0;
}

3.1.2.635 W8021: Handler for 'type1' hidden by previous handler for


'type2' (C++)
(Command-line option to suppress warning: -w-hch)

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.

3.1.2.636 W8056: Integer arithmetic overflow (C++)


The compiler detected an overflow condition in an integer math expression.

For example:
int X = 0xFFFF * 0xFFFF;

3.1.2.637 W8035: User-defined message (C++)


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.

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++)

3.1.2.639 W8026: Functions with exception specifications are not


expanded inline (C++)
Also:Functions taking class by value arguments are not expanded inline

(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.1.2.640 W8058: Cannot create pre-compiled header: 'reason' (C++)


(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 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).

3.1.2.641 W8046: Pragma option pop with no matching option push


(C++)
The compiler encountered a #pragma option pop before a previous #pragma option push, or in the case of nesting, there are
more occurrences of #pragma option pop than of #pragma option push.

3.1.2.642 W8050: No type OBJ file present; disabling external types


option. (C++) 3
(Command-line option to suppress warning: -w-nto)

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

3.1.2.643 W8027: Functions containing 'statement' are not expanded


inline (C++)
(Command-line option to suppress warning: -w-inl)

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:

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.

For local destructors

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++)

3.1.2.645 W8053: 'ident' is obsolete (C++)


(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:


#ifdef __cplusplus
extern "C" {
#endif
void my_func(void);
#ifdef __cplusplus
}
#endif
#pragma obsolete my_func
main()
{
my_func(); // Generates warning about obsolete function
}

3.1.2.646 W8103: Path 'path' and filename 'filename' exceed


maximum size of 'n' (C++)
(Command-line option to display warning: -wstv)

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.

3.1.2.647 W8062: Previous options and warnings not restored (C++)


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 option push than of #pragma option pop.

3.1.2.648 W8055: Possible overflow in shift operation (C++)


The compiler detects cases where the number of bits shifted over is larger than the number of bits in the affected variable; for
example:
char c; c >> 16;

3.1.2.649 W8072: Suspicious pointer arithmetic (C++)


3
This message indicates an unintended side effect to the pointer arithmetic (or array indexing) found in an expression.

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.

3.1.2.650 W8033: Conversion to 'type' will fail for members of virtual


base 'class' (C++)
(Command-line option to suppress warning: -w-mpc)

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.

3.1.2.651 W8034: Maximum precision used for member pointer type


'type' (C++)
(Command-line option to suppress warning: -w-mpd)

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.

3.1.2.652 E2537: Cannot create instance of abstract class (C++)


This class is an abstract class, which you cannot instantiate.

3.1.2.653 E2018: Cannot catch 'identifier' -- ambiguous base class


'identifier' (C++)
It is not legal to catch a class that contains more than one copy of a (non-virtual) base class. However, you can catch the
exception as a more derived type. For example:
struct awkward : std::runtime_error, std::logic_error {};

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++)

3.1.2.654 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.

3.1.2.655 E2538: Static assert failed: '%s' (C++)


See Static Assertions ( see page 498) for details about how to use static_assert., which is one of the C++0x features.

3.1.2.656 E2548: ... was unexpected; expression is not a variadic


template pattern (C++)
This message pertains to the expected syntax of variadic templates.

3.1.2.657 E2543: Combination of options 'options' is not permitted


(C++)
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.

3.1.2.658 E2549: Operand is not a parameter pack (C++)


A parameter pack is required in the indicated location. This message pertains to variadic templates.

3.1.2.659 E2544: Function exception specifications do not match


(C++)
The throw specifications on two function declaration/definitions which refer to the same function do not agree. Rewrite the
function exception specifications to match.

3.1.2.660 E2536: Incomplete type cannot be part of a exception


declaration (C++) 3
This error occurs when an incomplete type is used in exception declaration. From 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.

381
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.661 E2535: Incomplete type cannot be part of a throw


specification (C++)
This error occurs when an incomplete type is used in a throw specification. From 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).

3.1.2.662 E2532: Constant in new expression requires an initializer


(C++)
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.

3.1.2.663 E2541: Attribute '%s' cannot be set (C++)


This error occurs if the specified attribute cannot be applied to this entity.

3.1.2.664 E2545: Enum underlying type must be an integral (C++)


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).

3.1.2.665 E2546: Redeclaration of enum is not identical (C++)


This error occurs if:

• a re-declaration of an enum has a different underlying type


• a scoped enum is re-declared as an unscoped enum
• an unscoped enum is re-declared as a scoped enum
For more information, see Strongly Typed Enums ( see page 498).

3 3.1.2.666 E2533: Parameter mismatch (wanted typename) (C++)


This error occurs when a parameter passed to a type trait function is not the correct type.

3.1.2.667 E2534: Integral constant expression expected (C++)


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

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.

3.1.2.668 E2531: Parameter is an incomplete type (C++)


This error occurs when an incomplete type is passed into a type trait function that does not accept incomplete type parameters.
For example:
class A;
void foo()
{
__is_abstract(A); // error
}

3.1.2.669 E2539: Constant expression expected (C++)


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).

3.1.2.670 E2547: ... expected (C++)


An ellipsis (...) is expected in the location indicated.

3.1.2.671 E2540: String literal expected (C++)


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).

3.1.2.672 E2552: This feature is not (yet) supported (C++)


Support might be added in a coming release.

3.1.2.673 E2542: '%s' is marked 'final' and cannot be overriden (C++)


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. 3

3.1.2.674 E2553: %s mismatch in redeclaration of '%s' (C++)


Attributes specified on a declaration have to be a subset of attributes specified on a definition.

383
C++ Compiler Errors And Warnings (C++) RAD Studio 3.1 C++ Reference

3.1.2.675 E2551: Return statement not allowed in __finally block


(C++)
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).

3.1.2.676 W8104: Local Static with constructor dangerous for


multi-threaded apps (C++)
(Command-line option to suppress warning: -w-mls)

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.

3.1.2.677 W8106: %s are deprecated (C++)


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.

3.1.2.678 W8110: Duplicate '%s' attribute directive ignored (C++)


(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.

3.1.2.679 W8108: Constant in new expression requires an initializer


(C++)
(Command-line option to suppress warning: -w-nci)

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.

3.1.2.680 W8113: Inline function was declared with 'extern template'


3
(C++)
(Command-line option to suppress warning: -w-iex)

'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

3.1.2.681 W8109: Parameter '%s' is a dependent type (C++)


(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.

3.1.2.682 W8105: Reference/Constant member 'identifier' in class


without constructors (C++)
(Command-line option to suppress warning: -w-mnc)

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.

3.1.2.683 W8107: Type name expected (C++)


(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.

3.1.2.684 W8112: Unresolved dependencies in expression (C++)


(Command-line option to suppress warning: -w-dex)

This warning is generated if dependencies in the expression cannot be resolved.

3.1.3 C++ Language Guide


This sections contains C++ language topics.

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.

3.1.3.1 C++ Specifics


This section contains C++ Specific 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:

• Data declarations (of any type, including enumerations, bit


fields and other classes)
• Nested type declarations
• Nested type definitions
• Template declarations
• Template definitions
• Function declarations
• 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.
Inline Functions ( see page 391) This section contains Inline Function topics.
Class Name Scope ( see page 393) The scope of a class name is local. There are some special requirements if the
class name appears more than once in the same scope. Class name scope
starts at the point of declaration and ends with the enclosing block. A class name
hides any class, object, enumerator, or function with the same name in the
enclosing scope. If a class name is declared in a scope containing the
declaration of an object, function, or enumerator of the same name, the class can
be referred to only by using the elaborated type specifier. This means that the
class key, class... more ( see page 393)
The Keyword This ( see page 394) This section contains Keyword this topics.
Class Names ( see page 396) class-name is any identifier unique within its scope. With structures, classes,
and unions, class-name can be omitted. See Untagged structures and typedefs
for discussion of untagged structures.
Member Scope ( see page 396) This section contains Member Scope topics.
Class Objects ( see page 402) Class objects can be assigned (unless copying has been restricted), passed as
arguments to functions, returned by functions (with some exceptions), and so on.
Other operations on class objects and members can be user-defined in many
ways, including definition of member and friend functions and the redefinition of
standard functions and operators when used with objects of a certain class.
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... more ( see page 402)
Virtual Base Classes ( see page 403) This section contains Virtual Base Class topics.
Class Types ( see page 404) The declaration creates a unique type, class type class-name. This lets you
declare further class objects (or instances) of this type, and objects derived from
this type (such as pointers to, references to, arrays of class-name, and so on):
Member Functions ( see page 405) A function declared without the friend specifier is known as a member function of
the class. Functions declared with the friend modifier are called friend functions.
Member functions are often referred to as methods in Delphi documentation.
The same name can be used to denote more than one function, provided they
differ in argument type or number of arguments.
VCL Class Declarations ( see page 405) Syntax 3
Class Methods ( see page 406) In C++Builder, a class method is a method that can be invoked on a class
name, as well as on an instance of that class. In contrast, object methods can be
invoked only on objects -- instances of a class.
Static Properties ( see page 410) Static properties have been implemented in C++Builder 2009 to enhance
compatibility with the Delphi language

3.1.3.1.1.1 C++ Classes


C++ classes offer extensions to the predefined type system. Each class type represents a unique set of objects and the

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.

A simplified, “first-look” syntax for class declarations is

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 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)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.2 Friends Of Classes


3 This section contains Friends Of Class topics.

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)

3.1.3.1.1.2.1 Friends Of Classes


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 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.

It is also possible for an individual member function of class X to be a friend of class Y:


class X {
.
.
.
void 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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes

3.1.3.1.1.3 Class Member List


The optional member-list is a sequence including, but not exclusive to:

• 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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.4 Inline Functions


This section contains Inline Function topics.

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)

3.1.3.1.1.4.1 Inline Functions


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 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

char* func(void) { return i; } // inline by default


char* i;
};
is equivalent to:
inline char* X::func(void) { return i; }
func is defined outside the class with an explicit inline specifier. The value i returned by func is the char* i of class X (see
Member scope).

Inline functions and exceptions

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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.5 Class Name Scope


The scope of a class name is local. There are some special requirements if the class name appears more than once in the same
scope. Class name scope starts at the point of declaration and ends with the enclosing block. A class name hides any class,
object, enumerator, or function with the same name in the enclosing scope. If a class name is declared in a scope containing the
declaration of an object, function, or enumerator of the same name, the class can be referred to only by using the elaborated
type specifier. This means that the class key, class, struct, or union, must be used with the class name. For example,
struct S { ... };
int S(struct S *Sptr);
void func(void) {
S t; // ILLEGAL declaration: no class key and function S in scope
struct S s; // OK: elaborated with class key
S(&s); // OK: this is a function call
}
C++ also allows a forward class declaration:
class X; // no members, yet!
Forward declarations permit certain references to class name X (usually references to pointers to class objects) before the class
has been fully defined. See Structure member declarations for more information. Of course, you must make a complete class
declaration with members before you can define and use objects of that class. 3
See also the syntax for forward declarations of VCL classes.

See Also
C++ Classes ( see page 387)

Class Types ( see page 404)

Class Objects ( see page 402)

393
C++ Language Guide RAD Studio 3.1 C++ Reference

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.6 The Keyword This


This section contains Keyword this topics.

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)

3.1.3.1.1.6.1 Static Members


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 operators. For example, y.x and yptr->x, where y is an object
of class X and yptr is a pointer to an object of class X, although the expressions y and yptr are not evaluated. In particular, a
static member function can be called with or without the special member function syntax:
class X {
int member_int;
public:
static void func(int i, X* ptr);
};
void g(void)
3 {
X obj;
func(1, &obj); // error unless there is a global func()
// defined elsewhere
X::func(1, &obj); // calls the static func() in X
// OK for static functions only
obj.func(1, &obj); // so does this (OK for static and
// nonstatic functions)
}
Because static member functions can be called with no particular object in mind, they don’t have a this pointer, and therefore

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

• Reduce the number of visible global names


• Make obvious which static objects logically belong to which class
• Permit access control to their names
See Also
C++ Classes ( see page 387)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394) 3


Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

395
C++ Language Guide RAD Studio 3.1 C++ Reference

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.7 Class Names


class-name is any identifier unique within its scope. With structures, classes, and unions, class-name can be omitted. See
Untagged structures and typedefs for discussion of untagged structures.

See Also
C++ Classes ( see page 387)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.8 Member Scope


This section contains Member Scope topics.

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:

• public: The member can be used by any function.


3
• private: The member can be used only by member
functions and friends of the class it’s declared in.
• protected: Same as for private. Additionally, the member
can be used by member functions and friends of classes
derived from the declared class, but only in... more ( see
page 399)

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)

3.1.3.1.1.8.1 Base And Derived Class Access


When you declare a derived class D, you list the base classes B1, B2, ... in a comma-delimited base-list:
class-key D : base-list { <member-list> }
D inherits all the members of these base classes. (Redefined base class members are inherited and can be accessed using
scope overrides, if needed.) D can use only the public and protected members of its base classes. But, what will be the access
attributes of the inherited members as viewed by D? D might want to use a public member from a base class, but make it
private as far as outside functions are concerned. The solution is to use access specifiers in the base-list.

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.

The default is private if D is a class declaration, and public if D is a struct declaration.

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 function Xfunc() is in X, which is derived from private B, so it has access to

• 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)

Class Types ( see page 404)


3 Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

398
3.1 C++ Reference RAD Studio C++ Language Guide

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.8.2 Member Access Control


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:

• public: The member can be used by any function.


• private: The member can be used only by member functions and friends of the class it’s declared in.
• protected: Same as for private. Additionally, the member can be used by member functions and friends of classes derived
from the declared class, but only in objects of the derived type. (Derived classes are explained in Base and derived class
access.)
Note: Friend function declarations are not affected by access specifiers (see Friends of classes for more information).
Members of a class are private by default, so you need explicit public or protected access specifiers to override the default.
Members of a struct are public by default, but you can override this with the private or protected access specifier.
Members of a union are public by default; this cannot be changed. All three access specifiers are illegal with union members.
A default or overriding access modifier remains effective for all subsequent member declarations until a different access
modifier is encountered. For example,
class X {
int i; // X::i is private by default
char ch; // so is X::ch
public:
int j; // next two are public
int k;
protected:
int l; // X::l is protected
};
struct Y {
int i; // Y::i is public by default
private:
int j; // Y::j is private
public:
int k; // Y::k is public
};
union Z {
int i; // public by default; no other choice
double d;
}; 3
Note: The access specifiers can be listed and grouped in any convenient sequence. You can save typing effort by declaring all
the private members together, and so on.

See Also
C++ Classes ( see page 387)

Class Types ( see page 404)

399
C++ Language Guide RAD Studio 3.1 C++ Reference

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.8.3 Member Scope


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, 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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.8.4 Nested Types


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 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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.9 Class Objects


Class objects can be assigned (unless copying has been restricted), passed as arguments to functions, returned by functions
(with some exceptions), and so on. Other operations on class objects and members can be user-defined in many ways, including
definition of member and friend functions and the redefinition of standard functions and operators when used with objects of a
certain class.

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)

Class Types ( see page 404)

Class Scope ( see page 431)

402
3.1 C++ Reference RAD Studio C++ Language Guide

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.10 Virtual Base Classes


This section contains Virtual Base Class topics.

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:

3.1.3.1.1.10.1 Virtual Base Classes


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:
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

constructed. For example, this code


class X : public Y , virtual public Z
X one;
produces this order:
Z(); // virtual base class initialization
Y(); // non-virtual base class
X(); // derived class
See Also
C++ Classes ( see page 387)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes

Friends Of Classes ( see page 389)

3.1.3.1.1.11 Class Types


The declaration creates a unique type, class type class-name. This lets you declare further class objects (or instances) of this
type, and objects derived from this type (such as pointers to, references to, arrays of class-name, and so on):
class X { ... };
X x, &xr, *xptr, xarray[10];
/* four objects: type X, reference to X, pointer to X and array of X */
struct Y { ... };
Y y, &yr, *yptr, yarray[10];
// C would have
// struct Y y, *yptr, yarray[10];
union Z { ... };
Z z, &zr, *zptr, zarray[10];
3 // C would have
// union Z z, *zptr, zarray[10];
Note the difference between C and C++ structure and union declarations: The keywords struct and union are essential in C, but
in C++, they are needed only when the class names, Y and Z, are hidden (see Class name scope)

See Also
C++ Classes ( see page 387)

Class Scope ( see page 431)

404
3.1 C++ Reference RAD Studio C++ Language Guide

Class Objects ( see page 402)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.12 Member Functions


A function declared without the friend specifier is known as a member function of the class. Functions declared with the friend
modifier are called friend functions.

Member functions are often referred to as methods in Delphi documentation.

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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Objects ( see page 402)

Class Member List ( see page 390)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397) 3


Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.13 VCL Class Declarations


Syntax

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.

3.1.3.1.1.14 Class Methods


In C++Builder, a class method is a method that can be invoked on a class name, as well as on an instance of that class. In
contrast, object methods can be invoked only on objects -- instances of a class.

How Class Methods Work in Delphi


The Delphi language (Object Pascal) supports class methods and a metaclass as described in the Class Methods section in the
Delphi help topic Methods.

Here is a sample:
TTest = class;

// Declaring metaclass type


TTestClass = class of TTest;

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;

// Class getter and setter


class function GetCount: Integer;
class procedure SetCount(I: Integer);

// Virtual class getter and setter


class function GetStrProp: string; virtual;
class procedure SetStrProp(N: 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;

// Function that takes a class reference


function RegisterTestType(Cls: TTestClass): boolean;
Class Methods as Static Methods with Explicit TMetaClass* Parameter
Prior to C++Builder 2009, class methods were represented as static methods with an explicit metaclass parameter. A metaclass
is represented by a pointer to a TMetaClass instance or a TClass. This metaclass or class reference is obtained with the
__classid extension, which returns a TMetaClass* instance for a class name.

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;

class DELPHICLASS TTest;


class PASCALIMPLEMENTATION TTest : public System::TObject
{
typedef System::TObject inherited;
public:
// Class methods exposed as static methods with the 'hidden'
// class reference explicit as the first parameter.
static int __fastcall add(TMetaClass* vmt, int I, int J);
static UnicodeString __fastcall GetClsName(TMetaClass* vmt);

// Virtual class methods would be exposed as plain virtual methods with


// the hidden class reference explicit as the first parameter.
// This means that upon calling this method from C++, there would have
// to be two 'hidden' parameters passed in--which would not work.
virtual UnicodeString __fastcall GetClsNameVirt(TMetaClass* vmt);

// Non-virtual methods are feasible to work with. These two methods


// are typically overloaded with the first TMetaClass* parameter
// hardcoded to __classid(TTest).
static int __fastcall GetCount(TMetaClass* vmt);
static void __fastcall SetCount(TMetaClass* vmt, int I);

// 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);

// Delphi class static method would be plain C++ static.


static int __fastcall GetStaticCount();
static void __fastcall SetStaticCount(int I);
3
// Although the compiler allows these declarations,
// because TMetaClass* is required, you'll get an error
// from the C++ compiler upon attempting to access these
properties.
__property int Count = {read=GetCount, write=SetCount, nodefault};
__property UnicodeString StrProp = {read=GetStrProp, write=SetStrProp};};

extern PACKAGE bool __fastcall RegisterTestType(TMetaClass* Cls);

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;

class DELPHICLASS TTest;


class PASCALIMPLEMENTATION TTest : public System::TObject
{
typedef System::TObject inherited;

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();

// Virtual methods can be used.


__classmethod virtual UnicodeString __fastcall GetClsNameVirt();

// Methods can access class properties


__classmethod int __fastcall GetCount();
__classmethod void __fastcall SetCount(int I);
__classmethod virtual UnicodeString __fastcall GetStrProp();
__classmethod virtual void __fastcall SetStrProp(UnicodeString N);

// Class static methods still map to C++ static methods.


static int __fastcall GetstaticCount();
static void __fastcall SetstaticCount(int I);

// 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.

This implementation provides two capabilities:


3
• Class methods can be virtual.
• Class properties can be defined.

Dynamic Dispatch of Virtual Class Methods


If you have a class method defined with __classmethod for a class that is derived from another class, you can't dynamically
invoke the derived class's virtual method using a class name. However, you can invoke the proper method using an instance.

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();
};

class TDerived: TBase {


virtual __classmethod void cfunc();
virtual void vfunc();
};

// Regular virtual methods


TDerived d;
d.vfunc(); //calls TDerived::vfunc;

TBase* bp = new TDerived();


bp->vfunc(); //calls TDerived::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

Updating Your Code to Use __classmethod


If you have C++ code that implements class methods using the older style class methods with a Metaclass * parameter, you can
update your code to use the __classmethod syntax. Since the TMetaClass* parameter is now hidden, the signature and
mangling of such class methods are different. The following table illustrates how to update common C++ constructs using class
methods. It uses the add(int i, int j) method and the Count property from the __classmethod code sample above to illustrate the
changes you would make.

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)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.1.15 Static Properties


Static properties have been implemented in C++Builder 2009 to enhance compatibility with the Delphi language

Declaring Class Functions as Static


If property access functions (getters and setters) are declared as static, you can use the property directly from the class without
specifying an object. For example:
class TMyClass : TComponent {
static int x;
static int GetX() { return x; }
static void SetX( int i ) { x = i; }

__property int X = { read = GetX, write = SetX }


};

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)

Class Methods ( see page 406)

Class Types ( see page 404)

Class Scope ( see page 431)

Class Member List ( see page 390)

Member Functions ( see page 405)

The Keyword This ( see page 394)

Static Members ( see page 394)

Inline Functions ( see page 391)

Member Scope ( see page 400)

Nested Types ( see page 401)

Member Access Control ( see page 399)

Base And Derived Class Access ( see page 397)

Virtual Base Classes ( see page 403)

Friends Of Classes ( see page 389)

3.1.3.1.2 Class Templates Overview


This section contains Class Templates Overview topics.

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,

3.1.3.1.2.1 Using Angle Brackets In Templates


Be careful when using the right angle bracket character upon instantiation:
Buffer<char, (x > 100 ? 1024 : 64)> buf;
In the preceding example, without the parentheses around the second argument, the > between x and 100 would prematurely
close the template argument list.

3.1.3.1.2.2 Template Arguments


Multiple arguments are allowed as part of the class template declaration. Template arguments can also represent values in
addition to data types:
template<class T, int size = 64> class Buffer { ... };
Both non-type template arguments such as size and type arguments can have default values. The value supplied for a non-type
template argument must be a constant expression:
const int N = 128;
int i = 256;
Buffer<int, 2*N> b1;// OK
Buffer<float, i> b2;// Error: i is not constant
Since each instantiation of a template class is indeed a class, it receives its own copy of static members. Similarly, template
functions get their own copy of static local variables.

3.1.3.1.2.3 Class Templates


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.

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)

Eliminating Pointers In Templates ( see page 412)

Template Arguments ( see page 412)


3
3.1.3.1.2.4 Eliminating Pointers In Templates
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.
template <class T> aBase {

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.

3.1.3.1.2.5 Using Type-safe Generic Lists In Templates


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,
class GList
{
public:
void insert( void * );
void *peek();
.
.
.
};
are that it isn't type-safe and common solutions need repeated class definitions. Since there's no type checking on what gets
inserted, you have no way of knowing what results you'll get. You can solve the type-safe problem by writing a wrapper class:
class FooList : public GList {
public:
void insert( Foo *f ) { GList::insert( f ); }
Foo *peek() { return (Foo *)GList::peek(); }
.
.
.
};
This is type-safe. insert will only take arguments of type pointer-to-Foo or object-derived-from-Foo, so the underlying container
will only hold pointers that in fact point to something of type Foo. This means that the cast in FooList::peek() is always safe, and
you've created a true FooList. Now, to do the same thing for a BarList, a BazList, and so on, you need repeated separate class
definitions. To solve the problem of repeated class definitions and type-safety, you can once again use templates. See the
example for type-safe generic list class. The C++ Standard Template Library (STL) has a rich set of type-safe collection classes.

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.

3.1.3.1.3 Compiler Template Switches


3
This section contains Compiler Template Switch topics.

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:

• Those methods which were actually used


• Virtual methods of an instance
• All methods of explicitly instantiated classes
The advantage of this behavior is that it results in
significantly smaller object files, libraries and executable
files, depending on how heavily you use templates.
Optionally, you can use the ‘-Ja’ switch to generate all
methods.
You can also force all of the out-of-line methods of a
template instance to be generated by using the explicit
template instantiation syntax defined in the ISO/ANSI C++
Standard. The syntax is:
template class classname<template... more ( see page
414)

3.1.3.1.3.1 Template Compiler Switches


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 instances will be user-defined so that they
aren't generated from the template.

3.1.3.1.3.2 Template Generation Semantics


The C++ compiler generates the following methods for template instances:

• Those methods which were actually used


• Virtual methods of an instance

3 • All methods of explicitly instantiated classes


The advantage of this behavior is that it results in significantly smaller object files, libraries and executable files, depending on
how heavily you use templates.
Optionally, you can use the ‘-Ja’ switch to generate all methods.
You can also force all of the out-of-line methods of a template instance to be generated by using the explicit template
instantiation syntax defined in the ISO/ANSI C++ Standard. The syntax is:
template class classname<template parameter>;

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 ();

3.1.3.1.4 Constructors And Destructors


This section contains Constructor and Destructor topics.

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:

• They do not have return value declarations (not even


void).
• They cannot be inherited, though a derived class can call
the base class’s constructors and destructors.
• Constructors, like most C++ functions, can have default
arguments or use member... more ( see page 415)
Constructors ( see page 416) This section contains Constructor topics.
Destructors ( see page 422) This section contains Destructor topics.

3.1.3.1.4.1 Introduction To Constructors And Destructors


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:

• They do not have return value declarations (not even void).


• They cannot be inherited, though a derived class can call the base class’s constructors and destructors.
• Constructors, like most C++ functions, can have default arguments or use member initialization lists.
• Destructors can be virtual, but constructors cannot. (See Virtual destructors.)
• You can’t take their addresses.
int main (void)
{
.
.
. 3
void *ptr = base::base; // illegal
.
.
.
}
• Constructors and destructors can be generated by the compiler if they haven’t been explicitly defined; they are also invoked
on many occasions without explicit calls in your program. Any constructor or destructor generated by the compiler will be
public.

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:

3.1.3.1.4.2.1 Class Initialization


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 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.

Note: Base class constructors must be declared as either public

417
C++ Language Guide RAD Studio 3.1 C++ Reference

or protected to be called from a derived class.


class base1
{
int x;
public:
base1(int i) { x = i; }
};
class base2
{
int x;
public:
base2(int i) : x(i) {}
};
class top : public base1, public base2
{
int a, b;
public:
top(int i, int j) : base1(i*5), base2(j+i), a(i) { b = j;}
};
With this class hierarchy, a declaration of top one(1, 2) would result in the initialization of base1 with the value 5 and base2 with
the value 3. The methods of initialization can be intermixed.

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)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

3.1.3.1.4.2.2 Constructor Defaults


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.

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

X(); // class X constructor


};
A class X constructor cannot take X as an argument:
class X {
public:
X(X); // illegal
};
The parameters to the constructor can be of any type except that of the class it’s a member of. The constructor can accept a
reference to its own class as a parameter; when it does so, it is called the copy constructor. A constructor that accepts no
parameters is called the default constructor.

3.1.3.1.4.2.4 Order Of Calling Constructors


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,


class Y {...}
class X : public Y {...}
X one;
the constructors are called in this order:
Y(); // base class constructor
X(); // derived class constructor
For the case of multiple base classes,
class X : public Y, public Z
X one;
the constructors are called in the order of declaration:
Y(); // base class constructors come first
Z();
X();
Constructors for virtual base classes are invoked before any nonvirtual base classes. If the hierarchy contains multiple virtual
base classes, the virtual base class constructors are invoked in the order in which they were declared. Any nonvirtual bases are
then constructed before the derived class constructor is called.

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

base(); // virtual base class highest in hierarchy


// base is constructed only once
base2(); // nonvirtual base of virtual base level2
// must be called to construct level2
level2(); // virtual base class
base2(); // nonvirtual base of level1
level1(); // other nonvirtual base
toplevel();
If a class hierarchy contains multiple instances of a virtual base class, that base class is constructed only once. If, however, there
exist both virtual and nonvirtual instances of the base class, the class constructor is invoked a single time for all virtual instances
and then once for each nonvirtual occurrence of the base class.

Constructors for elements of an array are called in increasing order of the subscript.

See Also
Class Initialization ( see page 417)

Invoking Destructors ( see page 424)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

3.1.3.1.4.2.5 Overloading Constructors


Constructors can be overloaded, allowing objects to be created, depending on the values being used for initialization.
class X {
int integer_part;
double double_part;
public:
X(int i) { integer_part = i; }
X(double d) { double_part = d; }
};
int main()
{
X one(10); // invokes X::X(int) and sets integer_part to 10
X one(3.14); // invokes X::X(double) setting double_part to 3.14
return 0;
}
See Also
Class Initialization ( see page 417)

Invoking Destructors ( see page 424)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)


3
Virtual Destructors ( see page 424)

3.1.3.1.4.2.6 The Copy Constructor


A copy constructor for class X is one that can be called with a single argument of type X as follows:
X::X(X&)

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)

Class Initialization ( see page 417)

Invoking Destructors ( see page 424)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

Example Of Overloading Operators ( see page 439)

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:

• atexit() functions are executed in the order they were


inserted.
• #pragma exit functions are executed in the order of their
priority codes.
• Destructors for global variables are called.

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)

Invoking Destructors ( see page 424)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

3.1.3.1.4.3.2 Exit And Destructors


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.

See Also
Class Initialization ( see page 417)
3
Invoking Destructors ( see page 424)

Atexit ( see page 426)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

423
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.1.4.3.3 Invoking Destructors


A destructor is called implicitly when a variable goes out of its declared scope. 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).

See Also
Class Initialization ( see page 417)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

3.1.3.1.4.3.4 Virtual Destructors


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.
/* How virtual affects the order of destructor calls.
Without a virtual destructor in the base class, the derived
class destructor won't be called. */
#include <iostream>
class color {
public:
virtual ~color() { // Virtual destructor
std::cout << "color dtor\n";
}
};
class red : public color {
public:
~red() { // This destructor is also virtual
std::cout << "red dtor\n";
}
};
class brightred : public red {
public:
~brightred() { // This destructor is also virtual
std::cout << "brightred dtor\n";
}
};
int main()
3 {
color *palette[3];
palette[0] = new red;
palette[1] = new brightred;
palette[2] = new color;
// The destructors for red and color are called.
delete palette[0];
std::cout << std::endl;
// The destructors for bright red, red, and color are called.
delete palette[1];
std::cout << std::endl;

424
3.1 C++ Reference RAD Studio C++ Language Guide

// The destructor for color is called.


delete palette[2];
return 0;
}
Program Output:
red dtor
color dtor
brightred dtor
red dtor
color dtor
color dtor
However, if no destructors are declared as virtual, delete palette[0], delete palette[1], and delete palette[2] would all call only the
destructor for class color. This would incorrectly destruct the first two elements, which were actually of type red and brightred.

See Also
Class Initialization ( see page 417)

Invoking Destructors ( see page 424)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

3.1.3.1.4.3.5 abort And Destructors


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
#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)

Invoking Destructors ( see page 424)

Atexit ( see page 426)

Exit And Destructors ( see page 423)

Virtual Destructors ( see page 424)

3.1.3.1.4.3.6 atexit, #pragma exit, And Destructors


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:

• atexit() functions are executed in the order they were inserted.


• #pragma exit functions are executed in the order of their priority codes.
• Destructors for global variables are called.
See Also
Class Initialization ( see page 417)

Invoking Destructors ( see page 424)

Exit And Destructors ( see page 423)

abort And Destructors ( see page 425)

Virtual Destructors ( see page 424)

3.1.3.1.5 C++ namespaces


This section contains C++ name space topics.

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 ::.

• Explicit access qualification ( see page 428)


• Using directive ( see page 429)
• Using declaration ( see page 572)
3 Accessing namespaces in classes
You cannot use a using directive inside a class. However,
the using declarative is allowed and can be quite useful.
Anonymous namespaces ( see page 427) The C++ grammar allows you to define anonymous namespaces. To do this, you
use the keyword namespace with no identifier before the enclosing brace.
Defining A namespace ( see page 428) The grammar for defining a namespace is

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)

3.1.3.1.5.1 Declaring A namespace


An original namespace declaration should use an identifier that has not been previously used as a global identifier.
namespace alpha { /* ALPHA is the identifier of this namespace. */
/* your program declarations */
long double LD;
float f(float y) { return y; }
}
A namespace identifier must be known in all translation units where you intend to access its elements.

See Also
namespace Alias ( see page 429)

3.1.3.1.5.2 Accessing Elements Of A namespace


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 ::.

• Explicit access qualification ( see page 428)


• Using directive ( see page 429)
• Using declaration ( see page 572)
Accessing namespaces in classes
You cannot use a using directive inside a class. However, the using declarative is allowed and can be quite useful.
See Also
3
using Directive ( see page 429)

using (declaration) ( see page 572)

3.1.3.1.5.3 Anonymous namespaces


The C++ grammar allows you to define anonymous namespaces. To do this, you use the keyword namespace with no identifier
before the enclosing brace.

427
C++ Language Guide RAD Studio 3.1 C++ Reference

namespace { // Anonymous namespace


// Declarations
}
All anonymous, unnamed namespaces in global scope (that is, unnamed namespaces that are not nested) of the same
translation unit share the same namespace. This way you can make static declarations without using the static keyword.

Each identifier that is enclosed within an unnamed namespace is unique within the translation unit in which the unnamed
namespace is defined.

3.1.3.1.5.4 Defining A namespace


The grammar for defining a namespace is
original-namespace-name:
identifier
namespace-definition:
original-namespace-definition
extension-namespace-definition
unnamed-namespace-definition
Grammatically, there are three ways to define a namespace with the namespace keyword:
original-namespace-definition:
namespace identifier { namespace-body }
extension-namespace-definition:
namespace original-namespace-name { namespace-body }
unnamed-namespace-definition:
namespace { namespace-body }
The body is an optional sequence of declarations. The grammar is
namespace-body:
declaration-seq opt
See Also
Declaring A namespace ( see page 427)

Extending A namespace ( see page 428)

3.1.3.1.5.5 Explicit Access Qualification


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:
ALPHA::LD; // Access a variable
ALPHA::f; // Access a function
Explicit access qualification can always be used to resolve ambiguity. No matter which namespace (except anonymous
namespace) is being used in your subsystem, you can apply the scope resolution operator :: to access identifiers in any
namespace (including a namespace already being used in the local scope) or the global namespace. Therefore, any identifier in
the application can be accessed with sufficient qualification.

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.

Types cannot be defined in a cast.

3.1.3.1.5.6 Extending A namespace


Namespaces are discontinuous and open for additional development. If you redeclare a namespace, the effect is that you extend

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.

3.1.3.1.5.7 namespace Alias


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.
namespace BORLAND_SOFTWARE_CORPORATION {
/* namespace-body */
namespace NESTED_BORLAND_SOFTWARE_CORPORATION {
/* namespace-body */
}
}
// Alias namespace
namespace BI = BORLAND_SOFTWARE_CORPORATION;
// Use access qualifier to alias a nested namespace
namespace NBI = BORLAND_SOFTWARE_CORPORATION::NESTED_BORLAND_SOFTWARE_CORPORATION;

3.1.3.1.5.8 using Directive


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 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.

Warning: Do not use the using

directive in header files. You might accidentally break namespaces in client code.

See Also
Accessing Elements Of A namespace ( see page 427)

using (declaration) ( see page 572)


3
3.1.3.1.6 C++ Scope
This section contains C++ Scope topics.

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:

• 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... more ( see page 431)
Class Scope ( see page 431) The name M of a member of a class X has class scope “local to X”; it can be
used only in the following situations:

• 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)

3.1.3.1.6.1 C++ Scope


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.”
3 See Also
Class Scope ( see page 431)

Hiding ( see page 432)

C++ Scoping Rules Summary ( see page 431)

430
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.1.6.2 C++ Scoping Rules Summary


The following rules apply to all names, including typedef names and class names, provided that C++ allows such names in the
particular context discussed:

• 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)

Class Scope ( see page 431)

Hiding ( see page 432)

3.1.3.1.6.3 Class Scope


The name M of a member of a class X has class scope “local to X”; it can be used only in the following situations:

• 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)

Hiding ( see page 432)

C++ Scoping Rules Summary ( see page 431)

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)

Class Scope ( see page 431)

C++ Scoping Rules Summary ( see page 431)

3.1.3.1.7 Exporting And Importing Templates


This section contains Exporting And Importing Template topics.

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)

3.1.3.1.7.1 Exporting And Importing Templates


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 organized in three files. Using the
header file, code is generated in the dynamic link library.

1. Exportable/Importable Template Declarations


The header file contains all template class and template function declarations. An export/import version of the templates can be
instantiated by defining the appropriate macro at compile time.
2. Compiling Exportable Templates
3
Write the source code for a dynamic link library. When compiled, this library has reusable export code for templates.
3. Using ImportTemplates
Now you can write a calling function that uses templates. This executable file is linked to the dynamic link library. Only objects
that are not declared in the header file and which are instantiated in the main function cause the compiler to generate new
code. Code for a newly instantiated object is written into main.obj file.

432
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.1.8 Function Templates Overview


This section contains Function Templates Overview topics.

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:

3.1.3.1.8.1 Function Templates


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:


#define max(x,y) ((x > y) ? x : y)
However, using the #define circumvents the type-checking mechanism that makes C++ such an improvement over C. In fact,
this use of macros is almost obsolete in C++. Clearly, the intent of max(x, y) is to compare compatible types. Unfortunately, using
the macro allows a comparison between an int and a struct, which are incompatible.

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)

Implicit And Explicit Template Functions ( see page 434)

433
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.1.8.2 Implicit And Explicit Template Functions


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.
template<class T> T max(T a, T b){
return (a > b) ? a : b;
}
void f(int i, char c)
{
max(i, i); // calls max(int ,int )
max(c, c); // calls max(char,char)
max(i, c); // no match for max(int,char)
max(c, i); // no match for max(char,int)
}
This code results in the following error messages:
Could not find a match for 'max(int,char)' in function f(int,char)Could not find a match for
'max(char,int)' in function f(int,char)
Could not find a match for 'max(char,int)' in function f(int,char)
If the user explicitly declares a function, this function, on the other hand, will participate fully in overload resolution. See the
example of explicit function.

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.

3.1.3.1.8.3 Overriding A Template Function


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:
#include <string.h>
char *max(char *x, char *y){
return(strcmp(x,y) > 0) ? x : y;
}
If you call the function with string arguments, it's executed in place of the automatic template function. In this case, calling the
function avoided a meaningless comparison between two pointers.

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.

3 3.1.3.1.9 The new And delete Operators


This section contains new And delete Operator topics.

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.

• void operator delete(void *Type_ptr, [size_t... more ( see


page 436)
Overloading The Operator new ( see page 436) The global ::operator new() and ::operator new[]() can be overloaded. Each
overloaded instance must have a unique signature. Therefore, multiple instances
of a global allocation operator can coexist in a single program.
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.

• void * operator new(size_t Type_size); // For... more (


see page 436)
The delete Operator With Arrays ( see page 437) Arrays are deleted by operator delete[](). You must use the syntax delete [] expr
when deleting an array.
Operator new ( see page 437) By default, if there is no overloaded version of new, a request for dynamic
memory allocation always uses the global version of new, ::operator new(). A
request for array allocation calls ::operator new[](). With class objects of type
name, a specific operator called name::operator new() or name::operator
new[]() can be defined. When new is applied to class name objects it invokes the
appropriate name::operator new if it is present; otherwise, the global ::operator
new is used.
Only the operator new() function will accept an optional initializer. The array
allocator version, operator new[](), will not accept... more ( see page 437)
The Operator new With Arrays ( see page 437) When using the array form of operator new[](), the pointer returned points to the
first element of the array. When creating multidimensional arrays with new, all
array sizes must be supplied (although the leftmost dimension doesn't have to be
a compile-time constant):

3.1.3.1.9.1 Handling Errors For The New Operator 3


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) .

435
C++ Language Guide RAD Studio 3.1 C++ Reference

See Also
new ( see page 556)

3.1.3.1.9.2 Operator new Placement Syntax


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 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)

3.1.3.1.9.3 Overloading The Operator delete


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.

• void operator delete(void *Type_ptr, [size_t Type_size]); // For Non-array


• void operator delete[](size_t Type_ptr, [size_t Type_size]); // For arrays
See Also
The keyword delete ( see page 546)

3.1.3.1.9.4 Overloading The Operator new


The global ::operator new() and ::operator new[]() can be overloaded. Each overloaded instance must have a unique signature.
Therefore, multiple instances of a global allocation operator can coexist in a single program.

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

3.1.3.1.9.5 The delete Operator With Arrays


Arrays are deleted by operator delete[](). You must use the syntax delete [] expr when deleting an array.
char * p;
void func()
{
p = new char[10]; // allocate 10 chars
delete[] p; // delete 10 chars
}
Early C++ compilers required the array size to be named in the delete expression. In order to handle legacy code, the compiler
issues a warning and simply ignores any size that is specified. For example, if the preceding example reads delete[10] p and is
compiled, the warning is as follows:
Warning: Array size for 'delete' ignored in function func()
See Also
The keyword delete ( see page 546)

3.1.3.1.9.6 Operator new


By default, if there is no overloaded version of new, a request for dynamic memory allocation always uses the global version of
new, ::operator new(). A request for array allocation calls ::operator new[](). With class objects of type name, a specific
operator called name::operator new() or name::operator new[]() can be defined. When new is applied to class name objects it
invokes the appropriate name::operator new if it is present; otherwise, the global ::operator new is used.

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)

The keyword new ( see page 556)

3.1.3.1.9.7 The Operator new With Arrays


When using the array form of operator new[](), the pointer returned points to the first element of the array. When creating
multidimensional arrays with new, all array sizes must be supplied (although the leftmost dimension doesn't have to be a
compile-time constant):
mat_ptr = new int[3][10][12]; // OK
mat_ptr = new int[n][10][12]; // OK
mat_ptr = new int[3][][12]; // illegal 3
mat_ptr = new int[][10][12]; // illegal
Although the first array dimension can be a variable, all following dimensions must be constants.

See Also
The keyword new ( see page 556)

437
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.1.10 New-style Typecasting Overview


This section contains New-style Typecasting Overview topics.

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.

3.1.3.1.10.1 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.

Types cannot be defined in a cast.

See Also
Const_cast (typecast Operator) ( see page 539)

Dynamic_cast (typecast Operator) ( see page 547)

Reinterpret_cast (typecast Operator) ( see page 561)

static_cast (typecast Operator) ( see page 565)

3.1.3.1.11 Operator Overloading Overview


This section contains Operator Overloading Overview topics.

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:

3.1.3.1.11.1 How To Construct A Class Of Complex Vectors


This section contains How to Construct A Class Of Complex Vector topics.

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.... more ( see
page 439)

3.1.3.1.11.1.1 Example Of Overloading Operators


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

[0]=(0, 0) [1]=(1.1, 0) [2]=(2.2, 0) [3]=(33.3, 81)


The result of vector addition:
[0]=(0, 0) [1]=(2.2, 0) [2]=(4.4, 0) [3]=(36.6, 183.8)
The result of 10 * cvector2:
[0]=(0, 0) [1]=(11, 0) [2]=(22, 0) [3]=(333, 810)

3.1.3.1.11.2 Overloading Operators


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:


. .* :: ?:
The following preprocessing symbols cannot be overloaded.
# ##
The =, [ ], ( ), and -> operators can be overloaded only as nonstatic member functions. These operators cannot be overloaded
for enum types. Any attempt to overload a global version of these operators results in a compile-time error.

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)

Overloaded Operators And Inheritance ( see page 444)

Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Class Member Access Operators -> ( see page 443)

Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.12 Overloading Operator Functions Overview


This section contains Overloading Operator Functions Overview topics.

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.

• 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... more ( see page 445)

3.1.3.1.12.1 Overloading The Assignment operator =


The assignment operator=( ) can be overloaded by declaring a nonstatic member function. For example,
class String {
.
.
.
String& operator = (String& str);
.
.
.
String (String&);
~String();
}
This code, with suitable definitions of String::operator =(), allows string assignments str1 = str2 in the usual sense. Unlike the
other operator functions, the assignment operator function cannot be inherited by derived classes. If, for any class X, there is no
user-defined operator =, the operator = is defined by default as a member-by-member assignment of the members of class X:
X& X::operator = (const X& source)
{
// memberwise assignment
}
See Also
Example Of Overloading Operators ( see page 439)

Overloaded Operators And Inheritance ( see page 444)

Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Class Member Access Operators -> ( see page 443)
3
Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.12.2 Overloading Binary Operators


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

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)

Overloaded Operators And Inheritance ( see page 444)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Class Member Access Operators -> ( see page 443)

Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.12.3 Overloading The Class Member Access Operators ->


Syntax
postfix-expression -> primary-expression
Description

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.

The operator->() can only be overloaded as a nonstatic member function.

See Also
Example Of Overloading Operators ( see page 439)

Overloaded Operators And Inheritance ( see page 444)

Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.12.4 Overloading The Function Call Operator ( )


Syntax
postfix-expression ( <expression-list> )
Description

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.

A call X(arg1, arg2), where X is an object class X, is interpreted as X.operator()(arg1, arg2).

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)

Overloaded Operators And Inheritance ( see page 444)

Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Class Member Access Operators -> ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.12.5 Overloading Operator Functions


Operator functions can be called directly, although they are usually invoked indirectly by the use of the overload operator:
c3 = c1.operator + (c2); // same as c3 = c1 + c2
Apart from new and delete, which have their own rules, an operator function must either be a nonstatic member function or have
at least one argument of class type. The operator functions =, ( ), [ ] and -> must be nonstatic member functions.

Enumerations can have overloaded operators. However, the operator functions =, ( ), [ ], and -> cannot be overloaded for
enumerations.

See Also
Example Of Overloading Operators ( see page 439)

Overloaded Operators And Inheritance ( see page 444)

Overloading Binary Operators ( see page 442)

Overloading The Assignment Operator = ( see page 442)

Overloading The Class Member Access Operators -> ( see page 443)

Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.12.6 Overloaded Operators And Inheritance


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.

See Also
Example Of Overloading Operators ( see page 439)

3 Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Class Member Access Operators -> ( see page 443)

Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Subscript Operator [] ( see page 445)

444
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.1.12.7 Overloading The Subscript Operator []


Syntax
postfix-expression [ expression ]
Description

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).

The operator[]() can only be overloaded as a nonstatic member function.

See Also
Example Of Overloading Operators ( see page 439)

Overloaded Operators And Inheritance ( see page 444)

Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Function Call Operator ( ) ( see page 443)

Overloading The Class Member Access Operators -> ( see page 443)

3.1.3.1.12.8 Overloading Unary Operators


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.

• 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)

Overloaded Operators And Inheritance ( see page 444)


3
Overloading Binary Operators ( see page 442)

Overloading Operator Functions ( see page 444)

Overloading The Assignment Operator = ( see page 442)

Overloading The Class Member Access Operators -> ( see page 443)

Overloading The Function Call Operator ( ) ( see page 443)

445
C++ Language Guide RAD Studio 3.1 C++ Reference

Overloading The Subscript Operator [] ( see page 445)

3.1.3.1.13 Polymorphic Classes


This section contains Polymorphic Class topics.

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.

3.1.3.1.13.1 Abstract Classes


This section contains Abstract Class 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,

3.1.3.1.13.1.1 Abstract Classes


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,
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

For example, using the class shape previously outlined,


class circle : public shape {// circle derived from abstract class
int radius;// private
public:
void rotate(int) { }// virtual function defined: no action
// to rotate a circle
void draw(); // circle::draw must be defined somewhere
}
Member functions can be called from a constructor of an abstract class, but calling a pure virtual function directly or indirectly
from such a constructor provokes a runtime error.

See Also
Polymorphic Classes ( see page 447)

Virtual Functions ( see page 449)

Dynamic Functions ( see page 447)

3.1.3.1.13.2 Polymorphic Classes


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.

See Also
Virtual Functions ( see page 449)

Dynamic Functions ( see page 447)

Abstract Classes ( see page 446)

3.1.3.1.13.3 Virtual Functions


This section contains Virtual Function topics.

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)

Virtual Functions ( see page 449)

Dynamic Functions

Abstract Classes ( see page 446)

3.1.3.1.13.3.2 Virtual Functions


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.
virtual int funct1(void); // A virtual function declaration.
virtual int funct2(void) = 0; // A pure function declaration.
A function declaration cannot provide both a pure-specifier and a definition.

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:

• They can be member functions only.


• They can be declared a friend of another class.
• They cannot be a static member.
A virtual function does not need to be redefined in a derived class. You can supply one definition in the base class so that all
calls will access the base function.

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

from D, the use of virtual is redundant.

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)

Dynamic Functions ( see page 447)

Abstract Classes ( see page 446)

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:

3.1.3.1.14.1 Reference Arguments


The reference declarator can also be used to declare reference type parameters within a function:
void func1 (int i);
void func2 (int &ir); // ir is type "reference to int"
.
.
.
int sum = 3;
func1(sum); // sum passed by value
func2(sum); // sum passed by reference
The sum argument passed by reference can be changed directly by func2. On the other hand, func1 gets a copy of the sum
argument (passed by value), so sum itself cannot be altered by func1.

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.

Compare the three implementations of the function treble:

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 Referencing ( see page 452)

Simple References ( see page 453)

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)

Reference Arguments ( see page 451)

Reference/Dereference Operators ( see page 658)

3.1.3.1.14.3 Simple References


The reference declarator can be used to declare references outside functions:
int i = 0;
int &ir = i; // ir is an alias for i
ir = 2; // same effect as i = 2
This creates the lvalue ir as an alias for i, provided the initializer is the same type as the reference. Any operations on ir have
precisely the same effect as operations on i. For example, ir = 2 assigns 2 to i, and &ir returns the address of i.

See Also
Referencing ( see page 452)

Reference Arguments ( see page 451)

3.1.3.1.15 Run-time Type Identification (RTTI)


This section contains Run-time Type Identification (RTTI) topics.

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.

3.1.3.1.15.1 Runtime Type Identification (RTTI) Overview


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 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)

The Typeid Operator ( see page 454)

3.1.3.1.15.2 The Typeid Operator


This section contains Typeid Operator topics.

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

3.1.3.1.15.2.1 Runtime Type Identification And Destructors


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
class Alpha {
public:
virtual ~Alpha( ) { }
};
void func( Alpha *Aptr ) {
delete Aptr; // Error. Alpha is not a polymorphic class type
}

3.1.3.1.16 The Scope Resolution Operator


This section contains Scope Resolution Operator topics.

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.

3.1.3.1.16.1 Scope Resolution Operator ::


The scope access (or resolution) operator :: (two colons) lets you access a global (or file duration) member name even if it is
3 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.

3.1.3.1.17 Stricter C++ Compiler (C++Builder 2007)


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

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):

• 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...
more ( see page 455)
Stricter C++ Compiler: String Literals Are Now Constants ( see page 457) String literals are now considered to be of type 'const char[]' by default. This,
combined with the stricter qualification binding of const values and types, can
generate error messages in code that compiled before.
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:
Stricter C++ Compiler: Template Changes ( see page 457) The C++ compiler no longer allows an explicit template without the 'template <>'
prefix. Use the compiler switch -Vbe to allow this. The following example shows
this:
Stricter C++ Compiler: Function Overload Resolution ( see page 458) One of the areas where the C++Builder 2007 compiler differs the most from the
previous versions is in overload resolution, which includes the detection of
ambiguity. The compiler now better conforms to the rules in section 13.3 of the
2003 C++ ANSI Standard. Several constructs that were previously allowed might
now be reported as ambiguous or no match found, requiring that you modify
code to clarify its intent.
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... more ( see page 458)
Stricter C++ Compiler: Initialization and Conversion ( see page 459) The compiler now obeys the rules of 8.5.1 and 13.3.1 of the 2003 C++ ANSI
Standard for initialization and conversion:

• 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 3
to look for (possibly ambiguous) converting constructors. If
the chosen conversion function is a converting
constructor, the call initializes a temporary of the... more
( see page 459)

3.1.3.1.17.1 Stricter C++ Compiler: Binding of References and Qualifiers


There are many constructs that now generate error messages from the CodeGear C++ compiler included with C++Builder 2007

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);

int takesUnsignedPtr(unsigned long* psize) {

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 Func(WideString& wref);

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);

Here is an example of trying to bind a const object to a non-const method:

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.

To remedy this, look for the VarToAnsiStr method:


AnsiString VarToAnsiStr (Variant &V TFieldType DataType)
and change it to take a const Variant&, as in:
AnsiString VarToAnsiStr (const Variant &V, TFieldType DataType)
See Also
Stricter C++ Compiler (C++Builder 2007) ( see page 454)

String Literals Are Now Constants ( see page 457)

Template Changes ( see page 457)

Function Overload Resolution ( see page 458)

Initialization and Conversion ( see page 459)

3.1.3.1.17.2 Stricter C++ Compiler: String Literals Are Now Constants


String literals are now considered to be of type 'const char[]' by default. This, combined with the stricter qualification binding of
const values and types, can generate error messages in code that compiled before.

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)

Template Changes ( see page 457)

Function Overload Resolution ( see page 458)

Initialization and Conversion ( see page 459)


3
3.1.3.1.17.3 Stricter C++ Compiler: Template Changes
The C++ compiler no longer allows an explicit template without the 'template <>' prefix. Use the compiler switch -Vbe to allow
this. The following example shows this:
template <class>
class foo {
foo();

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
};

template <> void SP::foo(const S &) {} //OK


See Also
Stricter C++ Compiler (C++Builder 2007) ( see page 454)

Binding of References and Qualifiers ( see page 455)

String Literals Are Now Constants ( see page 457)

Function Overload Resolution ( see page 458)

Initialization and Conversion ( see page 459)

3.1.3.1.17.4 Stricter C++ Compiler: Function Overload Resolution


One of the areas where the C++Builder 2007 compiler differs the most from the previous versions is in overload resolution, which
includes the detection of ambiguity. The compiler now better conforms to the rules in section 13.3 of the 2003 C++ ANSI
Standard. Several constructs that were previously allowed might now be reported as ambiguous or no match found, requiring
that you modify code to clarify its intent.

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;}

3 The code above generates an error and a warning:


Error E2015 test.cpp 5: Ambiguity between 'std::abs(int) at C:\dev\tp\sc\include\math.h:208'
and 'std::abs(long double) at C:\dev\tp\sc\include\math.h:275' in function test(long)
Warning W8057 test.cpp 6: Parameter 'l' is never used in function test(long)
To fix this, cast to the type of the overload you want to invoke. For example:
#include <limits>bool test(long l) { return std::abs(static_cast<int>(l)) > 0;}

458
3.1 C++ Reference RAD Studio C++ Language Guide

See Also
Stricter C++ Compiler (C++Builder 2007) ( see page 454)

Binding of References and Qualifiers ( see page 455)

String Literals Are Now Constants ( see page 457)

Template Changes ( see page 457)

Initialization and Conversion ( see page 459)

3.1.3.1.17.5 Stricter C++ Compiler: Initialization and Conversion


The compiler now obeys the rules of 8.5.1 and 13.3.1 of the 2003 C++ ANSI Standard for initialization and conversion:

• 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 &)'

// copy initialization with dst=V src=G


// ==> user-defined conversion sequences are considered.
V v4 = g;
V v5 = G();
// Both of these statements now compile but previously got the error:
// Error E2015: Ambiguity between 'V::V(const A &)' and 'V::V(const V &)'

// copy initialization with dst=V src=V


// ==> converting constructors of V are considered.
V v6 = (V)g;
V v7 = V(g); 3
// Both of these statements compiled previously but now get the error:
// Error E2015: Ambiguity between 'V::V(const V &)' and 'V::V(const A &)'
Conversion via User-Defined Operators
The new C++Builder 2007 compiler often reports ambiguities for conversions that involve user-defined operators. An example is
shown below:
class AnsiString { public: bool operator ==(const AnsiString& other);
AnsiString(const wchar_t* src); };

459
C++ Language Guide RAD Studio 3.1 C++ Reference

class Variant { public: operator AnsiString() const;operator wchar_t*() const;


bool operator ==(const AnsiString& rhs) const { return static_cast<AnsiString>(*this) ==
rhs;}
C++Builder users might notice that the above is a stripped down version of the VCL AnsiString and Variant classes. Previous
versions of the compiler invoked the 'Variant' 'operator AnsiString() const' for 'static_cast<AnsiString>(*this)', while C++Builder
2007 uses 'conversion via constructor'. Since the Variant can be converted to multiple types for which there are AnsiString
constructors, the compiler generates an ambiguity error.

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.

Previous Construct Updated Construct Notes


AnsiString test(OleVariant v) { AnsiString AnsiString test(OleVariant v) { AnsiString ret Do not cast RHS when relying on
ret = (AnsiString) v; return ret; } = /*(AnsiString)*/ v; return ret; } conversion operator in an
assignment.
WideString test(OleVariant v) { WideString WideString test(OleVariant v) { WideString Use Copy Initialization instead of
w(v); return w; } w = v; return w; } the more direct constructor.

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)

Binding of References and Qualifiers ( see page 455)

String Literals Are Now Constants ( see page 457)

Template Changes ( see page 457)

Function Overload Resolution ( see page 458)

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)

3.1.3.1.18.1 Template Body Parsing


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.
template <class T> class X : T
{
Int j; // Error: Type name expected in template X<T>
};
Let's assume that Int hasn't yet been defined. This means that Int must be a member of the template argument T. But it also
might just be a typing error and should be int instead of Int. Because the compiler can't guess the right meaning it issues an
error message.

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)

Function Templates ( see page 433)

Class Templates ( see page 412) 3


Template Compiler Switches ( see page 414)

Template Generation Semantics ( see page 414)

Exporting And Importing Templates ( see page 432)

461
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.1.18.2 Using Templates


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)

3.1.3.1.19 C++0x Features (C++Builder 2009)


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.

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:

• Enumerators are in the scope of their enum.


• Enumerators and enums do not implicitly convert to int (as
do "plain" enumerators and enums).
• Enums and their enumerators can have a defined
underlying type.
Type Specifier decltype (C++0x) ( see page 499) The C++0x standard includes the decltype keyword and operator, which
represents the type of an expression. This feature is one of the C++0x features
added to C++Builder 2009.
Unicode Character Types and Literals (C++0x) ( see page 500) C++Builder 2009 implements new character types and character literals for
Unicode. These types are among the C++0x features added to C++Builder 2009.

3.1.3.1.19.1 alignof Operator (C++0x)


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:


alignof(type);
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. For instance, an alignment of 2 means that the type must begin on even memory addresses. 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)

Working Draft - Standard for Programming Language C++ (Sec. 5.3.6)

3.1.3.1.19.2 Type Trait Functions (C++0x)


This section contains Type Trait Functions help topics.

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

__alignment_of ( see page 473) Category


Type Trait Functions
Syntax:
unsigned int __alignment_of( typename T )
This function is not necessary, as alignof ( see page 531) is a proposed new
keyword.
__array_extent ( see page 473) Category
Type Trait Functions
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.
__array_rank ( see page 473) Category
Type Trait Functions
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..
__has_nothrow_assign ( see page 473) Category
Type Trait Functions
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).
Also true if copy assignment operator has an empty exception specification.
Ox interaction false if copy assignment is defined as deleted.
__has_nothrow_copy_constructor ( see page 474) Category
Type Trait Functions
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.
Error if T is an incomplete type.
True if __has_trivial_copy_constructor(T).
Ox interaction false if copy constructor is defined as deleted.
__has_nothrow_default_constructor ( see page 474) Category
Type Trait Functions
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.
Error if T is an incomplete type.
True if __has_trivial_default_constructor(T).
True if default constructor has an empty exception specification.
False (but well-formed) if a class type does not have a default constructor.
False if T is a reference type.
Ox interaction false if the default constructor is defined as deleted.

464
3.1 C++ Reference RAD Studio C++ Language Guide

__has_trivial_assign ( see page 475) Category


Type Trait Functions
Syntax
bool __has_trivial_assign (typename T )
Returns true if and only if T has a trivial copy assignment operator.
Error if T is an incomplete type.
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:

• a scalar type (or array thereof)


• a class type with a trivial copy assignment operator
According to Section 21.8 p11 of the Working Draft, a copy
assignment operator for class X is trivial if:
• It is... more ( see page 475)
__has_trivial_copy_constructor ( see page 475) Category
Type Trait Functions
Syntax
bool __has_trivial_copy_constructor ( typename T )
Returns true if and only if T has a trivial default constructor.
Error if T is an incomplete type.
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::

• a scalartype (or array thereof)


• a reference type (or array thereof)
• an array of class type with trivial destructor
• a class type with a trivial copy constructor (12.8)
According to Section 12.8... more ( see page 475)
__has_trivial_default_constructor ( see page 476) Category
Type Trait Functions
Syntax
bool __has_trivial_default_constructor (typename T )
Returns true if and only if T has a trivial default constructor.
Errorif T is an incomplete type.
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:

• 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... more ( see page 476)

465
C++ Language Guide RAD Studio 3.1 C++ Reference

__has_trivial_destructor ( see page 477) Category


Type Trait Functions
Syntax
bool __has_trivial_destructor (typename T )
Returns true if and only if T has a trivial destructor.
Errorif T is an incomplete type.
Note: Definition from 20.4.4.3 notes has a type T has a trivial destructor if T is
one of:

• a scalartype (or array thereof)


• a scalartype (or array thereof)
• an array of class type with a trivial destructor
• an array of class type with a trivial destructor
• a class type with a trivial destructor
According to Section 12.4, p 3 of the Working Draft, a
destructor for class X is trivial if:
• it... more ( see page 477)
__has_virtual_destructor ( see page 478) Category
Type Trait Functions
Syntax
bool __has_virtual_destructor (typename T )
Returns true if and only if T is a class type and the destructor is declared virtual.
Error if T is an incomplete type.
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.
__is_abstract ( see page 478) Category
Type Trait Functions
Syntax
bool __is_abstract( typename T )
Returns true if and only if T is an abstract class type.
Error if T is an incomplete type.
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.
__is_arithmetic ( see page 478) Category
Type Trait Functions
Syntax
bool __is_arithmetic ( typename T )
Returns __is_integral(T) || __is_floating_point(T).
__is_array ( see page 479) Category
Type Trait Functions
Syntax
bool __is_array( typename T )
Returns true if and only if T is an array type.
Note: False for decayed pointer-to-array and reference to array; true for
array-of-unknown bounds.
__is_base_of ( see page 479) Category
Type Trait Functions
Syntax
bool __is_base_of (typename Base, typename Derived)
Returns true if and only if Base is a base class of Derived.
3 Error if Derived is an incomplete type and Base is a class-type..
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.

466
3.1 C++ Reference RAD Studio C++ Language Guide

__is_class ( see page 479) Category


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.
Returns false for reference/pointer to class type.
Returns true for specialization of a class 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_complete_type (typename T ) ( see page 480) Category
Type Trait Functions
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.
__is_compound ( see page 480) Category
Type Trait Functions
Syntax
bool __is_compound( typename T )
Returns true if and only if T is a compound type..
A compound type is essentially one item from the following list:

• 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

__is_empty ( see page 481) Category


Type Trait Functions
Syntax
bool __is_empty( typename T )
Returns true if and only if T is an 'empty' type.
Error if T is an incomplete type
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:

• is a class type but not a union type.


• has no non-static data members other than bit-fields of
length 0
• has no virtual member functions
• has no virtual base classes
• has no base class which is not empty.
__is_enum ( see page 482) Category
Type Trait Functions
Usage: bool _is_enum ( typename T )
Returns true if and only if T is an enum type.
Returns true for the C++0x strongly typed enums as well.
Returns false for reference/pointer to enum type.
__is_floating_point ( see page 482) Category
Type Trait Functions
Syntax
bool __is_floating_point(typename T)
Returns true if and only if T is a (potentially cv-qualified) floating point type.
The standard set of floating point types is:

• 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

__is_integral ( see page 484) Category


Type Trait Functions
Syntax
bool __is_integral(typename T)
Returns True if and only if T is an (potentially cv-qualified) integral type.
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.
__is_lvalue_expr ( see page 484) Category
Type Trait Functions
Syntax
bool __is_lvalue_expr( typename T )
Returns true if and only if T is an lvalue expression.
__is_lvalue_reference ( see page 484) Category
Type Trait Functions
Syntax
bool __is_lvalue_reference( typename T )
Returns true if and only if T is an lvalue reference type.
Can be a reference to an object or function type.
__is_member_function_pointer ( see page 485) Category
Type Trait Functions
Syntax
bool __is_member_function_pointer( typename T )
Returns true if and only if T is a pointer-to-member-function type .
Returns false for a pointer-to-data member.
Returns false for a regular object pointer.
__is_member_object_pointer ( see page 485) Category
Type Trait Functions
Syntax
bool __is_member_object_pointer( typename T )
Returns true if and only if T is a pointer-to-data-member type.
Returns false for pointer-to-member-function.
Returns false for a regular object pointer.
__is_member_pointer ( see page 485) Category
Type Trait Functions
Syntax
bool __is_member_pointer( typename T )
Returns: __is_member_object_pointer(T) ||
__is_member_function_pointer(T).
__is_object ( see page 485) Category
Type Trait Functions
Syntax
bool __is_object( typename T)
Returns true if and only if T is an object type.
Defined in Section 3.9 p8 of the Working Draft, essentially:
!__is_reference(T) && !__is_function(T) && !__is_void(T).
__is_pod ( see page 486) Category
Type Trait Functions
Syntax
bool __is_pod( typename T )
Returns true if and only if T is a POD (plain ol' data) type.
Error if T is an incomplete type.
POD types are defined in Section 3.9 p10 of the Working Draft. 3
POD classes are defined in Section 9 p9 of the Working Draft.
Effectively __is_trivial_type(T) && is standard_layout(T)
__is_pointer ( see page 486) Category
Type Trait Functions
Syntax
bool __is_pointer( typename T )
Returns true if and only if T is a pointer type.
Can be an object pointer or a function pointer.
False for pointer-to-member.

469
C++ Language Guide RAD Studio 3.1 C++ Reference

__is_polymorphic ( see page 487) Category


Type Trait Functions
Syntax
bool __is_polymorphic( typename T )
Returns true if and only if T is a poiymorphic class type.
Error if T is an incomplete type.
Polymorphic classes are defined in Section 10.3 of the Working Draft.
"A class that declares or inherits a virtual function is called a polymorphic class."
__is_reference ( see page 487) Category
Type Trait Functions
Syntax
bool __is_reference( typename T )
Returns: __is_lvalue_reference(T) || __is_rvalue_reference(T).
__is_rvalue_expr ( see page 487) Category
Type Trait Functions
Syntax
bool __is_rvalue_expr( typename T )
Returns true if and only if T is an rvalue expression.
__is_rvalue_reference ( see page 488) Category
Type Trait Functions
Usage: bool __is_rvalue_reference( typename T )
Returns true if and only if T is an rvalue reference type.
Can be a reference to an object or function type, even though function type
rvalues make little sense beyond metaprogramming in the type system.
__is_same ( see page 488) Category
Type Trait Functions
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.
__is_scalar ( see page 488) Category
Type Trait Functions
Syntax
bool __is_scalar( typename T )
Returns true if and only if T is a scalar type.
Scalar type is defined in Section 3.9 p10 of the Working Draft, essentially:
__is_arithmetic( T ) || __is_enumeration(T) ||
__is_pointer(T) || __is_member_pointer(T)
Scalar types have a built in meaning for operator < as well as operator ==.
Therefore, __closure is not a scalar type.
__is_signed ( see page 489) Category
Type Trait Functions
Syntax
_bool __is_signed( typename T )
Returns true if and only if __is_arithmetic(T) and T recognizes values less
than zero.

470
3.1 C++ Reference RAD Studio C++ Language Guide

__is_standard_layout ( see page 489) Category


Type Trait Functions
Syntax
bool __is_standard_layout(typename T)
Returns true if and only if T is a standard layout type.
Error if T is an incomplete type.
Standard layout classes are defined in Section 9, p 6 of the Working Draft.
A standard layout type is:

• 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

__is_void ( see page 491) Category


Type Trait Functions
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.
__is_volatile ( see page 491) Category
Type Trait Functions
Syntax
bool __is_volatile( typename T )
Returns true if and only if T is a volatile-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.

3.1.3.1.19.2.1 Type Trait Functions Overview (C++0x)


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 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.

Differences Between Type Trait Functions and Other Intrinsic Functions


Type trait functions accept only named types, not arbitrary expressions (which would be accepted by typeid, sizeof, and
decltype). You can specify multiple arguments with a type trait function, but a comma-separated list is interpreted as an
application of the comma operator by typeid, sizeof, and decltype.

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.

Incomplete Types and Type Trait Functions


Many of the type trait functions do work with incomplete types. For example, after a class has been forward declared, the type
can be identified as a class, not a union, enum or fundamental type. The class can have references and pointers, and so forth.
Therefore, most type trait functions accept two special incomplete types: void and array-of-unknown-bound (of complete types).
For these two incomplete types, most type trait functions return False.

However, a few type functions require complete types. For example, a class declaration is not sufficient to know about bases or
triviality.

For convenience, the following type trait function is implemented in C++Builder:


3
__is_complete_type(T)
This type trait function is unique in that it might return different results at compile time depending on its location in the translation
unit. This phenomenon makes this type trait function ripe for ODR violations when used carelessly.

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)

Working Draft — Standard for Programming Language C++:


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.2 __alignment_of
Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 463)

3.1.3.1.19.2.3 __array_extent
Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.4 __array_rank
Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.5 __has_nothrow_assign
Category

473
C++ Language Guide RAD Studio 3.1 C++ Reference

Type Trait Functions

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).

Also true if copy assignment operator has an empty exception specification.

Ox interaction false if copy assignment is defined as deleted.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.6 __has_nothrow_copy_constructor
Category

Type Trait Functions

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.

Error if T is an incomplete type.

True if __has_trivial_copy_constructor(T).

Ox interaction false if copy constructor is defined as deleted.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.7 __has_nothrow_default_constructor
Category

Type Trait Functions

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.

3 Error if T is an incomplete type.

True if __has_trivial_default_constructor(T).

True if default constructor has an empty exception specification.

False (but well-formed) if a class type does not have a default constructor.

False if T is a reference type.

Ox interaction false if the default constructor is defined as deleted.

474
3.1 C++ Reference RAD Studio C++ Language Guide

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.8 __has_trivial_assign
Category

Type Trait Functions

Syntax
bool __has_trivial_assign (typename T )

Returns true if and only if T has a trivial copy assignment operator.

Error if T is an incomplete type.

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:

• a scalar type (or array thereof)


• a class type with a trivial copy assignment operator
According to Section 21.8 p11 of the Working Draft, a copy assignment operator for class X is trivial if:
• It is not user provided
• class X has no virtual functions
• class X has no virtual base classes
• each direct base class of X has a trivial copy assignment operator.
• for all the non-static data members of X that are of class type (or array thereof), each such class type has a trivial copy
assignment operator;
A copy assignment operator is not user provided if it is implicitly declared, or defined inline as = default;.
Ox interaction false if the copy assign operator is defined as deleted.
Ox interaction false if the copy assign operator is defined as deleted.
Ox interaction false if the default constructor is defined as deleted.
Ox interaction with default function definitions.
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft - Standard for Programming Language C++ - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.9 __has_trivial_copy_constructor 3
Category

Type Trait Functions

Syntax
bool __has_trivial_copy_constructor ( typename T )

Returns true if and only if T has a trivial default constructor.

475
C++ Language Guide RAD Studio 3.1 C++ Reference

Error if T is an incomplete type.

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::

• a scalartype (or array thereof)


• a reference type (or array thereof)
• an array of class type with trivial destructor
• a class type with a trivial copy constructor (12.8)
According to Section 12.8 p6 of the Working Draft:
A copy constructor for class X is trivial if:
• It is not user provided (see Section 8.4)
• class X has no virtual functions
• class X has no virtual base classes
• each direct base class of X has a trivial copy constructor.
• for all the non-static data members of X that are of class type (or array thereof), each such class type has a trivial copy
constructor;.
A copy constructor is not user provided if it is implicitly declared, or defined inline as = default;
Ox interaction false if the default constructor is defined as deleted.
Ox interactionwith default function definitions.
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft - Standard for Programming Language C++: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.10 __has_trivial_default_constructor
Category

Type Trait Functions

Syntax
bool __has_trivial_default_constructor (typename T )

Returns true if and only if T has a trivial default constructor.

Errorif T is an incomplete type.

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

• Its class has no virtual functions


• Its class has no virtual base classes
• Each direct base class of X has a trivial copy assignment operator.
• All the direct base classes of its class have trivial default constructors.
• For all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default
constructor.
A default consructor is not user provided if it is implicitly declared, or defined inline as = default;.
Ox interaction if the copy assign operator is defined as deleted.
Ox interaction false if the default constructor is defined as deleted.
Ox interaction with default function definitions.
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft - Standard for Programming Language C++ - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.11 __has_trivial_destructor
Category

Type Trait Functions

Syntax
bool __has_trivial_destructor (typename T )

Returns true if and only if T has a trivial destructor.

Errorif T is an incomplete type.

Note: Definition from 20.4.4.3 notes has a type T has a trivial destructor if T is one of:

• a scalartype (or array thereof)


• a scalartype (or array thereof)
• an array of class type with a trivial destructor
• an array of class type with a trivial destructor
• a class type with a trivial destructor
According to Section 12.4, p 3 of the Working Draft, a destructor for class X is trivial if:
• it is not user-provided
• class X has no virtual functions
• class X has no virtual base classes
• all of the direct base classes of its class have trivial destructors 3
• for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial
destructor.
A destructor is not user provided if it is implicitly declared, or defined inline as = default;
Ox interaction false if the destructor is defined as deleted.
Ox interaction with default function definitions.

477
C++ Language Guide RAD Studio 3.1 C++ Reference

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.12 __has_virtual_destructor
Category

Type Trait Functions

Syntax
bool __has_virtual_destructor (typename T )

Returns true if and only if T is a class type and the destructor is declared virtual.

Error if T is an incomplete type.

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.13 __is_abstract
Category

Type Trait Functions

Syntax
bool __is_abstract( typename T )

Returns true if and only if T is an abstract class type.

Error if T is an incomplete type.

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)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf
3
3.1.3.1.19.2.14 __is_arithmetic
Category

Type Trait Functions

Syntax
bool __is_arithmetic ( typename T )

478
3.1 C++ Reference RAD Studio C++ Language Guide

Returns __is_integral(T) || __is_floating_point(T).

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.15 __is_array
Category

Type Trait Functions

Syntax
bool __is_array( typename T )

Returns true if and only if T is an array type.

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.16 __is_base_of
Category

Type Trait Functions

Syntax
bool __is_base_of (typename Base, typename Derived)

Returns true if and only if Base is a base class of Derived.

Error if Derived is an incomplete type and Base is a class-type..

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)

Type Trait Functions Overview ( see page 472)

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

Returns false for reference/pointer to class type.

Returns true for specialization of a class 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.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.18 __is_complete_type (typename T )


Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.19 __is_compound
Category

Type Trait Functions

Syntax
bool __is_compound( typename T )

Returns true if and only if T is a compound type..

A compound type is essentially one item from the following list:

• 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)

Type Trait Functions Overview ( see page 472)

Working Draft - Standard for Programming Language C++ - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.20 __is_const
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.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.21 __is_convertible
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.

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();

To test() { return create<From>(); |


See Also
C++0x Features (C++Builder 2009) ( see page 462)
3
Type Trait Functions Overview ( see page 472)

Working Draft - Standard for Programming Language C++ - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.22 __is_empty
Category

Type Trait Functions

481
C++ Language Guide RAD Studio 3.1 C++ Reference

Syntax
bool __is_empty( typename T )

Returns true if and only if T is an 'empty' type.

Error if T is an incomplete type

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:

• is a class type but not a union type.


• has no non-static data members other than bit-fields of length 0
• has no virtual member functions
• has no virtual base classes
• has no base class which is not empty.
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.23 __is_enum
Category

Type Trait Functions

Usage: bool _is_enum ( typename T )

Returns true if and only if T is an enum type.

Returns true for the C++0x strongly typed enums as well.

Returns false for reference/pointer to enum type.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.24 __is_floating_point
Category

Type Trait Functions

3 Syntax
bool __is_floating_point(typename T)

Returns true if and only if T is a (potentially cv-qualified) floating point type.

The standard set of floating point types is:

• 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)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.25 __is_function
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.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions (C++0x) ( see page 472)

3.1.3.1.19.2.26 __is_fundamental
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.

Definition is essentially __is_arithmetic(T) || __is_void(T)

Alternative is a compound type, such as pointer, reference, enum, class or array.

See Also 3
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

483
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.1.19.2.27 __is_integral
Category

Type Trait Functions

Syntax
bool __is_integral(typename T)

Returns True if and only if T is an (potentially cv-qualified) integral type.

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)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.28 __is_lvalue_expr
Category

Type Trait Functions

Syntax
bool __is_lvalue_expr( typename T )

Returns true if and only if T is an lvalue expression.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.29 __is_lvalue_reference
Category

Type Trait Functions

Syntax
bool __is_lvalue_reference( typename T )

Returns true if and only if T is an lvalue reference type.


3
Can be a reference to an object or function type.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

484
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.1.19.2.30 __is_member_function_pointer
Category

Type Trait Functions

Syntax
bool __is_member_function_pointer( typename T )

Returns true if and only if T is a pointer-to-member-function type .

Returns false for a pointer-to-data member.

Returns false for a regular object pointer.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.31 __is_member_object_pointer
Category

Type Trait Functions

Syntax
bool __is_member_object_pointer( typename T )

Returns true if and only if T is a pointer-to-data-member type.

Returns false for pointer-to-member-function.

Returns false for a regular object pointer.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.32 __is_member_pointer
Category

Type Trait Functions

Syntax
bool __is_member_pointer( typename T )

Returns: __is_member_object_pointer(T) || __is_member_function_pointer(T).

See Also
3
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.33 __is_object
Category

485
C++ Language Guide RAD Studio 3.1 C++ Reference

Type Trait Functions

Syntax
bool __is_object( typename T)

Returns true if and only if T is an object type.

Defined in Section 3.9 p8 of the Working Draft, essentially:


!__is_reference(T) && !__is_function(T) && !__is_void(T).

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.34 __is_pod
Category

Type Trait Functions

Syntax
bool __is_pod( typename T )

Returns true if and only if T is a POD (plain ol' data) type.

Error if T is an incomplete type.

POD types are defined in Section 3.9 p10 of the Working Draft.

POD classes are defined in Section 9 p9 of the Working Draft.

Effectively __is_trivial_type(T) && is standard_layout(T)

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ - ttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.35 __is_pointer
Category

Type Trait Functions

Syntax
3
bool __is_pointer( typename T )

Returns true if and only if T is a pointer type.

Can be an object pointer or a function pointer.

False for pointer-to-member.

486
3.1 C++ Reference RAD Studio C++ Language Guide

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.36 __is_polymorphic
Category

Type Trait Functions

Syntax
bool __is_polymorphic( typename T )

Returns true if and only if T is a poiymorphic class type.

Error if T is an incomplete type.

Polymorphic classes are defined in Section 10.3 of the Working Draft.

"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)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.37 __is_reference
Category

Type Trait Functions

Syntax
bool __is_reference( typename T )

Returns: __is_lvalue_reference(T) || __is_rvalue_reference(T).

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.38 __is_rvalue_expr
Category

Type Trait Functions 3


Syntax
bool __is_rvalue_expr( typename T )

Returns true if and only if T is an rvalue expression.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

487
C++ Language Guide RAD Studio 3.1 C++ Reference

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.39 __is_rvalue_reference
Category

Type Trait Functions

Usage: bool __is_rvalue_reference( typename T )

Returns true if and only if T is an rvalue reference type.

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.40 __is_same
Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.41 __is_scalar
Category

Type Trait Functions

Syntax
bool __is_scalar( typename T )

Returns true if and only if T is a scalar type.


3
Scalar type is defined in Section 3.9 p10 of the Working Draft, essentially:
__is_arithmetic( T ) || __is_enumeration(T) ||
__is_pointer(T) || __is_member_pointer(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)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.42 __is_signed
Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.43 __is_standard_layout
Category

Type Trait Functions

Syntax
bool __is_standard_layout(typename T)

Returns true if and only if T is a standard layout type.

Error if T is an incomplete type.

Standard layout classes are defined in Section 9, p 6 of the Working Draft.

A standard layout type is:

• 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

not happened when this type function is initially implanted.


See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

3.1.3.1.19.2.44 __is_trivial
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 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)

3 Type Trait Functions Overview ( see page 472)

Working Draft — Standard for Programming Language C++ -


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2588.pdf

__has_trivial_assign.xml ( see page 475)

__has_trivial_copy_constructor ( see page 475)

__has_trivial_copy_constructor.xml ( see page 475)

490
3.1 C++ Reference RAD Studio C++ Language Guide

__has_trivial_default_constructor.xml ( see page 476)

3.1.3.1.19.2.45 __is_union
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.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.46 __is_unsigned ( typename T )


Category

Type Trait Functions

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)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.2.47 __is_void
Category

Type Trait Functions

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

Type Trait Functions

491
C++ Language Guide RAD Studio 3.1 C++ Reference

Syntax
bool __is_volatile( typename T )

Returns true if and only if T is a volatile-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.

See Also
C++0x Features (C++Builder 2009) ( see page 462)

Type Trait Functions Overview ( see page 472)

3.1.3.1.19.3 Attributes noreturn and final (C++0x)


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]].

The noreturn Attribute


The noreturn attribute specifies that a function does not return. If a function marked noreturn is called and eventually executes
a return statement, the program is considered ill-formed, but the compiler does not issue a message.

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.

The final Attribute


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.

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

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 (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)

noreturn ( see page 557)

final ( see page 550)

3.1.3.1.19.4 Explicit Conversion Operators (C++0x)


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 contexts (copy-initialization) as explicit
constructors do.

For example:
class T { };

class X {

public:

explicit operator T() const;

};

void m() {

X x;

// with cast:

T tc = (T)x;// ok 3
// without cast:

T t = x;// error: E2034

// 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)

Draft Working Paper

Summary of Working Group Papers

3.1.3.1.19.5 extern Templates (C++0x)


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.

Explicit Instantiation and Declaration


An extern template allows you to declare a template without instantiating it in the translation unit.

To illustrate, the following both creates and instantiates a template:


template <class T>
class MyClass {
//various code
}

template class MyClass<int>;


...
MyClass<int> myClass;
The line template class MyClass<int> is an explicit template definition and causes the template to be instantiated
explicitly in its code unit, resulting in generating code for the template in that unit. Similarly, the line MyClass<int> myClass;
implicitly instantiates the template, also resulting in code generation in the unit. If either of these lines of code are in your unit, the
template is instantiated there.

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.

extern Template Usage


Here are the rules for using extern templates:

• 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)

Working Draft - Standard for Programming Language C++ (Sec. 17.2)

3.1.3.1.19.6 Forward Declaration of Enums (C++0x)


C++Builder 2009 introduces forward declaration of enums. You can declare an enumeration without providing a list of
enumerators. Such declarations would not 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.
enum E : short; // OK: unscoped, underlying type is short
enum F: // illegal: enum-base is required
enum class G : short // OK: scoped, underlying type is short
enum class H; // OK: scoped, underlying type is int
enum E : short; // OK: redeclaration of E
enum class G : short; // OK: redeclaration of G
enum class H; // OK: redeclaration of H
enum class H : int; // OK: redeclaration of H
enum class E : short; // illegal: previously declared as unscoped
enum G : short; // illegal: previously declared as scoped
enum E; // illegal: enum-base is required
enum E : int // illegal: different underlying type
enum class G; // illegal: different underlying type
enum class H : short; // illegal: different underlying type
enum class H {/* */}] // OK: this redeclaration is a definition
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Strongly Typed Enums ( see page 498)

3.1.3.1.19.7 rvalue References (C++0x)


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.

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

// Both references can be used the same way


SomeOtherClass value1 = SomeFunc(lReference);
SomeOtherClass value2 = SomeFunc(rReference);

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.

Eliminating Unnecessary Copying


In many cases, data is copied that simply needs to be moved, that is, the original data holder need not retain the data. An
example is swapping data in two structures, so neither structure holds its previous data. It would be logically sufficient to simply
switch the references to the data.

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

A Proposal to Add an Rvalue Reference to the C++ Language

A Brief Introduction to Rvalue References

3.1.3.1.19.8 Static Assertions (C++0x)


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.

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)

3.1.3.1.19.9 Strongly Typed Enums (C++0x)


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:

• Enumerators are in the scope of their enum.


• Enumerators and enums do not implicitly convert to int (as do "plain" enumerators and enums).
• Enums and their enumerators can have a defined underlying type.
Declaration
You declare a scoped enum by specifying enum class or enum struct. For example:
enum class A {A1, A2, A3 = 50, A4 /* = 51 */};
3
No Implicit Type Conversion
With scoped enums, there is no longer any implicit conversion to or from an integer.

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

enum class A : unsigned long {A1 = 1, A2 = 2, Abig = 0xFFFFFFFOU };


Scoping
A scoped enum introduces its own scope. The names of enumerators are in the enum's scope, and are not injected into the
enclosing scope. For instance:
enum class A { A1, A2, A3 = 100, A4 /* = 101 */ };
A a1 = A1; // error
A a2 = A::A2; // OK-scope specified
Changes to Existing Enums
In addition, existing enums are being extended as follows:

• 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:

• The method for calling scoped enumerators


• The fact that enum class (and enum struct) cannot be specified with elaborated-type-specifiers
enum class E { a, b };
enum E x1 = E::a; // OK
enum class E x2 = E::a; // illegal
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Strongly Typed Enums (Revision 3)

Forward Declaration of Enumerations ( see page 495)

3.1.3.1.19.10 Type Specifier decltype (C++0x)


The C++0x standard includes the decltype keyword and operator, which represents the type of an expression. This feature is
one of the C++0x features added to C++Builder 2009.

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

const char *namePtr, nameChar;


decltype(namePtr); // type is const char*
decltype(nameChar); // type is const char
int& F(void);
decltype(F()); // type is int&

struct; D {double value; }


const D* d = new D();

decltype(d->value); // type is double


decltype((d->value)); // type is const double&

double GetValue(int one);


long int GetValue(double d);
decltype(GetValue); // ill-formed -- ambiguous
See Also
C++0x Features (C++Builder 2009) ( see page 462)

Working Draft - Standard for Programming Language C++ (Sec. 7.1.6.2 - Simple Type Specifiers)

3.1.3.1.19.11 Unicode Character Types and Literals (C++0x)


C++Builder 2009 implements new character types and character literals for Unicode. These types are among the C++0x features
added to C++Builder 2009.

Character Types char16_t and char32_t


Two new types represent Unicode characters:

• 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:

• 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... more ( see
page 507)

3.1.3.1.20.1 TCHAR Mapping


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

char _TCHAR does not float to a wide definition.


wchar_t Sets the UNICODE and _UNICODE defines. _TCHAR floats to the wide definitions of standard library and API
functions.

To set the TCHAR maps to option, go to the Project Options Directories and Conditionals dialog box.

Use _TCHAR maps to wchar_t for VCL


The VCL is implemented in Unicode and always expects Unicode. To use the VCL, you should set TCHAR maps to to wchar_t.
For example, the following code does not compile unless you have set _TCHAR to wchar_t:
TResourceStream* res = new
TResourceStream(HInstance, ResourceId, RT_RCDATA);
If _TCHAR is char, RT_RCDATA maps to a char*, but VCL expects wchar_t.

Use _TEXT function for Constants Strings


3
To ensure that constants strings float properly to ANSI or Unicode, use either the function _TEXT or _T. For example:
::MessageBox(0, _TEXT("The message"),
_TEXT("The caption"), MB_OK);
Code Changes Are Required for Using _TCHAR maps to wchar_t
Before you can set the _TCHAR option to wchar_t, your project must have an entry point called either _tmain or _tWinMain.
New projects created with C++Builder 2009 have these entry points by default, but for imported projects you might need to add
these entry points by hand. You must also include the tchar.h header file, which contains the floating definitions and the entry

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)

Unicode in RAD Studio

Enabling Unicode in Your Applications

Enabling C++ Applications for Unicode ( see page 507)

Directories and Conditionals Dialog Box

3.1.3.1.20.2 Floating Functions


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.

Example of Writing Portable Code Using _TCHAR


RTL functions are available in either ANSI/MBCS or Unicode definitions. For example, the RTL function strlen can be used in
ANSI/MBCS mode as follows:
void StorePersonData(const char* name)
{
PersistToDB(name, strlen(name));
}

A more portable way of writing this code is:

void StorePersonData(const _TCHAR* name)


{
PersistToDB(name, _tcstrlen(name));
}
This example assumes that PersistToDB has a Unicode version. Note that for functions that are not going to change or float,
you should use either char or wchar_t.

List of Floating Definitions from tchar.h


The following table is derived from the tchar.h header file. The char/ANSI column lists the floating functions that are appropriate
when _TCHAR is mapped to char, the ANSI version of the function. The wchar_t/UNICODE column lists the functions for
wchar_t, the UNICODE version of the function. The _TCHAR/Portable column lists the portable version of the function, which
maps to the appropriate function (either the ANSI or UNICODE version) as determined by the current setting of the _TCHAR
mapping option.

Floating Function Definitions from tchar.h

char / ANSI wchar_t / UNICODE _TCHAR / Portable


_access _waccess _taccess
_atoi64 _wtoi64 _tstoi64
3 _atoi64 _wtoi64 _ttoi64
_cgets _cgetws cgetts
_chdir _wchdir _tchdir
_chmod _wchmod _tchmod
_cprintf _cwprintf _tcprintf
_cputs _cputws _cputts

502
3.1 C++ Reference RAD Studio C++ Language Guide

_creat _wcreat _tcreat


_cscanf _cwscanf _tcscanf
_ctime64 _wctime64 _tctime64
_execl _wexecl _texecl
_execle _wexecle _texecle
_execlp _wexeclp _texeclp
_execlpe _wexeclpe _texeclpe
_execv _wexecv _texecv
_execve _wexecve _texecve
_execvp _wexecvp _texecvp
_execvpe _wexecvpe _texecvpe
_fdopen _wfdopen _tfdopen
_fgetchar _fgetwchar _fgettchar
_findfirst _wfindfirst _tfindfirst
_findnext64 _wfindnext64 _tfindnext64
_findnext _wfindnext _tfindnext
_findnexti64 _wfindnexti64 _tfindnexti64
_fputchar _fputwchar _fputtchar
_fsopen _wfsopen _tfsopen
_fullpath _wfullpath _tfullpath
_getch _getwch _gettch
_getche _getwche _gettche
_getcwd _wgetcwd _tgetcwd
_getdcwd _wgetdcwd _tgetdcwd
_ltoa _ltow _ltot
_makepath _wmakepath _tmakepath
_mkdir _wmkdir _tmkdir
_mktemp _wmktemp _tmktemp
_open _wopen _topen
_popen _wpopen _tpopen
_putch _putwch _puttch
_putenv _wputenv _tputenv
_rmdir _wrmdir _trmdir 3
_scprintf _scwprintf _sctprintf
_searchenv _wsearchenv _tsearchenv
_snprintf _snwprintf _sntprintf
_snscanf _snwscanf _sntscanf
_sopen _wsopen _tsopen
_spawnl _wspawnl _tspawnl

503
C++ Language Guide RAD Studio 3.1 C++ Reference

_spawnle _wspawnle _tspawnle


_spawnlp _wspawnlp _tspawnlp
_spawnlpe _wspawnlpe _tspawnlpe
_spawnv _wspawnv _tspawnv
_spawnve _wspawnve _tspawnve
_spawnvp _wspawnvp _tspawnvp
_spawnvpe _wspawnvpe _tspawnvpe
_splitpath _wsplitpath _tsplitpath
_stat64 _wstat64 _tstat64
_stat _wstat _tstat
_stati64 _wstati64 _tstati64
_strdate _wstrdate _tstrdate
_strdec _wcsdec _tcsdec
_strdup _wcsdup _tcsdup
_stricmp _wcsicmp _tcsicmp
_stricoll _wcsicoll _tcsicoll
_strinc _wcsinc _tcsinc
_strlwr _wcslwr _tcslwr
_strncnt _wcsncnt _tcsnbcnt
_strncnt _wcsncnt _tcsnccnt
_strncnt _wcsncnt _tcsnccnt
_strncoll _wcsncoll _tcsnccoll
_strnextc _wcsnextc _tcsnextc
_strnicmp _wcsnicmp _tcsncicmp
_strnicmp _wcsnicmp _tcsnicmp
_strnicoll _wcsnicoll _tcsncicoll
_strnicoll _wcsnicoll _tcsnicoll
_strninc _wcsninc _tcsninc
_strnset _wcsnset _tcsncset
_strnset _wcsnset _tcsnset
_strrev _wcsrev _tcsrev
_strset _wcsset _tcsset

3 _strspnp _wcsspnp _tcsspnp


_strtime _wstrtime _tstrtime
_strtoi64 _wcstoi64 _tcstoi64
_strtoui64 _wcstoui64 _tcstoui64
_strupr _wcsupr _tcsupr
_tempnam _wtempnam _ttempnam
_ui64toa _ui64tow _ui64tot

504
3.1 C++ Reference RAD Studio C++ Language Guide

_ultoa _ultow _ultot


_ungetch _ungetwch _ungettch
_unlink _wunlink _tunlink
_utime64 _wutime64 _tutime64
_utime _wutime _tutime
_vscprintf _vscwprintf _vsctprintf
_vsnprintf _vsnwprintf _vsntprintf
asctime _wasctime _tasctime
atof _wtof _tstof
atoi _wtoi _tstoi
atoi _wtoi _ttoi
atol _wtol _tstol
atol _wtol _ttol
ctime _wctime _tctime
fgetc fgetwc _fgettc
fgets fgetws _fgetts
fopen _wfopen _tfopen
fprintf fwprintf _ftprintf
fputc fputwc _fputtc
fputs fputws _fputts
freopen _wfreopen _tfreopen
fscanf fwscanf _ftscanf
getc getwc _gettc
getchar getwchar _gettchar
getenv _wgetenv _tgetenv
gets getws _getts
isalnum iswalnum _istalnum
isalpha iswalpha _istalpha
isascii iswascii _istascii
iscntrl iswcntrl _istcntrl
isdigit iswdigit _istdigit
isgraph iswgraph _istgraph
islower iswlower _istlower 3
isprint iswprint _istprint
ispunct iswpunct _istpunct
isspace iswspace _istspace
isupper iswupper _istupper
isxdigit iswxdigit _istxdigit
main wmain _tmain

505
C++ Language Guide RAD Studio 3.1 C++ Reference

perror _wperror _tperror


printf wprintf _tprintf
putc putwc _puttc
putchar putwchar _puttchar
puts _putws _putts
remove _wremove _tremove
rename _wrename _trename
scanf wscanf _tscanf
setlocale _wsetlocale _tsetlocale
sprintf swprintf _stprintf
sscanf swscanf _stscanf
strcat wcscat _tcscat
strchr wcschr _tcschr
strcmp wcscmp _tcscmp
strcoll wcscoll _tcscoll
strcpy wcscpy _tcscpy
strcspn wcscspn _tcscspn
strerror _wcserror _tcserror
strftime wcsftime _tcsftime
strlen wcslen _tcsclen
strlen wcslen _tcslen
strncat wcsncat _tcsncat
strncat wcsncat _tcsnccat
strncmp wcsncmp _tcsnccmp
strncmp wcsncmp _tcsncmp
strncpy wcsncpy _tcsnccpy
strncpy wcsncpy _tcsncpy
strpbrk wcspbrk _tcspbrk
strrchr wcsrchr _tcsrchr
strspn wcsspn _tcsspn
strstr wcsstr _tcsstr
strtod wcstod _tcstod

3 strtok wcstok _tcstok


strtol wcstol _tcstol
strtoul wcstoul _tcstoul
strxfrm wcsxfrm _tcsxfrm
system _wsystem _tsystem
tmpnam _wtmpnam _ttmpnam
tolower towlower _totlower

506
3.1 C++ Reference RAD Studio C++ Language Guide

toupper towupper _totupper


ungetc ungetwc _ungettc
vfprintf vfwprintf _vftprintf
vprintf vwprintf _vtprintf
vsprintf vswprintf _vstprintf
WinMain wWinMain _tWinMain

See Also
TCHAR Mapping ( see page 501)

Unicode in RAD Studio

Enabling Unicode in Your Applications

Enabling C++ Applications for Unicode ( see page 507)

3.1.3.1.20.3 Enabling C++ Applications for Unicode


C++ has a unique set of Unicode-related issues that Delphi users do not have. Some of these issues are:

• 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)

Floating Functions ( see page 502)

Unicode in RAD Studio

Enabling Unicode in Your Applications

Directories and Conditionals Dialog Box 3

3.1.3.1.21 Handling Delphi Features in C++Builder 2009


This section contains topics describing how you can handle issues that might arise when C++Builder 2009 interacts with certain
new Delphi features.

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:

3.1.3.1.21.1 How to Handle Delphi Anonymous Methods in C++


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:
interface

type

TRefProc = reference to function (I, J: Integer): Integer;

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;

__interface TRefProc : public System::IInterface


{
public:
virtual int __fastcall Invoke(int I, int J) = 0 ;
};

class PASCALIMPLEMENTATION TTestClass : public System::TObject


{
public:
int __fastcall TakeRefProc(_di_TRefProc RefProc, int I, int J);
3 };
C++ code that seeks to specify a function or member function as a method reference parameter has to wrap the latter behind an
interface that exposes an Invoke() method. A C++ template can be used to encapsulated such an interface. The following C++
code shows an example of a template that can be used to pass C++ methods or member functions as method references to
Delphi.
enum _DummyType{}; // Parameter used as default

template <typename INTF, // Interface with Invoke

508
3.1 C++ Reference RAD Studio C++ Language Guide

typename F, // Function type


typename R, // Return type
typename P1 = _DummyType, // Param #1
typename P2 = _DummyType, // Param #2
typename P3 = _DummyType, // Param #3
typename P4 = _DummyType, // Param #4
typename P5 = _DummyType> // Param #5
class TMethodRef : public TInterfacedObject, public INTF

{
private:
F callback;
public:
TMethodRef(F _callback) : callback(_callback) {}

HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject)


{ return TInterfacedObject::QueryInterface (riid, ppvObject); }
ULONG STDMETHODCALLTYPE AddRef()
{ return TInterfacedObject::_AddRef(); }
ULONG STDMETHODCALLTYPE Release()
{ return TInterfacedObject::_Release(); }

R __fastcall Invoke(P1 p1)


{
return callback(p1);
}
R __fastcall Invoke(P1 p1, P2 p2)
{
return callback(p1, p2);
}
R __fastcall Invoke(P1 p1, P2 p2, P3 p3)
{
return callback(p1, p2, p3);
}
R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4)
{
return callback(p1, p2, p3, p4);
}
R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
{
return callback(p1, p2, p3, p4, p5);
}
};
The following code shows how to use the template shown above to pass a C++ routine as a method reference.
// C++ function we want to pass as a method reference.
int multiplyCallback(int i, int j)
{
return i*j;
}

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;

std::auto_ptr<TTestClass> cls(new TTestClass());


_di_TRefProc proc = new TMethodRef<TRefProc, TClosure, int, int, int>(&myClass.add);

int i = cls->TakeRefProc(proc, 10, 20);


assert(i == 30);
}
See Also
Handling Generics ( see page 511)

Handling AnsiString Code Page Specification ( see page 510)

3.1.3.1.21.2 How to Handle Delphi AnsiString Code Page Specification in C++


The C++ implementation of the AnsiString type provides CodePage support 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:
template AnsiStringT<unsigned short codePage>
Therefore, the type previously known as AnsiString type is now simply a typedef of the new AnsiStringT template, as in:
typedef AnsiStringT<65001> UTF8String;

typedef AnsiStringT<65535> RawByteString;


You can declare other specializations of AnsiStringT with the codepage you need.

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)

Handling Generics ( see page 511)

510
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.1.21.3 How to Handle Delphi Generics in C++


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:
interface

type

MyTList<T> = class(TList<T>) // TList is a class in the Generics.Collections namespace


FItems: array of T;
protected
function GetLength: Integer;
public
function Get(Index: Integer): T;
published
property Len: Integer read GetLength;
end;

{ ScoreList derived from a TList<double>}


ScoreList = class(MyTList<double>)
end;
{ StringList derived from a TList<string>}
StringList = class(MyTList<string>)
end;

implementation

{$R *.dfm}

function MyTList<T>.GetLength: Integer;


begin
Result := Count;
end;

function MyTList<T>.Get(Index: Integer): T;


begin
Result := Items[Index];
end;
The interface above is exposed to C++ as the following:
// Template declaration generated by Delphi parameterized types is
// used only for accessing Delphi variables and fields.
// Don't instantiate with new type parameters in user code.
template<typename T> class PASCALIMPLEMENTATION MyTList__1 : public
Generics_collections::TList__1<T>
{
typedef Generics_collections::TList__1<T> inherited;

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) { }

};

class DELPHICLASS ScoreList;


class PASCALIMPLEMENTATION ScoreList : public MyTList__1<double>
{
typedef MyTList__1<double> inherited;

public:
/* TList<Double>.Create */ inline __fastcall ScoreList(void)/* overload */ :
MyTList__1<double>() { }
/* TList<Double>.Destroy */ inline __fastcall virtual ~ScoreList(void) { }

};

class DELPHICLASS StringList;


class PASCALIMPLEMENTATION StringList : public MyTList__1<System::UnicodeString>
{
typedef MyTList__1<System::UnicodeString> inherited;

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);

int len = list->Len;


assert(len == 2);

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

MyTList__1<UnicodeString> *stringList = new MyTList__1<UnicodeString>();


stringList->Add("hiya");
stringList->Add("there");
stringList->Add("buckeroo");
UnicodeString dstring = stringList->Get(0);
delete stringList;
}
If C++ code attempts to use a Delphi generic for types that were not instantiated in Delphi, you'll get errors at link time. For
example, the following code attempts to use TList__1<char> when the Delphi code did not explicitly instantiate
TList<AnsiChar>:
void UseListOfChar()
{
TList__1<char>* charList = new TList__1<char>();
charList->Add('a');
char ch = charList->Get(1);
delete charList;
}
While the code above compiles, the following errors are generated at link time:
[ILINK32 Error] Error: Unresolved external 'Test::MyTList__1<char>::>::' referenced from
USETEST.OBJ
[ILINK32 Error] Error: Unresolved external '__fastcall Test::MyTList__1<char>>::Add(char)'
referenced from USETEST.OBJ
[ILINK32 Error] Error: Unresolved external '__fastcall Test::MyTList__1<char>::Get(int)'
referenced from USETEST.OBJ
To eliminate the error, you have to make sure that the Delphi code uses the type MyTList<AnsiChar>.

See Also
Handling Anonymous Methods ( see page 508)

Handling AnsiString Code Page Specification ( see page 510)

3.1.3.2 Keywords, Alphabetical Listing


This section contains Keywords, Alphabetical Listing topics.

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

__inline ( see page 525) Category


Keyword extensions
Syntax
__int8, __int16, __int32, __int64, Unsigned __int64, Extended Integer Types ( Category
see page 526) Keyword extensions
Description
You can specify the size for integer types. You must use the appropriate suffix
when using extended integers.
__msfastcall ( see page 526) Category
Modifiers, Keyword extensions
Syntax
__msreturn ( see page 527) Category
Modifiers, Keyword extensions
Syntax
__property ( see page 527) Category
Keyword extensions
Syntax
__published ( see page 528) Category
Keyword extensions
Syntax
__rtti, -RT Option ( see page 528) Category (__rtti keyword)
Modifiers, C++ Keyword Extensions, C++-Specific Keywords
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.... more ( see page 528)
__thread, Multithread Variables ( see page 529) Category
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.
The syntax is Type __thread variable__name. For example
__try ( see page 529) Category
Statements, Keyword extensions
Syntax
_export, __export ( see page 530) Category
Modifiers, Keyword extensions
Form 1
_fastcall, __fastcall ( see page 530) Category
Modifiers, Keyword extensions
Syntax
_stdcall, __stdcall ( see page 531) Category
Modifiers, Keyword extensions
Syntax
alignof ( see page 531) Category
Operators, Keyword extensions
Syntax
3

514
3.1 C++ Reference RAD Studio C++ Language Guide

and, && ( see page 531) Category


Alternative Representations of Operators and Tokens, Operators
Syntax
Description
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... more ( see page
531)
asm, _asm, __asm ( see page 532) Category
Keyword extensions, C++-Specific Keywords
Syntax
auto ( see page 533) Category
Storage class specifiers
Syntax
bitand, & ( see page 533) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The bitand operator is an alternative representation of the &operator (bitwise
AND).
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).
bitor, | ( see page 533) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The bitor operator is an alternative representation of the |~operator ( bitwise OR).
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.
In order to use the bitor operator, you need to check the Enable new operator
names option (the -VM compiler switch, available... more ( see page 533)
bool, false, true ( see page 533) Category
C++-Specific Keywords
Syntax
break ( see page 534) 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.
3
case ( see page 535) Category
Statements
Syntax
catch ( see page 536) Category
Statements, C++-Specific Keywords
Syntax

515
C++ Language Guide RAD Studio 3.1 C++ Reference

cdecl, _cdecl, __cdecl ( see page 536) Category


Modifiers, Keyword extensions
Syntax
char ( see page 536) Category
Type specifiers
Syntax
char16_t ( see page 537) Category
C++-Specific Keywords, Type specifiers
Syntax
char32_t ( see page 537) Category
C++-Specific Keywords, Type specifiers
Syntax
class ( see page 537) Category
C++-Specific Keywords, Type specifiers
Syntax
compl, ~ ( see page 538) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The compl operator is an alternative representation of the ~operator ( bitwise
NOT).
The compl operator is the abbreviation for complement.
compl Inverts true to false and false to true, The tilde (~) is placed in front of the
integer used for the complement.
The complement of 1 would be 0, and vice versa.
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.
The type of the result is the type of the... more ( see page 538)
const ( see page 538) Category
Modifiers
Syntax
const_cast (typecast Operator) ( see page 539) Category
C++-Specific Keywords
Syntax
continue ( see page 540) Category
Statements
Syntax
__declspec(dllexport) ( see page 540) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(dllimport) ( see page 541) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(naked) ( see page 541) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(noreturn) ( see page 541) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(nothrow) ( see page 542) Category
Modifiers, Keyword extensions, Storage class specifiers
3 Syntax
__declspec(novtable) ( see page 542) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(property) ( see page 543) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(selectany) ( see page 543) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax

516
3.1 C++ Reference RAD Studio C++ Language Guide

__declspec(thread) ( see page 544) Category


Modifiers, Keyword extensions, Storage class specifiers
Syntax
__declspec(uuid(“ComObjectGUID”)) ( see page 544) Category
Modifiers, Keyword extensions, Storage class specifiers
Syntax
decltype ( see page 545) Category
Type specifiers
Syntax
default ( see page 545) Category
Statements
Syntax
delete ( see page 546) Category
Operators, C++-Specific Keywords
Syntax
do ( see page 546) Category
Statements
Syntax
double ( see page 547) Category
Type specifiers
Syntax
dynamic_cast (typecast Operator) ( see page 547) Category
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...
more ( see page 547)
enum ( see page 548) Category
Type specifiers
Syntax
explicit ( see page 548) Category
C++-Specific Keywords
Syntax
export ( see page 549) Category
Unimplemented
Syntax
extern ( see page 549) Category
Storage class specifiers
Syntax
final ( see page 550) Category
Attributes, Keyword extensions
Syntax
__finally ( see page 550) Category
Statements, Keyword extensions
Syntax
float ( see page 552) Category
Type specifiers 3
Syntax
for ( see page 552) Category
Statements
Syntax
friend ( see page 553) Category
C++-Specific Keywords
Syntax

517
C++ Language Guide RAD Studio 3.1 C++ Reference

goto ( see page 553) Category


Statements
Syntax
if, else ( see page 553) Category
Operators
C++ Syntax
import, _import, __import ( see page 554) Category
Modifiers, Keyword extensions
Form 1
inline ( see page 554) Category
C++-Specific Keywords
Syntax
int ( see page 555) Category
Type specifiers
Syntax
long ( see page 555) Category
Type specifiers
Syntax
mutable ( see page 555) Category
C++-Specific Keywords, Storage class specifiers
Syntax
namespace ( see page 556) 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... more ( see page 556)
new ( see page 556) Category
Operators, C++-Specific Keywords
Syntax
noreturn ( see page 557) Category
Attributes, Keyword extensions
Syntax
not, ! ( see page 557) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The not operator is an alternative representation of the !operator (logical
negation).
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 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... more ( see page 557)
not_eq, != ( see page 558) Category
Alternative Representations of Operators and Tokens, Operators
3 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).

518
3.1 C++ Reference RAD Studio C++ Language Guide

nullptr ( see page 558) Category


Reserved Words
Syntax
operator ( see page 558) Category
Operators, C++-Specific Keywords
Syntax
or, || ( see page 559) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The or operator is an alternative representation of the || operator ( logical OR).
Only two statements can be evaluated at a time.
or returns true if two values are different, such as 2 or 6.
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).
or_eq, |= ( see page 559) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The or_eq operator is an alternative representation of !=(bitwise inclusive OR).
or_eq tests for logical equivalence or bitwise equality.
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).
pascal, _pascal, __pascal ( see page 559) Category
Modifiers, Keyword extensions
Syntax
private ( see page 560) Category
C++-Specific Keywords
Syntax
protected ( see page 560) Category
C++-Specific Keywords
Syntax
public ( see page 561) Category
C++-Specific Keywords
Syntax
register ( see page 561) Category
Storage class specifiers
Syntax
reinterpret_cast (typecast Operator) ( see page 561) Category
C++-Specific Keywords
Syntax
return ( see page 562) Category
Statements
Syntax
short ( see page 563) Category
Type specifiers
Syntax
signed ( see page 563) Category
3
Type specifiers
Syntax

519
C++ Language Guide RAD Studio 3.1 C++ Reference

sizeof ( see page 563) Category


Operators
Description
The sizeof operator has two distinct uses:
sizeof unary-expression
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... more
( see page 563)
static ( see page 564) Category
Storage class specifiers
Syntax
static_assert ( see page 565) Category
Statements, C++-Specific Keywords
Syntax
static_cast (typecast Operator) ( see page 565) Category
C++-Specific Keywords
Syntax
struct ( see page 566) Category
Type specifiers
Syntax
switch ( see page 567) Category
Statements
Syntax
template ( see page 568) Category
C++-Specific Keywords
Syntax
this ( see page 568) Category
C++-Specific Keywords
Example
throw ( see page 569) Category
Statements, C++-Specific Keywords
Syntax
try ( see page 569) Category
Statements, C++-Specific Keywords
Syntax
typedef ( see page 569) Category
Storage class specifiers
Syntax
typeid ( see page 570) Category
Operators, C++-Specific Keywords
Syntax
typename ( see page 570) Category
C++-Specific Keywords
Syntax 1
union ( see page 571) Category
Type specifiers
3 Syntax
unsigned ( see page 571) Category
Type specifiers
Syntax

520
3.1 C++ Reference RAD Studio C++ Language Guide

using (declaration) ( see page 572) Category


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;
virtual ( see page 572) Category
C++-Specific Keywords
Syntax
void ( see page 572) Category
Special types
Syntax
volatile ( see page 573) Category
Modifiers
Syntax
wchar_t ( see page 573) Category
C++-Specific Keywords, Type specifiers
Syntax
while ( see page 574) Category
Statements
Syntax
xor, ^ ( see page 574) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
Description
The xor operator is an alternative representation of the ^ operator (bitwise xor).
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... more ( see page 574)
__classmethod ( see page 574) Category
Modifiers, Keyword extensions
Syntax
alignas ( see page 575) Category
C++-Specific Keywords
Syntax
and_eq, &= ( see page 575) Category
Alternative Representations of Operators and Tokens, Operators
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).
axiom ( see page 575) Category
Reserved Words 3
Syntax
concept ( see page 576) Category
Reserved Words
Syntax
concept_map ( see page 576) Category
Reserved Words
Syntax

521
C++ Language Guide RAD Studio 3.1 C++ Reference

constexpr ( see page 576) Category


Reserved Words
Syntax
late_check ( see page 576) Category
Reserved Words
Syntax
requires ( see page 577) Category
Reserved Words
Syntax
thread_local ( see page 577) Category
Reserved Words
Syntax
xor_eq, ^= ( see page 577) Category
Alternative Representations of Operators and Tokens, Operators
Syntax
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.
False is returned even if 6*3=9*2.
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).
_Bool ( see page 578) Category
Reserved Words
Syntax
_Complex ( see page 578) Category
Reserved Words
Syntax
_Imaginary ( see page 578) Category
Reserved Words
Syntax
restrict ( see page 579) Category
Reserved Words
Syntax

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)

__closure ( see page 523)

__property ( see page 527)

__published ( see page 528)

3.1.3.2.2 __classid
Category

Operators, Keyword extensions

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)

__property ( see page 527)

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

Modifiers, Keyword extensions, Storage class specifiers

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.

Argument Comparable keyword


dllexport __export
dllimport __import
thread __thread

See Also
_export ( see page 530)

import ( see page 554)


3 __declspec(dllexport) ( see page 540)

__declspec(dllimport) ( see page 541)

__declspec(naked) ( see page 541)

__declspec(noreturn) ( see page 541)

__declspec(nothrow) ( see page 542)

__declspec(novtablet) ( see page 542)

524
3.1 C++ Reference RAD Studio C++ Language Guide

__declspec(property) ( see page 543)

__declspec(selectany) ( see page 543)

__declspec(thread) ( see page 544)

__declspec(uuid) ( see page 544)

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.

Specifying an already-used dispatch ID in a dispid directive causes a compile-time error.

See Also
__closure ( see page 523)

__property ( see page 527)

3.1.3.2.6 __except
Category

Statements, Keyword extensions

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)

__try ( see page 529)


3

3.1.3.2.7 __inline
Category

Keyword extensions

Syntax

525
C++ Language Guide RAD Studio 3.1 C++ Reference

__inline <datatype> <class>_<function> (<parameters>) { <statements>; }


Description

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.

3.1.3.2.8 __int8, __int16, __int32, __int64, Unsigned __int64, Extended Integer


Types
Category

Keyword extensions

Description

You can specify the size for integer types. You must use the appropriate suffix when using extended integers.

Type Suffix Example Storage


__int8 i8 __int8 c = 127i8; 8 bits
__int16 i16 __int16 s = 32767i16; 16 bits
__int32 i32 __int32 i = 123456789i32; 32 bits
__int64 i64 __int64 big = 12345654321i64; 64 bits
unsigned __int64 ui64 unsigned __int64 hugeInt = 1234567887654321ui64; 64 bits

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)


3
Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

3.1.3.2.9 __msfastcall
Category

526
3.1 C++ Reference RAD Studio C++ Language Guide

Modifiers, Keyword extensions

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

Modifiers, Keyword extensions

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> "}"

<prop dim list> ::=


"[" <type> [ <id> ] "]" [ <prop dim list> ]

<prop attrib list> ::=


<prop attrib> [ , <prop attrib list> ]

<prop attrib> ::=


read = <data/function id> |
write = <data/function id> |
stored = <data/function id> |
stored = <boolean constant> |
default = <constant> |
nodefault |
index = <const int expression> 3
Description

The __property keyword was added to support the VCL

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

The __published keyword was added to support the VCL.

See Also
__closure ( see page 523)

__dispid ( see page 525)

3.1.3.2.13 __rtti, -RT Option


Category (__rtti keyword)

Modifiers, C++ Keyword Extensions, C++-Specific Keywords

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)

Runtime Type Identification And Destructors ( see page 454)

3.1.3.2.14 __thread, Multithread Variables


Category

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.

The syntax is Type __thread variable__name. For example


int __thread x;
This statement declares an integer type variable that will be global but private to each thread in the program in which the
statement occurs.

3.1.3.2.15 __try
Category

Statements, Keyword extensions

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:

• Execute the actions specified by the handler


• Ignore the generated exception and resume program execution 3
• Continue the search for some other handler (regenerate the exception)
If no handler is found, the program will call the terminate function. If no exceptions are thrown, the program executes in the
normal fashion.
See Also
catch ( see page 536)

__finally ( see page 550)

529
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.2.16 _export, __export


Category

Modifiers, Keyword extensions

Form 1
class _export <class name>
Form 2
return_type _export <function name>
Form 3
data_type _export <data name>
Description

These modifiers are used to export classes, functions, and data.

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.

Note: If you use _export

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.

3.1.3.2.17 _fastcall, __fastcall


Category

Modifiers, Keyword extensions

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.

3.1.3.2.18 _stdcall, __stdcall


Category

Modifiers, Keyword extensions

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.

Such functions comply with the standard WIN32 argument-passing convention.

Note: Note: The __stdcall modifier is subject to name mangling. See the description of the -VC option.

3.1.3.2.19 alignof
Category

Operators, Keyword extensions

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)

Working Draft - Standard for Programming Language C++ (Sec. 5.3.6)

alignof Operator (C++0x) ( see page 463)

3
3.1.3.2.20 and, &&
Category

Alternative Representations of Operators and Tokens, Operators

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.

Overloading && or and

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.

3.1.3.2.21 asm, _asm, __asm


Category

Keyword extensions, C++-Specific Keywords

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

Storage class specifiers

Syntax
[auto] <data-definition> ;
Description

Use the auto modifer to define a local variable as having a local lifetime.

This is the default for local variables and is rarely used.

3.1.3.2.23 bitand, &


Category

Alternative Representations of Operators and Tokens, Operators

Syntax

Description

The bitand operator is an alternative representation of the &operator (bitwise AND).

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

Alternative Representations of Operators and Tokens, Operators

Syntax

Description

The bitor operator is an alternative representation of the |~operator ( bitwise OR).

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).

3.1.3.2.25 bool, false, true


Category

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>

using namespace std;

int main(int argc, char* argv[])


{
char ch;

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

do ( see page 546)

for ( see page 552)

while ( see page 574)

case ( see page 535)

default ( see page 545)

switch ( see page 567)

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.

If no match is found, control is passed to the default case.

Note: It is illegal to have duplicate case

constants in the same switch statement. Example

This example illustrates the use of keywords break, case, default, return, and switch.
#include <iostream>

using namespace std;

int main(int argc, char* argv[])


{ 3
char ch;

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

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
break ( see page 534)

default ( see page 545)

switch ( see page 567)

3.1.3.2.28 catch
Category

Statements, C++-Specific Keywords

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.

3.1.3.2.29 cdecl, _cdecl, __cdecl


Category

Modifiers, Keyword extensions

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.

A char can be signed, unsigned, or unspecified. By default, signed char is assumed.

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

C++-Specific Keywords, Type specifiers

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

C++-Specific Keywords, Type specifiers

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

C++-Specific Keywords, Type specifiers

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)

Protected ( see page 560)

public ( see page 561)

3.1.3.2.34 compl, ~
Category

Alternative Representations of Operators and Tokens, Operators

Syntax

Description

The compl operator is an alternative representation of the ~operator ( bitwise NOT).

The compl operator is the abbreviation for complement.

compl Inverts true to false and false to true, The tilde (~) is placed in front of the integer used for the complement.

The complement of 1 would be 0, and vice versa.

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.

The type of the result is the type of the promoted operand.

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 make a variable value unmodifiable.

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

const float pi = 3.14;

// When used by itself, const is equivalent to int.


const maxint = 12345;

// A constant pointer
char *const str1 = "Hello, world";

// A pointer to a constant character string.


char const *str2 = "CodeGear Corporation";
Given these declarations, the following statements are illegal.
pi = 3.0; // Assigns a value to a const.
i = maxint++; // Increments a const.
str1 = "Hi, there!" // Points str1 to something else.
Using the const Keyword in C++ Programs

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++.

Warning: A pointer can indirectly modify a const variable, as in the following:


*(int *)&my_age = 35;
If you use the const modifier with a pointer parameter in a function's parameter list, the function cannot modify the variable that
the pointer points to. For example,
int printf (const char *format, ...);
printf is prevented from modifying the format string.

See Also
mutable ( see page 555)

3.1.3.2.36 const_cast (typecast Operator)


Category

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)

Reinterpret_cast (typecast Operator) ( see page 561)

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

This example illustrates the use of the keyword continue.


void __fastcall TForm1::Button1Click(TObject *Sender)
{
float array[20];

// Code to initialize array...


for (int i = 0; i < 20; i++)
{
array[i] = random(i + 20);
}
array[6] = 0;

for (int i = 0; i < 20; i++)


{
if (array[i] == 0)
continue;
array[i] = 1/array[i];
ListBox1->Items->Add(array[i]);
}
}
See Also
for ( see page 552)

while ( see page 574)

3 3.1.3.2.38 __declspec(dllexport)
Category

Modifiers, Keyword extensions, Storage class specifiers

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

replaces the __export keyword.

3.1.3.2.39 __declspec(dllimport)
Category

Modifiers, Keyword extensions, Storage class specifiers

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

: dllimport replaces the __import keyword.

3.1.3.2.40 __declspec(naked)
Category

Modifiers, Keyword extensions, Storage class specifiers

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

This code defines a function with the naked attribute:


// Example of the naked attribute
__declspec( naked ) int func( formal_parameters )
{ 3
// Function body
}

3.1.3.2.41 __declspec(noreturn)
Category

Modifiers, Keyword extensions, Storage class specifiers

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

Modifiers, Keyword extensions, Storage class specifiers

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.

The following three declarations are equivalent:


#define WINAPI __declspec(nothrow) __stdcall
void WINAPI foo1();
void __declspec(nothrow) __stdcall foo2();
void __stdcall foo3() throw();
Using void __declspec(nothrow) __stdcall foo2(); has the advantage that you can use an API definition, such as the
illustrated by the #define statement, to easily specify nothrow on a set of functions. The third declaration, void __stdcall foo3()
throw(); is the syntax defined by the C++ standard.
3

3.1.3.2.43 __declspec(novtable)
Category

Modifiers, Keyword extensions, Storage class specifiers

Syntax

542
3.1 C++ Reference RAD Studio C++ Language Guide

__declspec( novtable ) declarator


This form of _declspec can be applied to any class declaration, but should only be applied to pure interface classes, that is
classes that will never be instantiated on their own. The _declspec stops the compiler from generating code to initialize the vfptr
in the constructor(s) and destructor of the class. In many cases, this removes the only references to the vtable that are
associated with the class and, thus, the linker will remove it. Using this form of _declspec can result in a significant reduction in
code size

3.1.3.2.44 __declspec(property)
Category

Modifiers, Keyword extensions, Storage class specifiers

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

__declspec(property(get=GetX, put=PutX)) int x[];

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

Modifiers, Keyword extensions, Storage class specifiers 3


Syntax
__declspec( selectany ) declarator
A global data item can normally be initialized only once in an application or library. This attribute can be used in initializing global
data defined by headers, when the same header appears in more than one source file.

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

This code shows how to use the selectany attribute:

//Correct - x1 is initialized and externally visible

__declspec(selectany) int x1=1;

//Incorrect - const is by default static in C++, so

//x2 is not visible externally (This is OK in C, since

//const is not by default static in C)

const __declspec(selectany) int x2 =2;

//Correct - x3 is extern const, so externally visible

extern const __declspec(selectany) int x3=3;

//Correct - x4 is extern const, so it is externally visible

extern const int x4;

const __declspec(selectany) int x4=4;

//Incorrect - __declspec(selectany) is applied to the uninitialized //declaration of x5 extern __declspec(selectany) int x5;

3.1.3.2.46 __declspec(thread)
Category

Modifiers, Keyword extensions, Storage class specifiers

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

Modifiers, Keyword extensions, Storage class specifiers

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:

struct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown;

struct __declspec(uuid("{00020400-0000-0000-c000-000000000046}")) IDispatch;

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

Use the default statement in switch statement blocks.

• 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>

using namespace std;

int main(int argc, char* argv[])


{
char ch; 3
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. */

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)

case ( see page 535)

switch ( see page 567)

3.1.3.2.50 delete
Category

Operators, C++-Specific Keywords

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)

The Delete Operator With Arrays ( see page 437)

3.1.3.2.51 do
3
Category

Statements

Syntax
do <statement> while ( <condition> );
Description

The do statement executes until the condition becomes false.

546
3.1 C++ Reference RAD Studio C++ Language Guide

<statement> is executed repeatedly as long as the value of <condition> remains true.

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)

long ( see page 555)

3.1.3.2.53 dynamic_cast (typecast Operator)


Category

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.

Note: Runtime type identification (RTTI) is required for dynamic_cast

547
C++ Language Guide RAD Studio 3.1 C++ Reference

See Also
Const_cast (typecast Operator) ( see page 539)

Reinterpret_cast (typecast Operator) ( see page 561)

__rtti ( see page 528)

static_cast (typecast Operator) ( see page 565)

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

Storage class specifiers

Syntax
extern <data definition> ;

549
C++ Language Guide RAD Studio 3.1 C++ Reference

[extern] <function prototype> ;


Description

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.

The keyword extern is optional for a function prototype.

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

Attributes, Keyword extensions

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

Statements, Keyword extensions

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.

Type Length Range


float 32 bits 3.4 * (10**-38) to 3.4 * (10**+38)

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

The for statement implements an iterative loop.

<condition> is checked before the first entry into the block.

<statement> is executed repeatedly UNTIL the value of <condition> is false.

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>.

Labels are always terminated by a colon.

3.1.3.2.64 if, else


Category

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

Use if to implement a conditional statement.

You can declare variables in the condition expression. For example,


if (int val = func(arg))
is valid syntax. The variable val is in scope for the if statement and extends to an else block when it exists.

The condition statement must convert to a bool type. Otherwise, the condition is ill-formed.

When <condition> evaluates to true, <statement1> executes.

If <condition> is false, <statement2> executes.

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.

3.1.3.2.65 import, _import, __import


Category

Modifiers, Keyword extensions

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

This keyword can be used as a class, function, or data modifier.

3.1.3.2.66 inline
3 Category

C++-Specific Keywords

Syntax
inline <datatype> <class>_<function> (<parameters>) { <statements>; }
Description

Use the inline keyword to declare or define C++ inline functions.

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

Use the int type specifier to define an integer data type.

Variables of type int can be signed (default) or unsigned.

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

C++-Specific Keywords, Storage class specifiers

Syntax
mutable <variable name>;
Description

Use the mutable specifier to make a variable modifiable even though it is in a const-qualified expression.

Using the mutable Keyword

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

Operators, C++-Specific Keywords

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.

Example of Operator new with Nothrow


#include <new>
int main(int argc, char* argv[])
{
int *pn;
// nothrow version returns null pointer rather than throwing a
// bad_alloc exception.
pn = new(nothrow) int[5000000];
if(pn != NULL) {
// Allocation succeded.
}
return 0;
}
See Also
Delete ( see page 546)

The Operator new With Arrays ( see page 437)

Operator new ( see page 437)

Operator new Placement Syntax ( see page 436)

Handling Errors For The New Operator ( see page 435)

3.1.3.2.72 noreturn
Category

Attributes, Keyword extensions

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

Alternative Representations of Operators and Tokens, Operators 3


Syntax

Description

The not operator is an alternative representation of the !operator (logical negation).

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

Alternative Representations of Operators and Tokens, Operators

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.

Warning: C++Builder does not implement nullptr

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

Operators, C++-Specific Keywords

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

Alternative Representations of Operators and Tokens, Operators

Syntax

Description

The or operator is an alternative representation of the || operator ( logical OR).

Only two statements can be evaluated at a time.

or returns true if two values are different, such as 2 or 6.

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

Alternative Representations of Operators and Tokens, Operators

Syntax

Description

The or_eq operator is an alternative representation of !=(bitwise inclusive OR).

or_eq tests for logical equivalence or bitwise equality.

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).

3.1.3.2.79 pascal, _pascal, __pascal


Category

Modifiers, Keyword extensions


3

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

(the name is in uppercase).

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.

Class members are private by default.

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)

friend ( see page 553)

Protected ( see page 560)

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)

friend ( see page 553)

Private ( see page 560)

560
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.2.82 public
Category

C++-Specific Keywords

Syntax
public: <declarations>
Description

A public class member can be accessed by any function.

Members of a struct or union 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)

friend ( see page 553)

Private ( see page 560)

Protected ( see page 560)

__published ( see page 528)

struct ( see page 566)

3.1.3.2.83 register
Category

Storage class specifiers

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.

3.1.3.2.84 reinterpret_cast (typecast Operator) 3


Category

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.

A pointer can be explicitly converted to an integral type.

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 yet undefined class can be used in a pointer or reference conversion.

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)

Dynamic_cast (typecast Operator) ( see page 547)

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>

using namespace std;

int main(int argc, char* argv[])


int main(int argc, char* argv[])
{
char ch;

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.

When the base type is omitted from a declaration, int is assumed.

See Also
long ( see page 555)

signed ( see page 563)

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.

When the base type is omitted from a declaration, int is assumed.

See Also
char ( see page 536)

int ( see page 555)

long ( see page 555)

short ( see page 563)

unsigned ( see page 571)

3.1.3.2.88 sizeof
3
Category

Operators

Description

The sizeof operator has two distinct uses:

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.

The integer type of the result of sizeof is size_t.

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

Storage class specifiers

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

Statements, C++-Specific Keywords

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.

3.1.3.2.91 static_cast (typecast Operator)


Category

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

• if an unambiguous conversion exists from Y to X


• if X is not a virtual base class
An object can be explicitly converted to a reference type X& if a pointer to that object can be explicitly converted to an X*. The
result of the conversion is an lvalue. No constructors or conversion functions are called as the result of a cast to a reference.
An object or a value can be converted to a class object only if an appropriate constructor or conversion operator has been
declared.
A pointer to a member can be explicitly converted into a different pointer-to-member type only if both types are pointers to
members of the same class or pointers to members of two classes, one of which is unambiguously derived from the other.
When T is a reference the result of static_cast< T > (arg) is an lvalue. The result of a pointer or reference cast refers to the
original expression.
See Also
Const_cast (typecast Operator) ( see page 539)

Dynamic_cast (typecast Operator) ( see page 547)

Reinterpret_cast (typecast Operator) ( see page 561)

3.1.3.2.92 struct
Category

Type specifiers

Syntax
struct [<struct type name>] {
[<type> <variable-name[, variable-name, ...]>] ;
.
.
.
} [<structure variables>] ;
Description

Use a struct to group variables into a single record.

<struct type name> An optional tag name that refers to the structure type.

<structure variables> The data definitions, also optional.

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).

Separate different variable types by a semicolon.

Use the . operator, or the -> operator to access elements in a structure.

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)

public ( see page 561)

union ( see page 571)

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.

If no case satisfies the condition the default case evaluates.

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>

using namespace std;

int main(int argc, char* argv[])


{
char ch;

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)

case ( see page 535)

default ( see page 545)

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

Statements, C++-Specific Keywords

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

Statements, C++-Specific Keywords

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:

• The program searches for a matching handler


• If a handler is found, the stack is unwound to that point
• Program control is tranferred to the handler
If no handler is found, the program will call the terminate function. If no exceptions are thrown, the program executes in the
normal fashion.
See Also
catch ( see page 536)

3.1.3.2.98 typedef
3
Category

Storage class specifiers

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

Operators, C++-Specific Keywords

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.

Note: When using the typename

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.

Note: Compile with: bcc32 (no -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

Note: Compile with: bcc32 (-A

switch)
bc++bcc32 -A test.cpp
The result is:

Error E2089 47071.cpp 7: Identifier 'AInt' cannot have a type qualifier

Error E2303 47071.cpp 7: Type name expected

Error E2139 47071.cpp 7: Declaration missing ;

Both results are as expected.

3.1.3.2.101 union
Category

Type specifiers

Syntax
union [<union type name>] {
<type> <variable names> ;
...
} [<union variables>] ;
Description

Use unions to define variables that share storage space.

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.

Use the record selector (.) to access elements of a union .

See Also
class ( see page 537)

public ( see page 561)

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.

When the base type is omitted from a declaration, int is assumed.

571
C++ Language Guide RAD Studio 3.1 C++ Reference

See Also
char ( see page 536)

int ( see page 555)

long ( see page 555)

short ( see page 563)

signed ( see page 563)

3.1.3.2.103 using (declaration)


Category

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.

The redefined function overrides the base class function.

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.

Note: C++ extends volatile

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

C++-Specific Keywords, Type specifiers

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

Use the while keyword to conditionally iterate a statement.

<statement> executes repeatedly until the value of <condition> is false.

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

Alternative Representations of Operators and Tokens, Operators

Syntax

Description

The xor operator is an alternative representation of the ^ operator (bitwise xor).

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

Modifiers, Keyword extensions

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)

Class Methods ( see page 406)

3.1.3.2.111 alignas
Category

C++-Specific Keywords

Syntax
alignas
Description

Reserved for future use.

Warning: C++Builder does not implement alignas

but does treat it as a keyword when the -Ax compiler flag is set.

3.1.3.2.112 and_eq, &=


Category

Alternative Representations of Operators and Tokens, Operators

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

Reserved for future use.

Warning: C++Builder does not implement axiom

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

Reserved for future use.

Warning: C++Builder does not implement concept

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

Reserved for future use.

Warning: C++Builder does not implement concept_map

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

Reserved for future use.

Warning: C++Builder does not implement constexpr


3
but does treat it as a keyword when the -Ax compiler flag is set.

3.1.3.2.117 late_check
Category

Reserved Words

576
3.1 C++ Reference RAD Studio C++ Language Guide

Syntax
late_check
Description

Reserved for future use.

Warning: C++Builder does not implement late_check

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

Reserved for future use.

Warning: C++Builder does not implement requires

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

Reserved for future use.

Warning: C++Builder does not implement thread_local

but does treat it as a keyword when the -Ax compiler flag is set.

3.1.3.2.120 xor_eq, ^=
Category

Alternative Representations of Operators and Tokens, Operators


3
Syntax

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

False is returned even if 6*3=9*2.

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

Reserved for future use.

Warning: C++Builder does not implement _Bool

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

Reserved for future use.

Warning: C++Builder does not implement _Complex

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.

Warning: C++Builder does not implement _Imaginary

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

Reserved for future use.

Warning: C++Builder does not implement restrict

but does treat it as a keyword when the -An compiler flag is set.

3.1.3.3 Keywords, By Category


This section contains Keywords, By Category topics.

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.

3.1.3.3.1 Alternative Representations of Tokens


This section contains topics about alternative representations of C++ tokens.

Keyword Topics
The following table summarizes the alternative representation keywords and the token that each keyword represents.

Keyword / Alternative Representation Token Definition


Represented
and ( see page 531) && logical AND
3
and_eq ( see page 575) &= assignment by bitwise AND
bitand ( see page 533) & bitwise AND
bitor ( see page 533) | bitwise OR
compl ( see page 538) ~ bitwise NOT (bitwise one's complement)
not ( see page 557) ! logical negation
not_eq ( see page 558) != bitwise inequality

579
C++ Language Guide RAD Studio 3.1 C++ Reference

or ( see page 559) || logical OR


or_eq ( see page 559) |= bitwise inclusive OR
xor ( see page 574) ^ bitwise exclusive OR
xor_eq ( see page 577) ^= bitwise XOR assignment

3.1.3.3.2 Attributes
This section contains C++ attributes keyword topics.

Keyword Topics
final ( see page 550)

noreturn ( see page 557)

See Also
Attributes noreturn and final (C++0x) ( see page 492)

3.1.3.3.3 C++Builder Keyword Extensions


This section contains C++Builder Keyword Extension topics.

Keyword Topics
alignof ( see page 531)

asm ( see page 532)

__automated ( see page 522)

cdecl ( see page 536)

__classid ( see page 523)

__classmethod ( see page 574)

__closure ( see page 523)

__declspec ( see page 523)

__declspec(dllexport) ( see page 540)

__declspec(dllimport) ( see page 541)

__declspec(naked) ( see page 541)

__declspec(noreturn) ( see page 541)

__declspec(nothrow) ( see page 542)


3 __declspec(novtable) ( see page 542)

__declspec(property) ( see page 543)

__declspec(selectany) ( see page 543)

__declspec(thread) ( see page 544)

__declspec(uuid(“ComObjectGUID”)) ( see page 544)

__except ( see page 525)

580
3.1 C++ Reference RAD Studio C++ Language Guide

_export ( see page 549)

_fastcall ( see page 530)

final ( see page 550)

__finally ( see page 550)

_import ( see page 554)

__inline ( see page 525)

__int8 __int16 __int32 __int64 Unsigned_int64 (Extended integer types) ( see page 526)

__msfastcall ( see page 526)

__msreturn ( see page 527)

noreturn ( see page 557)

__thread ( see page 529)

Pascal ( see page 559)

__property ( see page 527)

__published ( see page 528)

__rtti ( see page 528)

_stdcall ( see page 531)

__try ( see page 529)

3.1.3.3.4 C++ Specific Keywords


This section contains C++ specific keyword topics.

Keyword Topics
asm ( see page 532)

bool ( see page 533)

catch ( see page 536)

char16_t ( see page 537)

char32_t ( see page 537)

class ( see page 537)

const_cast (typecast operator) ( see page 529)

delete ( see page 546)

dynamic_cast (typecast operator) ( see page 547) 3


explicit ( see page 548)

false ( see page 533)

friend ( see page 553)

inline ( see page 554)

mutable ( see page 555)

581
C++ Language Guide RAD Studio 3.1 C++ Reference

namespace ( see page 556)

new ( see page 556)

operator ( see page 558)

private ( see page 560)

protected ( see page 560)

public ( see page 561)

reinterpret_cast (typecast operator) ( see page 561)

__rtti ( see page 528)

static_cast (typecst operator) ( see page 565)

static_assert ( see page 565)

template ( see page 568)

this ( see page 568)

throw ( see page 569)

true ( see page 533)

try ( see page 569)

typeid ( see page 570)

typename ( see page 570)

using (declaration) ( see page 572)

virtual ( see page 572)

whar_t ( see page 573)

3.1.3.3.5 Modifiers
This section contains C++ Modifier keyword topics.

Keyword Topics
Cdecl ( see page 536)

__classmethod ( see page 574)

const ( see page 538)

__declspec ( see page 523)

__declspec(dllexport) ( see page 540)

3 __declspec(dllimport) ( see page 541)

__declspec(naked) ( see page 541)

__declspec(noreturn) ( see page 541)

__declspec(nothrow) ( see page 542)

__declspec(novtable) ( see page 542)

__declspec(property) ( see page 543)

582
3.1 C++ Reference RAD Studio C++ Language Guide

__declspec(selectany) ( see page 543)

__declspec(thread) ( see page 544)

__declspec(uuid(“ComObjectGUID”)) ( see page 544)

dispid ( see page 525)

_export ( see page 549)

_fastcall ( see page 530)

_import ( see page 554)

__msfastcall ( see page 526)

__msreturn ( see page 527)

Pascal ( see page 559)

__rtti ( see page 528)

_stdcall ( see page 531)

volatile ( see page 573)

3.1.3.3.6 Operators
This section contains C++ Operator keyword topics.

Keyword Topics
alignof ( see page 531)

and ( see page 531)

and_eq ( see page 575)

bitand ( see page 533)

bitor ( see page 533)

__classid ( see page 523)

compl ( see page 538)

decltype ( see page 499)

delete ( see page 546)

if ( see page 553)

new ( see page 556)

not ( see page 557)

not_eq ( see page 558) 3


operator ( see page 558)

or ( see page 559)

or_eq ( see page 559)

typeid ( see page 570)

sizeof ( see page 563)

583
C++ Language Guide RAD Studio 3.1 C++ Reference

xor ( see page 574)

xor_eq ( see page 577)

3.1.3.3.7 Reserved Words


This section contains C++ Reserved Words keyword topics.

Keyword Topic
alignas ( see page 575)

axiom ( see page 575)

_Bool ( see page 578)

_Complex ( see page 578)

concept ( see page 576)

concept_map ( see page 576)

constexpr ( see page 576)

_Imaginary ( see page 578)

late_check ( see page 576)

nullptr ( see page 558)

requires ( see page 577)

restrict ( see page 579)

thread_local ( see page 577)

Type Trait Functions ( see page 472), such as __is_abstract, and so forth

3.1.3.3.8 Special Types


This section contains C++ Special Type keyword topics.

Keyword Topic
nullptr ( see page 558)

void ( see page 572)

3.1.3.3.9 Statement Keywords


This section contains C++ Statement keyword topics.

3 Keyword Topics
break ( see page 534)

case ( see page 535)

catch ( see page 536)

continue ( see page 540)

default ( see page 545)

584
3.1 C++ Reference RAD Studio C++ Language Guide

do ( see page 546)

__except ( see page 525)

__finally ( see page 550)

for ( see page 552)

goto ( see page 553)

return ( see page 562)

static_assert ( see page 565)

switch ( see page 567)

throw ( see page 569)

__try ( see page 529)

try ( see page 569)

while ( see page 574)

3.1.3.3.10 Storage Class Specifiers


This section contains C++ Storage Class Specifier keyword topics.

Keyword Topics
auto ( see page 533)

__declspec ( see page 523)

__declspec(dllexport) ( see page 540)

__declspec(dllimport) ( see page 541)

__declspec(naked) ( see page 541)

__declspec(noreturn) ( see page 541)

__declspec(nothrow) ( see page 542)

__declspec(novtable) ( see page 542)

__declspec(property) ( see page 543)

__declspec(selectany) ( see page 543)

__declspec(thread) ( see page 544)

__declspec(uuid(“ComObjectGUID”)) ( see page 544)

extern ( see page 549)

mutable ( see page 555) 3


register ( see page 561)

static ( see page 564)

typedef ( see page 540)

585
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.3.11 Type Specifiers (C++)


This section contains C++ Type Specifier keyword topics.

Keyword Topics
char ( see page 536)

case ( see page 535)

char16_t ( see page 537)

char32_t ( see page 537)

class ( see page 537)

decltype ( see page 545)

double ( see page 547)

enum ( see page 548)

float ( see page 552)

int ( see page 555)

long ( see page 555)

short ( see page 563)

signed ( see page 563)

struct ( see page 566)

union ( see page 571)

unsigned ( see page 571)

wchar_t ( see page 573)

3.1.3.4 Language Structure


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 other significant
units.

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

Enumerations ( see page 617) This section contains Enumeration topics.


Expressions ( see page 619) This section contains C++ Expression topics.
Functions ( see page 624) This section contains Function topics.
Operators Summary ( see page 635) This section contains Operator Summary topics.
Pointers ( see page 637) This section contains Pointer topics.
Postfix Expression Operators ( see page 642) This section contains Postfix Expression Operator topics.
Primary Expression Operators ( see page 644) This section contains Primary Expression Operator topics.
Statements ( see page 646) This section contains Statement topics.
Structures ( see page 649) This section contains Structure topics.
Unary Operators ( see page 656) This section contains C++ Unary Operator topics.
Unions ( see page 658) This section contains Union topics.

3.1.3.4.1 Binary Operators


This section contains Binary Operator topics.

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

3.1.3.4.1.1 Binary Operators


These are the binary operators in CodeGear C++:

Arithmetic Operator Description


+ Binary plus (add)
— Binary minus (subtract)
* Multiply
/ Divide
% Remainder (modulus)
3

Bitwise Operator Description


<< Shift left
>> Shift right
& Bitwise AND

587
C++ Language Guide RAD Studio 3.1 C++ Reference

^ Bitwise XOR (exclusive OR)


| Bitwise inclusive OR

Logical Operator Description


&& Logical AND

Assignment Operator Description


= Assignment
*= Assign product
/= Assign quotient
%= Assign remainder (modulus)
+= Assign sum
—= Assign difference
<<= Assign left shift
>>= Assign right shift
&= Assign bitwise AND
^= Assign bitwise XOR
|= Assign bitwise OR

Relational Operator Description


< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to
== Equal to
!= Not equal to

Component Selection Operator Description


. Direct component selector
3 -> Indirect component selector

Class Member Operator Description


:: Scope access/resolution
.* Dereference pointer to class member

588
3.1 C++ Reference RAD Studio C++ Language Guide

->* Dereference pointer to class member

Conditional Operator Description


?: Actually a ternary operator. For example: a ? x : y means "if a then x else y"

Comma Operator Description


, Evaluate

3.1.3.4.1.2 Bitwise Operators


Syntax
AND-expression & equality-expression
exclusive-OR-expr ^ AND-expression
inclusive-OR-expr exclusive-OR-expression
~cast-expression
shift-expression << additive-expression
shift-expression >> additive-expression
Remarks

Use the bitwise operators to modify the individual bits rather than the number.

Operator What it does


& bitwise AND; compares two bits and generates a 1 result if both bits are 1, otherwise it returns 0.
| bitwise inclusive OR; compares two bits and generates a 1 result if either or both bits are 1, otherwise it returns 0.
^ bitwise exclusive OR; compares two bits and generates a 1 result if the bits are complementary, otherwise it returns
0.
~ bitwise complement; inverts each bit. ~ is used to create destructors.
>> bitwise shift right; moves the bits to the right, discards the far right bit and if unsigned assigns 0 to the left most bit,
otherwise sign extends.
<< bitwise shift left; moves the bits to the left, it discards the far left bit and assigns 0 to the right most bit.

Both operands in a bitwise expression must be of an integral type.

A B A&B A^B A|B


0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
3
1 1 1 0 1

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

3.1.3.4.1.3 C++ Specific Operators


The operators specific to C++ are:

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.

3.1.3.4.1.4 Equality Operators


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
equality-expression:==!=
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression

3.1.3.4.1.5 Logical Operators


Syntax
logical-AND-expr && inclusive-OR-expression
logical-OR-expr || logical-AND-expression
! cast-expression
Remarks
3
Operands in a logical expression must be of scalar type.

&& 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).

3.1.3.4.1.6 >, <, >=, <= Relational Operators


Syntax
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
Considerations about Relational Operators
Use relational operators to test equality or inequality of expressions. If the statement evaluates to be true it returns a nonzero
character; otherwise it returns false (0).

Relational Operator Description


> greater than
< less than
>= greater than or equal to
<= less than or equal to

In the expression:
E1 <operator> E2
the operands must follow one of these conditions:

• Both E1 and E2 are of arithmetic type.


• Both E1 and E2 are pointers to qualified or unqualified versions of compatible types.
• Either E1 or E2 is a pointer to an object or incomplete type, and the other is a pointer to a qualified or unqualified version of
void.
• Either E1 or E2 is a pointer, and the other is a null pointer constant.

3.1.3.4.1.7 Assignment Operators


Syntax
unary-expr assignment-op assignment-expr
Remarks

The assignment operators are:


= *= /= %= += -=
<<= >>= &= ^= |=
The = operator is the only simple assignment operator, the others are compound assignment operators.

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.

The expression's value is E1 after the expression evaluates.

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:

• 1. E1 is a qualified or unqualified arithmetic type and E2 is an arithmetic type.


• 2. E1 has a qualified or unqualified version of a structure or union type compatible with the type of E2.
• 3. E1 and E2 are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all
the qualifiers of the type pointed to by the right.
• 4. Either E1 or E2 is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of
void. The type pointed to by the left has all the qualifiers of the type pointed to by the right.
• 5. E1 is a pointer and E2 is a null pointer constant.
Note: Spaces separating compound operators (+<space>=) will generate errors.
Note: There are certain conditions where assignment operators are not supported when used with properties.

3.1.3.4.1.8 Comma Operator


Syntax
expression , assignment-expression
Remarks

The comma separates elements in a function argument list.

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.

3.1.3.4.1.9 Conditional Operators


Syntax
logical-OR-expr ? expr : conditional-expr
Remarks

The conditional operator ?: is a ternary operator.

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.

3.1.3.4.1.10 Multiplicative Operators


Syntax
multiplicative-expr * cast-expr
multiplicative-expr / cast-expr
multiplicative-expr % cast-expr
Remarks

There are three multiplicative operators:

• * (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

• to determine the correct memory allocation requirements.


• to interpret the bit patterns found in the object during
subsequent... more ( see page 596)
Scope ( see page 597) 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... more ( see
page 597)
Storage Classes And Types ( see page 598) Associating identifiers with objects requires each identifier to have at least two
attributes: storage class and type (sometimes referred to as data type). The C++
compiler deduces these attributes from implicit or explicit declarations in the
source code.
Storage class dictates the location of the 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 syntax of the declaration, by its
placement in the source code, or by both of these factors.
The type determines how much memory is allocated to an... more ( see page
598)
Translation Units ( see page 599) The term translation unit refers to a source code file together with any included
files, but less any source lines omitted by conditional preprocessor directives.
Syntactically, a translation unit is defined as a sequence of external declarations:
Visibility ( see page 599) 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.
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... more ( see page 599)

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)

Objects ( see page 596)

Storage Classes And Types ( see page 598)

Scope ( see page 597)

Visibility ( see page 599)

Linkage ( see page 595)

The keyword static ( see page 564)

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.

External and internal linkage rules

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

linkage. In C, it will have internal linkage.

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.

Identifiers with no linkage attribute:

• 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)

Objects ( see page 596)

Storage Classes And Types ( see page 598)


3
Scope ( see page 597)

Visibility ( see page 599)

Duration ( see page 594)

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

• to determine the correct memory allocation requirements.


• to interpret the bit patterns found in the object during subsequent accesses.
• in many type-checking situations, to ensure that illegal assignments are trapped.
Borland's C++ compiler supports all standard data types, including signed and unsigned integers in various sizes, floating-point
numbers in various precisions, structures, unions, arrays, and classes. In addition, pointers to most of these objects can be
established and manipulated in memory.
Objects and declarations
Declarations establish the necessary mapping between identifiers and objects. Each declaration associates an identifier with a
data type. Most declarations, known as defining declarations, also establish the creation (where and when) of the object; that
is, the allocation of physical memory and its possible initialization. Other declarations, known as referencing declarations,
simply make their identifiers and types known to the compiler. There can be many referencing declarations for the same
identifier, especially in a multifile program, but only one defining declaration for that identifier is allowed.
Generally speaking, an identifier cannot be legally used in a program before its declaration point in the source code. Legal
exceptions to this rule (known as forward references) are labels, calls to undeclared functions, and class, struct, or union tags.
lvalues
An lvalue is an object locator: an expression that designates an object. An example of an lvalue expression is *P, where P is any
expression evaluating to a non-null pointer. A modifiable lvalue is an identifier or expression that relates to an object that can
be accessed and legally changed in memory. A const pointer to a constant, for example, is not a modifiable lvalue. A pointer
to a constant can be changed (but its dereferenced value cannot).
Historically, the l stood for "left," meaning that an lvalue could legally stand on the left (the receiving end) of an assignment
statement. Now only modifiable lvalues can legally stand to the left of an assignment statement. For example, if a and b are
nonconstant integer identifiers with properly allocated memory storage, they are both modifiable lvalues, and assignments
such as a = 1; and b = a + b are legal.
rvalues
The expression a + b is not an lvalue: a + b = a is illegal because the expression on the left is not related to an object. Such
expressions are often called rvalues (short for right values).
See Also
Declarations ( see page 593)

Storage Classes And Types ( see page 598)

Scope ( see page 597)

Visibility ( see page 599)

Duration ( see page 594)

Linkage ( see page 595)

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)

Objects ( see page 596)

Storage Classes And Types ( see page 598)

Visibility ( see page 599)

Duration ( see page 594)

Linkage ( see page 595)

3.1.3.4.2.5 Storage Classes And Types


Associating identifiers with objects requires each identifier to have at least two attributes: storage class and type (sometimes
referred to as data type). The C++ compiler deduces these attributes from implicit or explicit declarations in the source code.
3
Storage class dictates the location of the 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 syntax of the declaration, by its placement in the
source code, or by both of these factors.

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)

Objects ( see page 596)

Scope ( see page 597)

Visibility ( see page 599)

Duration ( see page 594)

Linkage ( see page 595)

3.1.3.4.2.6 Translation Units


The term translation unit refers to a source code file together with any included files, but less any source lines omitted by
conditional preprocessor directives. Syntactically, a translation unit is defined as a sequence of external declarations:
translation-unit:
external-declaration
translation-unit external-declaration
external-declaration
function-definition
declaration
word external has several connotations in C; here it refers to declarations made outside of any function, and which therefore
have file scope. (External linkage is a distinct property; see the section Linkage..) Any declaration that also reserves storage for
an object or function is called a definition (or defining declaration). For more details, see External declarations and definitions.

See Also
Declarations ( see page 593)

Objects ( see page 596)

Storage Classes And Types ( see page 598)

Scope ( see page 597)

Visibility ( see page 599)

Duration ( see page 594)

Linkage ( see page 595)

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

Objects ( see page 596)

Storage Classes And Types ( see page 598)

Scope ( see page 597)

Duration ( see page 594)

Linkage ( see page 595)

3.1.3.4.3 Declaration Syntax


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.

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:

• To zero if it is an arithmetic type


• To null if it is a pointer type
Note: If the object has automatic storage duration, its
value is indeterminate.
Syntax for initializers
Declaration and Declarators ( see page 612) A declaration is a list of names. The names are sometimes referred to as
declarators or identifiers. The declaration begins with optional storage class
specifiers, type specifiers, and other modifiers. The identifiers are separated by
commas and the list is terminated by a semicolon.
Simple declarations of variable identifiers have the following pattern:
Use of Storage Class Specifiers ( see page 614) Provides information on C++ storage class specifiers.
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.
The storage class specifiers in C++ are:

• auto ( see page 533)


• __declspec ( see page 523)
• extern ( see page 549)
• mutable ( see page 555)
• register ( see page 561)
• static ( see page 564)... more ( see page 614)
Variable Modifiers ( see page 614) In addition to the storage class specifier keywords, a declaration can use certain
modifiers to alter some aspect of the identifier. The modifiers available are 3
summarized in CodeGear C++ modifiers.
The following table summarizes the effects of a modifier applied to a called
function. For every modifier, the table shows the order in which the function
parameters are pushed on the stack. Next, the table shows whether the calling
program (the caller) or the called function (the callee) is responsible for popping
the parameters off the stack. Finally, the table shows the effect on the name of a
global function.... more ( see page 614)

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)

3.1.3.4.3.1 Tentative Definitions


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 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

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

Type Categories ( see page 608)


3
The Fundamental Types ( see page 609)

Initialization ( see page 611)

Declarations And Declarators ( see page 612)

Variable Modifiers ( see page 614)

Function Modifiers ( see page 616)

602
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.4.3.2 Possible Declarations


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
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

function-specifier: (C++ linkage-specification: (C++ specific)


specific)
inline extern string { <declaration-list> }
virtual extern string declaration
simple-type-name: type-specifier:
class-name simple-type-name
typedef-name class-specifier
boolean
char enum-specifier
short elaborated-type-specifier
int const
__int8
__int16
__int32
__int64
long volatile
signed declaration-list:
unsigned declaration
float declaration-list ; declaration
double
void
declarator-list: type-name:
init-declarator type-specifier <abstract-declarator>
declarator-list , abstract-declarator:
init-declarator
init-declarator: pointer-operator <abstract-declarator>
declarator <initializer> <abstract-declarator> ( argument-declaration-list )
declarator: <cv-qualifier-list>
dname <abstract-declarator> [ <constant-expression> ]
modifier-list ( abstract-declarator )
pointer-operator argument-declaration-list:
declarator
declarator ( <arg-declaration-list>
parameter-declaration-list
3 )
<cv-qualifier-list > arg-declaration-list , ...
(The <cv-qualifier-list > is <arg-declaration-list> ... (C++ specific)
for C++ only.)
declarator [ arg-declaration-list:
<constant-expression> ]
( declarator ) argument-declaration

604
3.1 C++ Reference RAD Studio C++ Language Guide

modifier-list: arg-declaration-list , argument-declaration


modifier argument-declaration:
modifier-list modifier decl-specifiers declarator
modifier: decl-specifiers declarator = expression
__cdecl (C++ specific)
__pascal decl-specifiers <abstract-declarator>
__stdcall decl-specifiers <abstract-declarator> = expression
__fastcall (C++ specific)
function-definition:
function-body:
pointer-operator: compound-statement

• <cv-qualifier-list> initializer:

& <cv-qualifier-list> (C++ = expression


specific)
class-name :: * = { initializer-list }
<cv-qualifier-list>
(C++ specific) ( expression-list ) (C++ specific)
cv-qualifier-list: initializer-list:
cv-qualifier expression
<cv-qualifier-list>
cv-qualifier initializer-list , expression
const { initializer-list <,> }
volatile
dname:
name
class-name (C++ specific)
~ class-name (C++
specific)
type-defined-name

See Also
Declaration Syntax

Tentative Definitions ( see page 602)

External Declarations And Definitions ( see page 606)


3
Type Categories ( see page 608)

The Fundamental Types ( see page 609)

Initialization ( see page 611)

Declarations And Declarators ( see page 612)

Variable Modifiers ( see page 614)

605
C++ Language Guide RAD Studio 3.1 C++ Reference

Function Modifiers ( see page 616)

3.1.3.4.3.3 External Declarations and Definitions


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, 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.

CodeGear C++ class declaration syntax (C++ only)

class-specifier: base-specifier:

class-head { <member-list> } : base-list

class-head: base-list:

class-key <identifier> <base-specifier> base-specifier

class-key class-name <base-specifier> base-list , base-specifier

member-list: base-specifier:

member-declaration <member-list> class-name

access-specifier : <member-list> virtual <access-specifier> class-name

member-declaration: access-specifier <virtual> class-name

<decl-specifiers> <member-declarator-list> ; access-specifier:

function-definition <;> private

qualified-name ; protected

3 member-declarator-list: public

member-declarator conversion-function-name:

member-declarator-list, member-declarator operator conversion-type-name

member-declarator: conversion-type-name:

declarator <pure-specifier> type-specifiers <pointer-operator>

<identifier> : constant-expression constructor-initializer:

606
3.1 C++ Reference RAD Studio C++ Language Guide

pure-specifier: : member-initializer-list

=0

member-initializer-list: operator-name: one of

member-initializer new delete sizeof typeid

member-initializer , member-initializer-list + - * / % ^

member-initializer: & | ~ ! = <>

class name ( <argument-list> ) += -= =* /= %= ^=

identifier ( <argument-list> ) &= |= << >> >>= <<=

operator-function-name: == != <= >= && ||

operator operator-name ++ __ , ->* -> ()

[ ] .*

See Also
Declaration Syntax ( see page 600)

Tentative Definitions ( see page 602)

Possible Declarations ( see page 603)

Type Categories ( see page 608)

The Fundamental Types ( see page 609)

Initialization ( see page 611)

Declarations And Declarators ( see page 612)

Variable Modifiers ( see page 614)

Function Modifiers ( see page 616)

3.1.3.4.3.4 Type Specifiers


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:
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:

char float signed


wchar_t
class int struct
double long union

607
C++ Language Guide RAD Studio 3.1 C++ Reference

enum short unsigned

Use the sizeof operators to find the size in bytes of any predefined or user-defined type.

3.1.3.4.3.5 Type Categories


Provides information on C++ type categories.

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)

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

The Fundamental Types ( see page 609)

Initialization ( see page 611)

608
3.1 C++ Reference RAD Studio C++ Language Guide

Declarations And Declarators ( see page 612)

Variable Modifiers ( see page 614)

Function Modifiers ( see page 616)

The keyword void ( see page 572)

3.1.3.4.3.6 The Fundamental Types


The fundamental type specifiers are built from the following keywords:

char __int8 long


double __int16 signed
float __int32 short
int __int64 unsigned

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

char, signed char Synonyms if default char set to


signed.
unsigned char
char, unsigned char Synonyms if default char set to
unsigned.
signed char
int, signed int
unsigned, unsigned int
short, short int, signed short int
unsigned short, unsigned short int
long, long int, signed long int
unsigned long, unsigned long int

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

Standard arithmetic conversions

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

Type Converts to Method


char int Zero or sign-extended (depends
on default char type)
unsigned char int Zero-filled high byte (always)

3 signed char int Sign-extended (always)


short int Same value; sign extended
unsigned short unsigned int Same value; zero filled
enum int Same value

Special char, int, and enum 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

Tentative Definitions ( see page 602)

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

Type Categories ( see page 608)

Initialization ( see page 611)

Declarations And Declarators ( see page 612)

Variable Modifiers ( see page 614)

Function Modifiers ( see page 616)

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:

• To zero if it is an arithmetic type


• To null if it is a pointer type
Note: If the object has automatic storage duration, its value is indeterminate.
Syntax for initializers
initializer
= expression
= {initializer-list} <,>}
(expression list)
initializer-list
expression
initializer-list, expression
{initializer-list} <,>}
Rules governing initializers

The number of initializers in the initializer list cannot be larger than the number of objects to be initialized.

The item to be initialized must be an object (for example, an array).

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

Tentative Definitions ( see page 602)

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

Type Categories ( see page 608)

The Fundamental Types ( see page 609)

Declarations And Declarators ( see page 612)


3
Variable Modifiers ( see page 614)

Function Modifiers ( see page 616)

3.1.3.4.3.8 Declaration and Declarators


A declaration is a list of names. The names are sometimes referred to as declarators or identifiers. The declaration begins with
optional storage class specifiers, type specifiers, and other modifiers. The identifiers are separated by commas and the list is

612
3.1 C++ Reference RAD Studio C++ Language Guide

terminated by a semicolon.

Simple declarations of variable identifiers have the following pattern:


data-type var1 <=init1>, var2 <=init2>, ...;
where var1, var2,... are any sequence of distinct identifiers with optional initializers. Each of the variables is declared to be of
type data-type. For example:
int x = 1, y = 2;
creates two integer variables called x and y (and initializes them to the values 1 and 2, respectively).

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:

Declaration syntax examples

Declarator syntax Implied type of name Example


type name; type int count;
type name[]; (open) array of type int count[];
type name[3]; Fixed array of three elements, int count[3] all (name[0], name[1], and name[2]
of type;
type *name; Pointer to type int *count;
type *name[]; (open) array of pointers to type int *count[];
type *(name[]); Same as above int *(count[]);
type (*name)[]; Pointer to an (open) array of type int (*count) [];
type &name; Reference to type (C++ only) int &count;
type name(); Function returning type int count();
type *name(); Function returning pointer to type int *count(); 3
type *(name()); Same as above int *(count());
type (*name)(); Pointer to function returning type int (*count) ();

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

Tentative Definitions ( see page 602)

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

Type Categories ( see page 608)

The Fundamental Types ( see page 609)

Initialization ( see page 611)

Variable Modifiers ( see page 614)

Function Modifiers ( see page 616)

3.1.3.4.3.9 Use of Storage Class Specifiers


Provides information on C++ storage class specifiers.

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.

The storage class specifiers in C++ are:

• auto ( see page 533)


• __declspec ( see page 523)
• extern ( see page 549)
• mutable ( see page 555)
• register ( see page 561)
• static ( see page 564)
• typedef ( see page 569)
See Also
Storage Class Specifier Keywords ( see page 585)

3.1.3.4.3.10 Variable Modifiers


In addition to the storage class specifier keywords, a declaration can use certain modifiers to alter some aspect of the identifier.
The modifiers available are summarized in CodeGear C++ modifiers.
3
The following table summarizes the effects of a modifier applied to a called function. For every modifier, the table shows the
order in which the function parameters are pushed on the stack. Next, the table shows whether the calling program (the caller) or
the called function (the callee) is responsible for popping the parameters off the stack. Finally, the table shows the effect on the
name of a global function.

Calling Conventions

614
3.1 C++ Reference RAD Studio C++ Language Guide

Modifier Push parameters Pop Name change (only in


parameters C)
__cdecl1 Right to left Caller '_' prepended
__fastcall Left to right Callee '@' prepended
__pascal Left to right Callee Uppercase
__stdcall Right to left Callee No change

1. This is the default.


Note: Note: __fastcall and __stdcall are always name mangled in C++. See the description of the -VC option in BCC32.

See Also
Declaration Syntax ( see page 600)

Tentative Definitions ( see page 602)

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

Type Categories ( see page 608)

The Fundamental Types ( see page 609)

Initialization ( see page 611)

Declarations And Declarators ( see page 612)

Function Modifiers ( see page 616)

Mixed-Language Calling Conventions ( see page 615)

The keyword const ( see page 538)

The keyword volatile ( see page 573)

3.1.3.4.3.11 Mixed-Language Calling Conventions


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
3
, which allows C names to be referenced from a C++ program.

Topics
Cdecl ( see page 536)

_fastcall ( see page 530)

Pascal ( see page 559)

615
C++ Language Guide RAD Studio 3.1 C++ Reference

_stdcall ( see page 531)

3.1.3.4.3.12 Multithread Variables


The following topic describes C++ multithread variables.

Topics
__thread ( see page 529)

3.1.3.4.3.13 Function Modifiers


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 an @. This prefix applies to both unmangled C function names and to mangled C++
function names.

CodeGear C++ modifiers

Modifier Use with Description


const1 Variables Prevents changes to object.
volatile1 Variables Prevents register allocation and some optimization. Warns
compiler that object might be subject to outside change during
evaluation.
__cdecl2 Functions Forces C argument-passing convention. Affects linker and
link-time names.
__cdecl2 Variables Forces global identifier case-sensitivity and leading underscores
in C.
__pascal Functions Forces Pascal argument-passing convention. Affects linker and
link-time names.
__pascal Variables Forces global identifier case-insensitivity with no leading
underscores in C.
__import Functions/classes Tells the compiler which functions or classes to import.
__export Functions/classes Tells the compiler which functions or classes to export.
__declspec(dllimport) Functions/classes Tells the compiler which functions or classes to import. This is the
preferred method.
3 __declspec(dllexport) Functions/classes Tells the compiler which functions or classes to export. This is the
preferred method.
__fastcall Functions Forces register parameter passing convention. Affects the linker
and link-time names.
__stdcall Function Forces the standard WIN32 argument-passing convention.

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

Tentative Definitions ( see page 602)

Possible Declarations ( see page 603)

External Declarations And Definitions ( see page 606)

Type Categories ( see page 608)

The Fundamental Types ( see page 609)

Initialization ( see page 611)

Declarations And Declarators ( see page 612)

Variable Modifiers ( see page 614)

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.

enum types can appear wherever int types are permitted.


enum days { sun, mon, tues, wed, thur, fri, sat } anyday;
enum days payday;
typedef enum days DAYS;
DAYS *daysptr;
int i = tues;
anyday = mon; // OK
*daysptr = anyday; // OK
mon = tues; // ILLEGAL: mon is a constant
Enumeration tags share the same name space as structure and union tags. Enumerators share the same name space as
ordinary variable identifiers:
int mon = 11;
{
enum days { sun, mon, tues, wed, thur, fri, sat } anyday;
/* enumerator mon hides outer declaration of int mon */
struct days { int i, j;}; // ILLEGAL: days duplicate tag
double sat; // ILLEGAL: redefinition of sat
}
mon = 12; // back in int mon scope
In C++, enumerators declared within a class are in the scope of that class.

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.

3.1.3.4.4.2 Assignment To Enum Types


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++).
3
Assigning an integer to a variable of enum type results in an error:
enum color
{
red, green, blue
};
int f()
{
color c;
c = 0;

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

3.1.3.4.5.1 Expressions (C++)


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 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.

CodeGear C++ expressions


primary-expression:
literal
this (C++ specific)
:: identifier (C++ specific)
:: operator-function-name (C++ specific)
:: qualified-name (C++ specific)
(expression)
name

teral:
integer-constant
character-constant
floating-constant
string-literal
name:
identifier
operator-function-name (C++ specific)
conversion-function-name (C++ specific)

~ class-name (C++ specific)


qualified-name (C++ specific)

qualified-name: (C++ specific)


qualified-class-name :: name
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression (<expression—list>)
simple-type-name (<expression-list>) (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

= *= /= %= += -=

<< => >= &= ^= |=


expression:
assignment-expression
expression , assignment-expression
constant-expression:
conditional-expression

3.1.3.4.5.2 Precedence Of Operators


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 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

3.1.3.4.5.3 Expressions And C++


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. 3
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++ allows user-defined conversions between class objects and fundamental types. Keep in mind, then, that some of the C
language rules for operators and conversions might not apply to expressions in C++.

623
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.4.5.4 Evaluation Order


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 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
i = v[i++]; // i is undefined
The value of i depends on whether i is incremented before or after the assignment. Similarly,
int total = 0;
sum = (total = 3) + (++total); // sum = 4 or sum = 7 ??
is ambiguous for sum and total. The solution is to revamp the expression, using a temporary variable:
int temp, total = 0;
temp = ++total;
sum = (total = 3) + temp;
Where the syntax does enforce an evaluation sequence, it is safe to have multiple evaluations:
sum = (i = 3, i++, i++); // OK: sum = 4, i = 5
Each subexpression of the comma expression is evaluated from left to right, and the whole expression evaluates to the rightmost
value

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.5.5 Errors And Overflows


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.

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:

• 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... more ( see page 635)

3.1.3.4.6.1 Declarations And Definitions


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.

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

Declarations And Prototypes ( see page 633)

Definitions ( see page 634) 3


Forma Parameter Declarations ( see page 635)

Function Calls And Argument Conversions ( see page 635)

625
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.4.6.2 The main() Function


Topics
Name Description
About The main() Function ( see page 627) Every C and C++ program must have a program-startup function.

• Console-based programs call the main function at startup.


• Windows GUI programs call the WinMain function at
startup.
Where you place the startup function is a matter of
preference. Some programmers place main at the
beginning of the file, others at the end. Regardless of its
location, the following points about main always apply.
• Arguments to main
• Wildcard arguments
• Using -p (Pascal Calling Conventions)
• The value that main() returns
Arguments to main() ( see page 628) Three parameters (arguments) are passed to main by the CodeGear C++Builder
startup routine: argc, argv, and env.

• 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...
more ( see page 628)
Default Runtime Libraries ( see page 628) 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).
Dynamic-link Libraries ( see page 629) The dynamic-link library (DLL) versions of the runtime library are contained in the
BIN subdirectory of your installation. These are listed below indicating whether
they are multithreaded.
Directory: BIN

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)

3.1.3.4.6.2.1 About The main() Function


Every C and C++ program must have a program-startup function. 3
• Console-based programs call the main function at startup.
• Windows GUI programs call the WinMain function at startup.
Where you place the startup function is a matter of preference. Some programmers place main at the beginning of the file, others
at the end. Regardless of its location, the following points about main always apply.
• Arguments to main
• Wildcard arguments

627
C++ Language Guide RAD Studio 3.1 C++ Reference

• Using -p (Pascal Calling Conventions)


• The value that main() returns
See Also
Arguments To Main ( see page 628)

Wildcard Arguments ( see page 632)

Using -p (Pascal Calling Conventions) ( see page 632)

The Value that main() Returns ( see page 632)

3.1.3.4.6.2.2 Arguments to main()


Three parameters (arguments) are passed to main by the CodeGear C++Builder startup routine: argc, argv, and env.

• 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.

Using main with a Unicode application


The Unicode version of the main function is:
int wmain (int argc, wchar_t *argv[])
The argv (and optional envp) parameter(s) support(s) wide-characters.

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

3.1.3.4.6.2.4 Dynamic-link Libraries


The dynamic-link library (DLL) versions of the runtime library are contained in the BIN subdirectory of your installation. These are
listed below indicating whether they are multithreaded.

Directory: BIN

File Name
CC3260.DLL 32-bit, single-threaded
CC3260MT.DLL 32-bit, multithreaded

See Also
The main() Function ( see page 627)

3.1.3.4.6.2.5 Multithread Programs


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 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)

_beginthread ( see page 976) 3


_beginthreadex ( see page 980)

_beginthreadNT ( see page 978)

_endthread ( see page 983)

_endthreadex ( see page 984)

_threadid ( see page 1005)

629
C++ Language Guide RAD Studio 3.1 C++ Reference

signal ( see page 1000)

3.1.3.4.6.2.6 Passing File Information To Child Processes


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 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)

execl ( see page 987)

spawnl ( see page 989)

3.1.3.4.6.2.7 Static Runtime Libraries


Listed below is each of the C++Builder static library names and its use.

Directory of BCB\LIB (LIB files)

File name Use


bcbatl.lib
bcbie.lib
bcbsmp.lib
cg32.lib CodeGuard library (link this in if you want to use CodeGuard)
cghelp.lib CodeGuard help library
cp32mt.lib VCL-compliant C RTL multithreaded static library
cp32mti.lib VCL-compliant import library for multithreaded C RTL cc3260mt.dll
cw32.lib RTL single-threaded static library
cw32i.lib Import library for RTL cc3260.dll
3 cw32mt.lib RTL multi-threaded static library
cw32mti.lib Import library for multithreaded RTL cc3260mt.dll
dbx.lib
dcl31w.lib
dclact.lib
dclado.lib

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

Directory of BCB\LIB (OBJ files)

File name Use


c0d32.obj DLL startup module 3
c0d32w.obj DLL startup module, Wide-char version
c0d32x.obj DLL startup module, no exception handling
c0pkg32.obj Package startup module
c0w32.obj GUI EXE startup module
c0w32w.obj GUI EXE startup module, Wide-char version

631
C++ Language Guide RAD Studio 3.1 C++ Reference

c0x32.obj 32-bit console-mode EXE startup module


c0x32w.obj 32-bit console-mode EXE startup module, Wide-char version
fileinfo.obj Passes open file-handle information to child processes
gp.obj Prints register-dump information when an exception occurs
wildargs.obj Transforms wild-card arguments into an array of arguments to main()/wmain() in console-mode
applications

(Lib\PSDK Subdirectory) Import libraries for the Platform SDK

See Also
The main() Function ( see page 627)

3.1.3.4.6.2.8 The Value main() Returns


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


exit(1)
the status is 1.
See Also
About the main() Function ( see page 627)

exit ( see page 1114)

_exit ( see page 1097)

3.1.3.4.6.2.9 Using --p (Pascal Calling Conventions)


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:
int __cdecl main(int argc, char* argv[], char
* envp[])
See Also
The main() Function ( see page 627)

3.1.3.4.6.2.10 Wildcard Arguments


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.


3
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 size of the argv array
varies, depending on the amount of memory available in your heap.

If no matching files are found, the argument is passed unchanged. (That is, a string consisting of the wildcard mask is passed to
main.)

Arguments enclosed in quotes ("...") are not expanded.

632
3.1 C++ Reference RAD Studio C++ Language Guide

See Also
About The Main Function ( see page 627)

3.1.3.4.6.3 Declarations And Prototypes


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 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

Here are some more examples of function declarators and prototypes:


int f();/* In C, a function returning an int with no information about parameters.
This is the K&R "classic style." */
int f();/* In C++, a function taking no arguments */
int f(void);/* A function returning an int that takes no parameters. */
int p(int,long);/* A function returning an int thataccepts two parameters: the first, an int;
the second, a long. */
int __pascal q(void);/* A pascal function returningan int that takes no parameters at all. */
int printf(char *format,...; /*A function returning an int andaccepting a pointer to a char
fixedparameter and any number of additionalparameters of unknown type. */
int (*fp)(int)/* A pointer to a function returning an intand requiring an int parameter. */

3.1.3.4.6.4 Definitions
The general syntax for external function definitions is as follows:

External function definitions


file
external-definition
file external-definition
external-definition:
function-definition
declaration
asm-statement
function-definition:
<declaration-specifiers> declarator <declaration-list>
compound-statement
In general, a function definition consists of the following sections (the grammar allows for more complicated cases):

• 1. Optional storage class specifiers: extern or static. The default is extern.


• 2. A return type, possibly void. The default is int.
• 3. Optional modifiers: __pascal, __cdecl, __export__saveregs. The defaults depend on the compiler option settings.
• 4. The name of the function.
• 5. A parameter declaration list, possibly empty, enclosed in parentheses. In C, the preferred way of showing an empty list is
func(void). The old style of func is legal in C but antiquated and possibly unsafe.
• 6. A function body representing the code to be executed when the function is called.
Note: You can mix elements from 1 and 2.

3.1.3.4.6.5 Extended Types Formatted I/O


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.

Format Character Functionality


%Ld __int64
%I8d 8–bit wide integer (char)
3
%I16d 16–bit wide integer (short)
%I32d 32–bit wide integer (long)
%I64d 64–bit wide integer (__int64)

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

3.1.3.4.6.6 Formal Parameter Declarations


The formal parameter declaration list follows a syntax similar to that of the declarators found in normal identifier declarations.
Here are a few examples:
int func(void) { // no args
int func(T1 t1, T2 t2, T3 t3=1) { // three simple parameters, one
// with default argument
int func(T1* ptr1, T2& tref) { // A pointer and a reference arg
int func(register int i) { // Request register for arg
int func(char *str,...) { /* One string arg with a variable number of other
args, or with a fixed number of args with varying types */
In C++, you can give default arguments as shown. Parameters with default values must be the last arguments in the parameter
list. The arguments' types can be scalars, structures, unions, or enumerations; pointers or references to structures and unions; or
pointers to functions, classes, or arrays.

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

3.1.3.4.6.7 Function Calls And Argument Conversions


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:

• 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.

3.1.3.4.7 Operators Summary


This section contains Operator Summary topics.

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:

• . C++ direct component selector


• .* C++ dereference
• :: C++ scope access/resolution
• ?: Conditional
Depending on context, the same operator can have more
than one meaning. For example, the ampersand (&) can
be interpreted as:
• a bitwise AND (A & B)
• an address operator (&A)
• in C++, a reference modifier
Note: No spaces are... more ( see page 636)

3.1.3.4.7.1 Operators Summary


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)


3
Equality ( see page 590)

Logical ( see page 590)

Postfix Expression Operators

Primary Expression Operators ( see page 645)

Preprocessor

636
3.1 C++ Reference RAD Studio C++ Language Guide

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:

• . C++ direct component selector


• .* C++ dereference
• :: C++ scope access/resolution
• ?: Conditional
Depending on context, the same operator can have more than one meaning. For example, the ampersand (&) can be interpreted
as:
• a bitwise AND (A & B)
• an address operator (&A)
• in C++, a reference modifier
Note: No spaces are allowed in compound operators. Spaces change the meaning of the operator and will generate an error.
See Also
Precedence Of Operators ( see page 622)

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

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 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 (j = 0; j < columns; ++j)


printf("%5.2Lf", matrix[i][j]);
de_allocate(matrix);
return 0;
}
void de_allocate(OBJECT x) {
int i;
for (i = 0; i < rows; i++) /* STEP 1: DELETE THE COLUMNS */
free(x[i]);
free(x); /* STEP 2: DELETE THE ROWS. */
}
This code produces the following output:
0.00 1.00 2.00 3.00 4.00
1.00 2.00 3.00 4.00 5.00
2.00 3.00 4.00 5.00 6.00
In certain contexts, the first array declarator of a series might have no expression inside the brackets. Such an array is of
indeterminate size. This is legitimate in contexts where the size of the array is not needed to reserve space.

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

3.1.3.4.8.2 C++ Reference Declarations


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.

3.1.3.4.8.3 Pointer Arithmetic


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.

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).

3.1.3.4.8.4 Pointer Constants


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:
int i; // i is an int
int * pi; // pi is a pointer to int (uninitialized)
int * const cp = &i; // cp is a constant pointer to int
const int ci = 7; // ci is a constant int
const int * pci; // pci is a pointer to constant int
const int * const cpc = &ci; // cpc is a constant pointer to a
// constant int
The following assignments are legal:
i = ci; // Assign const-int to int
*cp = ci; // Assign const-int to
// object-pointed-at-by-a-const-pointer
++pci; // Increment a pointer-to-const
pci = cpc; // Assign a const-pointer-to-a-const to a
// pointer-to-const
The following assignments are illegal:
ci = 0; // NO--cannot assign to a const-int
ci--; // NO--cannot change a const-int
*pci = 3; // NO--cannot assign to an object
// pointed at by pointer-to-const
cp = &ci; // NO--cannot assign to a const-pointer,
// even if value would be unchanged
cpc++; // NO--cannot change const-pointer
pi = pci; // NO--if this assignment were allowed,
// you would be able to assign to *pci
// (a const value) by assigning to *pi.
Similar rules apply to the volatile modifier. Note that const and volatile can both appear as modifiers to the same identifier.

3.1.3.4.8.5 Pointer Conversions


Pointer types can be converted to other pointer types using the typecasting mechanism:
3 char *str;
int *ip;
str = (char *)ip;
More generally, the cast (type*) will convert a pointer to type "pointer to type."

See C++ specific for a discussion of C++ typecast mechanisms.

640
3.1 C++ Reference RAD Studio C++ Language Guide

3.1.3.4.8.6 Pointer Declarations


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 before using them.

If type is any predefined or user-defined type, including void, the declaration


type *ptr; /* Uninitialized pointer */
declares ptr to be of type "pointer to type." All the scoping, duration, and visibility rules apply to the ptr object just declared.

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.

Note: See Referencing for a discussion of referencing and dereferencing.

See Also
Pointers To Objects ( see page 642)

Pointers To Functions ( see page 642)

Pointer Declarations ( see page 641) 3


Pointer Constants ( see page 640)

Pointer Arithmetic ( see page 639)

Pointer Conversions ( see page 640)

C++ Reference Declarations ( see page 639)

641
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.4.8.8 Pointers To Functions


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,
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.

3.1.3.4.8.9 Pointers To Objects


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.9 Postfix Expression Operators


This section contains Postfix Expression Operator topics.

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

3.1.3.4.9.1 . (direct Member Selector)


Syntax
postfix-expression . identifier
postfix-expression must be of type union or structure.

identifier must be the name of a member of that structure or union type.


3
Remarks

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

3.1.3.4.9.2 -> (indirect Member Selector)


Syntax
postfix-expression -> identifier
postfix-expression must be of type pointer to structure or pointer to union.

identifier must be the name of a member of that structure or union type.

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.

3.1.3.4.9.3 Array Subscript Operator


Brackets ([ ]) indicate single and multidimensional array subscripts. The expression
<exp1>[exp2]
is defined as
*((exp1) + (exp2))
where either:

• exp1 is a pointer and exp2 is an integer or


• exp1 is an integer and exp2 is a pointer

3.1.3.4.9.4 Increment/decrement Operators


Increment operator ( ++ )

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.

After the postfix expression is evaluated, the operand is incremented by 1.

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.

The increment value is appropriate to the type of the operand.

Pointer types follow the rules for pointer arithmetic.

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.

3.1.3.4.9.5 Function Call Operator


Syntax
postfix-expression(<arg-expression-list>)
Remarks

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.

3.1.3.4.10 Primary Expression Operators


This section contains Primary Expression Operator topics.

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:

1. literal this (C++ specific)


2. :: identifier (C++ specific)
3. :: operator-function-name (C++ specific)
4. :: qualified-name (C++ specific)
5. ( expression) name
literal:
1. integer-constantcharacter-constant
2. floating-constant
3. string-literal
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... more ( see page 645)

3.1.3.4.10.1 Primary Expression Operators


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:

1. literal this (C++ specific)


2. :: identifier (C++ specific)
3. :: operator-function-name (C++ specific)
4. :: qualified-name (C++ specific) 3
5. ( expression) name
literal:
1. integer-constantcharacter-constant
2. floating-constant
3. string-literal

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.

3.1.3.4.11.2 C++ Specifics


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 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)

C++ Classes ( see page 387)

Introduction To Constructors And Destructors ( see page 415) 3


Polymorphic Classes ( see page 447)

C++ Scope ( see page 430)

3.1.3.4.11.3 Expression Statements


Any expression followed by a semicolon forms an expression statement:

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.

3.1.3.4.11.4 Iteration Statements


Iteration statements let you loop a set of statements. There are three forms of iteration in C++: while, do while, and for loops.

3.1.3.4.11.5 Jump Statements


A jump statement, when executed, transfers control unconditionally. There are four such statements: break, continue, goto,
and return

3.1.3.4.11.6 Labeled Statements


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.

3.1.3.4.11.7 Selection Statements


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.

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.

CodeGear C++ 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

compound-statement: { <declaration-list> <statement-list> }


declaration-list: declaration
declaration-list declaration
statement-list: statement
statement-list statement
expression-statement: <expression> ;
asm-statement: asm tokens newline
asm tokens;
asm { tokens; <tokens;>= <tokens;>}
selection-statement: if ( expression ) statement
if ( expression ) statement else statement
switch ( expression ) statement
iteration-statement: while ( expression ) statement
do statement while ( expression ) ;
for (for-init-statement <expression> ; <expression>) statement
for-init-statement: expression-statement
declaration (C++ specific)
jump-statement: goto identifier ;
continue ;
break ;
return <expression> ;

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.

Structures are declared using the keyword struct. For example


struct mystruct { ... }; // mystruct is the structure tag
.
.
3 .
struct mystruct s, *ps, arrs[10];
/* s is type struct mystruct; ps is type pointer to struct mystruct;
arrs is array of struct mystruct. */

3.1.3.4.12.2 Untagged Structures And Typedefs


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

650
3.1 C++ Reference RAD Studio C++ Language Guide

this type elsewhere


struct { ... } s, *ps, arrs[10]; // untagged structure
It is possible to create a typedef while declaring a structure, with or without a tag:
typedef struct mystruct { ... } MYSTRUCT;
MYSTRUCT s, *ps, arrs[10]; // same as struct mystruct s, etc.
typedef struct { ... } YRSTRUCT; // no tag
YRSTRUCT y, *yp, arry[20];
Usually, you don't need both a tag and a typedef: either can be used in structure declarations.

Untagged structure and union members are ignored during initialization.

3.1.3.4.12.3 Structure Member Declarations


The member-decl-list within the braces declares the types and names of the structure members using the declarator syntax
shown in CodeGear C++ 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:
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.

Note: You can omit the struct

keyword in C++.

3.1.3.4.12.4 Structures And Functions


A function can return a structure type or a pointer to a structure type:
mystruct func1(void); // func1() returns a structure
mystruct *func2(void); // func2() returns pointer to structure
A structure can be passed as an argument to a function in the following ways:
void func1(mystruct s); // directly
void func2(mystruct *sptr); // via a pointer
void func3(mystruct &sref); // as a reference (C++ only)

3.1.3.4.12.5 Structure Member Access


Structure and union members are accessed using the following two selection operators:

• . (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 */

3.1.3.4.12.6 Structure Name Spaces


Structure tag names share the same name space with union tags and enumeration tags (but enums within a structure are in a
3 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. 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

3.1.3.4.12.7 Incomplete Declarations


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:
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.

3.1.3.4.12.8 Bit Fields


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:


type-specifier <bitfield-id> : width;
In C++, type-specifier is bool, char, unsigned char, short, unsigned short, long, unsigned long, int, unsigned int, __int64
or unsigned __int64. In strict ANSI C, type-specifier is int or unsigned int.

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

When using bit fields, be aware of the following issues:

• 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.

Padding of bit fields

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.

Layout and alignment

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.

Example of bit field layout, padding, and 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:

• Sort bit fields by type


• Make sure they are packed inside the areas by ordering them such that no bit field will straddle an area boundary
• Make sure the struct is filled as much as possible.
Another recommendation is to force byte alignment for this struct, by emitting "#pragma option -a1". If you want to know how big
your struct is, follow it by "#pragma sizeof(mystruct)", which gives you the size.
Using one bit signed fields
For a signed type of one bit, the possible values are 0 or –1. For an unsigned type of one bit, the possible values are 0 or 1. Note
that if you assign “1” to a signed bit field, the value will be evaluated as –1 (negative one).
When storing the values true and false into a one bit sized bit field of a signed type, you can not test for equality to true because
signed one bit sized bit fields can only hold the values '0' and '-1', which are not compatible with true and false. You can,
however, test for non-zero.
For unsigned varieties of all types, and of course for the bool type, testing for equality to true will work as expected.
Thus:
struct mystruct
{
int flag : 1;
} M;
int testing()
{
M.flag = true;
if(M.flag == true)
printf("success");}
will NOT work, but:
struct mystruct
{
int flag : 1;
} M;
int testing()
{
M.flag = true;
if(M.flag) 3
printf("success");
}
works just fine.

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.

3.1.3.4.13 Unary Operators


This section contains C++ Unary Operator topics.

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

3.1.3.4.13.1 Unary Operators


Syntax
<unary-operator> <unary expression>
OR
<unary-operator> <type><unary expression>
Remarks

Unary operators group right-to-left.

The C++ language provides the following unary operators:

• ! Logical negation
• * Indirection
• ++ Increment
• ~ Bitwise complement
• -- Decrement
• - Unary minus
• + Unary plus

3.1.3.4.13.2 Arithmetic Operators


Syntax
3 + cast-expression
- cast-expression
add-expression + multiplicative-expression
add-expression - multiplicative-expression
multiplicative-expr * cast-expr
multiplicative-expr / cast-expr
multiplicative-expr % cast-expr
postfix-expression ++ (postincrement)
++ unary-expression (preincrement)
postfix-expression -- (postdecrement)
-- unary-expression (predecrement)

656
3.1 C++ Reference RAD Studio C++ Language Guide

Remarks

Use the arithmetic operators to perform mathematical computations.

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.

3.1.3.4.13.3 Plus And Minus Operators


Unary

In these unary + - expressions


+ cast-expression
- cast-expression
the cast-expression operand must be of arithmetic type.

Results

• cast-expression Value of the operand after any required integral promotions.


• cast-expression Negative of the value of the operand after any required integral promotions.
Binary
Syntax
add-expression + multiplicative-expression
add-expression - multiplicative-expression
Legal operand types for op1 + op2:

• 1. Both op1 and op2 are of arithmetic type.


• 2. op1 is of integral type, and op2 is of pointer to object type.
• 3. op2 is of integral type, and op1 is of pointer to object type.
In case 1, the operands are subjected to the standard arithmetical conversions, and the result is the arithmetical sum of the
operands.
In cases 2 and 3, the rules of pointer arithmetic apply.
Legal operand types for op1 - op2:
• 1. Both op1 and op2 are of arithmetic type.
• 2. Both op1 and op2 are pointers to compatible object types.
• 3. op1 is of pointer to object type, and op2 is integral type. 3
In case 1, the operands are subjected to the standard arithmetic conversions, and the result is the arithmetic difference of the
operands.
In cases 2 and 3, the rules of pointer arithmetic apply.
Note: The unqualified type <type> is considered to be compatible with the qualified types const type, volatile type,and const
volatile type.

657
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.4.13.4 Reference/Deference Operators


Syntax
& cast-expression
* cast-expression
Remarks

The & and * operators work together to reference and dereference pointers that are passed to functions.

Referencing operator ( & )

Use the reference operator to pass the address of a pointer to a function outside of main().

The cast-expression operand must be one of the following:

• 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 of type pointer to function, the result is a function designator.

If the operand is a pointer to an object, the result is an lvalue designating that object.

The result of indirection is undefined if either of the following occur:

• 1. The cast-expression is a null pointer.


• 2. The cast-expression is the address of an automatic variable and execution of its block has terminated.
Note: & can also be the bitwise AND operator.
3 Note: * can also be the multiplication operator.

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=&mu;
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

Note: Unions correspond to the variant record types of Delphi.

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.

3.1.3.4.14.2 Anonymous Unions


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:

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.

C++ 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++.

Nested anonymous unions

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;
}

3.1.3.4.14.3 Union Declarations


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:
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.

3.1.3.5 Lexical Elements


This section contains Lexical Element topics.

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.

3.1.3.5.1 Lexical Elements


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 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)

Tokens ( see page 678)

3.1.3.5.2 Tokens Overview


This section contains Token topics.

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

3.1.3.5.2.1 Constants Overview


This section contains Constant topics.

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.

3.1.3.5.2.1.1 Character Constants Overview


3
This section contains Character 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.

• Three char types ( see page 666)


• Escape sequences ( see page 664)
• Wide-character and multi-character constants ( see
page 666)
Note: To compare sizes of character types, compile this
as a C program and then as a C++ program.

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:

3.1.3.5.2.1.1.1 Character Constants


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.

• Three char types ( see page 666)


• Escape sequences ( see page 664)
• Wide-character and multi-character constants ( see page 666)
Note: To compare sizes of character types, compile this as a C program and then as a C++ program.

#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

Note: Sizes are in bytes.

Sizes of character types

Output when compiled as C program Output when compiled as C++ program


Sizeof int = 4 Sizeof int = 4
Sizeof char = 1 Sizeof char = 1
Sizeof ch = 1 Sizeof ch = 1
Sizeof CH = 4 Sizeof CH = 1
Sizeof wchar_t = 2 Sizeof wchar_t = 2

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

3.1.3.5.2.1.1.2 Escape Sequences


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
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".

To avoid such problems, rewrite your code like this:


printf("\x007" "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.

The following table shows the available escape sequences.

Escape sequences

Note: You must use \\ to represent an ASCII backslash, as used in operating system paths.

Sequence Value Char What it does

\a 0x07 BEL Audible bell


\b 0x08 BS Backspace
\f 0x0C FF Formfeed
\n 0x0A LF Newline (linefeed)
\r 0x0D CR Carriage return
\t 0x09 HT Tab (horizontal)
\v 0x0B VT Vertical tab
\\ 0x5c \ Backslash
\' 0x27 ' Single quote (apostrophe)
\" 0x22 " Double quote
\? 0x3F ? Question mark
\O any O=a string of up to three octal digits
\xH any H=a string of hex digits
\XH any H=a string of hex digits

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)


3
Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

665
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.5.2.1.1.3 The Three Char Types


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 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)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

3.1.3.5.2.1.1.4 Wide-character And Multi-character Constants


3
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:
wchar_t ch = L'A';
When wchar_t is used in a C program it is a type defined in stddef.h header file. In a C++ program, wchar_t is a keyword that
can represent distinct codes for any element of the largest extended character set in any of the supported locales. In CodeGear
C++, wchar_t is the same size, signedness, and alignment requirement as an unsigned short type.

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)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

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.

Constants: Formal Definitions

constant: nonzero-digit: one of


floating-constant 123456789
integer-constant
numeration-constant
character-constant 3
floating-constant: octal-digit: one of
fractional-constant <exponent-part> <floating-suffix> 01234567
digit-sequence exponent-part <floating-suffix>
fractional-constant: hexadecimal-digit: one of
<digit-sequence> . digit-sequence 0123456789
digit-sequence . a b c d e f ABCDEF

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

digit-sequence: long-suffix: one of


digit lL
digit-sequence digit
floating-suffix: one of enumeration-constant:
flFL identifier
integer-constant: character-constant
decimal-constant <integer-suffix> c-char-sequence
octal-constant <integer-suffix>
hexadecimal-constant <integer-suffix>
decimal-constant: c-char-sequence:
nonzero-digit c-char
decimal-constant digit c-char-sequence c-char
octal-constant: c-char:
0 Any character in the source character set
octal-constant octal-digit except the single-quote ('), backslash (\), or
newline character escape-sequence.
hexadecimal-constant: escape-sequence: one of the following
0 x hexadecimal-digit \" \' \? \\
0 X hexadecimal-digi t \a \b \f \n
hexadecimal-constant hexadecimal-digit \o \oo \ooo \r
\t \v \Xh... \xh...

See Also
Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)


3 String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

668
3.1 C++ Reference RAD Studio C++ Language Guide

__int8 ( see page 526)

3.1.3.5.2.1.3 Integer Constant Without L Or U


Decimal constants

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

0x0000 to 0x7FFF int


0x8000 to 0xFFFF unsigned int
0x10000 to 0x7FFFFFFF long
0x80000000 to 0xFFFFFFFF unsigned long
>0xFFFFFFFF truncated

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673) 3


Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

__int8 ( see page 526)

669
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.5.2.1.4 Constant Expressions


This section contains Constant Expression topics.

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:

3.1.3.5.2.1.4.1 Constant Expressions


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:
constant-expression:
Conditional-expression
Constant expressions cannot contain any of the following operators, unless the operators are contained within the operand of a
sizeof operator:

• Assignment
• Comma
• Decrement
• Function call
• Increment
See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

3 Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

3.1.3.5.2.1.5 Constants and Internal Representation


This section contains Constants and Internal Representation topics.

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

3.1.3.5.2.1.5.1 Constants And Internal Representation


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

Type Size Range Sample applications


(bits)

unsigned char 8 0 <= X <= 255 Small numbers and full PC


character set
char 8 -128 <= X <= 127 Very small numbers and ASCII
characters
short int 16 -32,768 <= X <= 32,767 Counting, small numbers, loop
control
unsigned int 32 0 <= X <= 4,294,967,295 Large numbers and loops
int 32 -2,147,483,648 <= X <= Counting, small numbers, loop
2,147,483,647 control
unsigned long 32 0 <= X <= 4,294,967,295 Astronomical distances
enum 32 -2,147,483,648 <= X <= Ordered sets of values
2,147,483,647
long 32 -2,147,483,648 <= X <= Large numbers, populations
2,147,483,647
float 32 1.18 ( 10^-38 < |X| < 3.40 ( 10^38 Scientific (7-digit) precision)
double 64 2.23 ( 10^-308 < |X| < 1.79 ( 10^308 Scientific (15-digit precision)
long double 80 3.37 ( 10^-4932 < |X| < 1.18 ( 10^4932 Financial (18-digit precision) 3

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

671
C++ Language Guide RAD Studio 3.1 C++ Reference

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

__int8 ( see page 526)

The Three Char Types ( see page 666)

Internal Representation Of Numerical Types ( see page 676)

3.1.3.5.2.1.6 Floating Point Constants


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:

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.

Floating-point constant sizes and ranges

672
3.1 C++ Reference RAD Studio C++ Language Guide

Type Size Range


(bits)
float 32 3.4 ( 10^-38 to 3.4 ( 10^38
double 64 1.7 ( 10^-308 to 1.7 ( 10^308
long double 80 3.4 ( 10^-4932 to 1.1 ( 10^4932

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

3.1.3.5.2.1.7 Enumeration Constants


This section contains Enumeration Constant topics.

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,

3.1.3.5.2.1.7.1 Enumeration Constants


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 3
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,
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

giants = 0, cubs = 1, dodgers = 2


in the absence of explicit initializers. In the following example,
enum team { giants, cubs=3, dodgers = giants + 1 };
the constants are set as follows:
giants = 0, cubs = 3, dodgers = 1
The constant values need not be unique:
enum team { giants, cubs = 1, dodgers = cubs - 1 };
See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

3.1.3.5.2.1.8 Integer Constants


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,
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.

long and unsigned suffixes

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:

Decimal int, long int, unsigned long int


Octal int, unsigned int, long int, unsigned long int
Hexadecimal int, unsigned int, long int, unsigned long int

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)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

__int8 ( see page 526)

3.1.3.5.2.1.9 Internal Representation of Numerical Types


This section contains Internal Representation of Numerical Type topics.

675
C++ Language Guide RAD Studio 3.1 C++ Reference

Topics
Name Description
Internal Representation Of Numerical Types ( see page 676) 32-bit integers

Floating-point types, always

3.1.3.5.2.1.9.1 Internal Representation Of Numerical Types


32-bit integers

Floating-point types, always

3 s = Sign bit ( 0 = positive, 1 = negative) Exponent bias (normalized values):


i = Position of implicit binary point float: 127 (7FH)
1 = Integer bit of significance: double: 1,023 (3FFH)
Stored in long double long double: 16,383 (3FFFH)
Implicit in float, double

676
3.1 C++ Reference RAD Studio C++ Language Guide

See Also
Constants ( see page 667)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

String Constants ( see page 677)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Constant Expressions ( see page 670)

3.1.3.5.2.1.10 String Constants


This section contains String Constant topics.

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:

3.1.3.5.2.1.10.1 String Constants


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:
"This is literally a string!"
The null (empty) string is written "".

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)

Integer Constants ( see page 674)

Integer Constant Without L Or U ( see page 669)

Floating Point Constants ( see page 672)

Character Constants ( see page 663)

The Three Char Types ( see page 666)

Escape Sequences ( see page 664)

Wide-character And Multi-character Constants ( see page 666)

Enumeration Constants ( see page 673)

Constants And Internal Representation ( see page 671)

Internal Representation Of Numerical Types ( see page 676)

Constant Expressions ( see page 670)

3.1.3.5.2.2 Tokens
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
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)

Whitespace ( see page 686)

3.1.3.5.2.3 Identifiers Overview


This section contains Identifier topics.

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.

3.1.3.5.2.4 Keywords Overview


This section contains Keyword topics.

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)

Keywords By Category ( see page 579)

3.1.3.5.2.4.2 Keyword Extensions


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.

See Also
C++Builder Keyword Extensions ( see page 580)

Keywords ( see page 513)

Keywords By Category ( see page 579)

3.1.3.5.2.4.3 C++-Specific Keywords


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.

See Also
Alphabetical Listing of Keywords ( see page 513)

Keywords By Category ( see page 579)

3.1.3.5.2.4.4 Table Of CodeGear C++ Register Pseudovariables


This table lists all pseudovariables.

_AH _CL _EAX _ESP


_AL _CS _EBP _FLAGS
_AX _CX _EBX _FS
_BH _DH _ECX _GS
_BL _DI _EDI _SI
_BP _DL _EDX _SP
_BX _DS _ES _SS
_CH _DX _ESI

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.

3.1.3.5.2.5 Punctuators Overview


This section contains Punctuator topics.

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

func();/* function call, no args */


int (*fptr)();/* function pointer declaration */
fptr = func;/* no () means func pointer */
void func2(int n);/* function declaration with parameters */
Parentheses are recommended in macro definitions to avoid potential precedence problems during expansion:
#define CUBE(x) ((x) * (x) * (x))
The use of parentheses to alter the normal operator precedence and associativity rules is covered in Expressions.

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 comma (,) separates the elements of a function argument list:


void func(int n, float f, char ch);
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. Note that (exp1, exp2) evaluates both but is equal to the second:
func(i, j); /* call func with two args */
func((exp1, exp2), (exp3, exp4, exp5)); /* also calls func with two args! */
Semicolon

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.

In C++, you can omit the comma before the ellipsis.

Asterisk (pointer declaration)

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

/* int /* declaration */ i /* counter */; */


fails, because the scope of the first /* ends at the first */. This gives
i ; */
which would generate a syntax error.

To allow nested comments, check Project|Options|Advanced Compiler|Source|Nested Comments.

Delimiters and whitespace

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)

Whitespace ( see page 686)

Tokens ( see page 678)

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

Line splicing with \

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)

Tokens ( see page 678)

3.1.3.6 The Preprocessor


This section contains Preprocessor topics.

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.

3.1.3.6.1 Conditional Compilation Overview


This section contains Conditional Compilation Overview 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

3.1.3.6.1.1 Conditional Compilation 3


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.

687
C++ Language Guide RAD Studio 3.1 C++ Reference

3.1.3.6.1.2 #if, #elif, #else, And #endif


Syntax
#if constant-expression-1
<section-1>
<#elif constant-expression-2 newline section-2>
.
.
.
<#elif constant-expression-n newline section-n>
<#else <newline> final-section>
#endif
Description

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.

The constant expressions to be tested must evaluate to a constant integral value.

See Also
defined ( see page 689)

#ifdef And #ifndef ( see page 688)

3.1.3.6.1.3 #ifdef And #ifndef


Syntax
3 #ifdef identifier
#ifndef identifier
Description

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

has exactly the same effect as


#if 1
if identifier is currently defined, and the same effect as
#if 0
if identifier is currently undefined.

#ifndef tests true for the "not-defined" condition, so the line


#ifndef identifier
has exactly the same effect as
#if 0
if identifier is currently defined, and the same effect as
#if 1
if identifier is currently undefined.

The syntax thereafter follows that of the #if, #elif, #else, and #endif.

An identifier defined as NULL is considered to be defined.

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).

Defined performs the same function as #ifdef.


#if defined(mysym)
is the same as
#ifdef mysym
The advantage is that you can use defined repeatedly in a complex expression following the #if directive; for example,
#if defined(mysym) && !defined(yoursym)
See Also
#ifdef And #ifndef ( see page 688)
3
3.1.3.6.2 Defining And Undefining Macros
This section contains Defining And Undefining Macro topics.

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

3.1.3.6.2.1 Using The -D And -U Command-line Options


Identifiers can be defined and undefined using the command-line compiler options -D and -U.

The command line


BCC32 -Ddebug=1; paradox=0; X -Umysym myprog.cbc++ -Ddebug=1:paradox=0:X -Umysym myprog.c
bc++ -Ddebug=1:paradox=0:X -Umysym myprog.c
is equivalent to placing
#define debug 1
#define paradox 0
in the program.

See Also
#define ( see page 690)

3.1.3.6.2.2 Keywords And Protected Words In Macros


It is legal but ill-advised to use C++ keywords as macro identifiers:
#define int long /* legal but probably catastrophic */
#define INT long /* legal and possibly useful */
The following predefined global identifiers cannot appear immediately following a #define or #undef directive:

• __DATE__ __FILE__ __LINE__


• __STDC__ __TIME__

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

restrictions to macro expansion:

• 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)

Macros With Parameters ( see page 694)

#undef ( see page 691)

Using The -D And -U Command-line Options ( 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)

3.1.3.6.3 The #error Control Directive


This section contains #error Control Directive topics.

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

The #error directive generates the message:


Error: filename line# : Error directive: errmsg
This directive is usually embedded in a preprocessor conditional statement that catches some undesired compile-time condition.
In the normal case, that condition will be false. If the condition is true, you want the compiler to print an error message and stop
the compile. You do this by putting an #error directive within a conditional statement that is true for the undesired case.

3.1.3.6.4 File Inclusion With #include


This section contains File Inclusion With #include topics.

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:

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

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)

Header File Search with “header_name” ( see page 693)

3.1.3.6.4.2 Header File Search With <header_name>


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.

See Also
Header File Search With "header_name" ( see page 693)

3.1.3.6.4.3 Header File Search With "header_name"


The "header_name" version specifies a user-supplied include file; the file is searched in the following order:

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)

3.1.3.6.5 The #line Control Directive


This section contains #line Control Directive topics.

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.

3.1.3.6.6 Macros With Parameters Overview


This section contains Macros With Parameters Overview topics.

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.

3.1.3.6.6.1 Macros With Parameters


The following syntax is used to define a macro with parameters:
#define macro_identifier(<arg_list>) token_sequence
Any comma within parentheses in an argument list is treated as part of the argument, not as an argument delimiter.

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.

Such macros are called by writing


macro_identifier<whitespace>(<actual_arg_list>)
in the subsequent source code. The syntax is identical to that of a function call; indeed, many standard library C "functions" are
implemented as macros. However, there are some important semantic differences, side effects, and potential pitfalls.

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)

Nesting Parentheses And Commas ( see page 695)

Side Effects And Other Dangers ( see page 696)

Using The Backslash (\) For Line Continuation ( see page 695)

3.1.3.6.6.2 Nesting Parentheses And Commas


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.
#define ERRMSG(x, str) showerr("Error:", x. str)
#define SUM(x,y) ((x) + (y))
:
ERRMSG(2, "Press Enter, then ESC");
/* showerr("Error",2,"Press Enter, then ESC"); */
return SUM(f(i, j), g(k, l));
/* return ( (f(i, j)) + (g(k, l)) ); */

3.1.3.6.6.3 Token Pasting With ##


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


#define VAR(i, j) (i##j)
the call VAR(x, 6) expands to (x6). This replaces the older nonportable method of using (i/**/j).

3.1.3.6.6.4 Converting To Strings With #


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:


#define TRACE(flag) printf(#flag "=%d\n", flag)
the code fragment
int highval = 1024;
TRACE(highval);
becomes
int highval = 1024;
printf("highval" "=%d\n", highval);
which, in turn, is treated as 3
int highval = 1024;
printf("highval=%d\n", highval);

3.1.3.6.6.5 Using The Backslash (\) For Line Continuation


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.

695
C++ Language Guide RAD Studio 3.1 C++ Reference

#define WARN "This is really a single-\


line warning."

3.1.3.6.6.6 Side Effects And Other Dangers


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.


int cube(int x) {
return x* x*x;

3.1.3.6.7 Pragma Directives Overview


This section contains Pragma Directives Overview topics.

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)

#pragma anon_struct ( see page 698)

#pragma argsused ( see page 699)

#pragma checkoption ( see page 699)

#pragma codeseg ( see page 699)

#pragma comment ( see page 699)

#pragma defineonoption ( see page 700)


3
#pragma exit ( see page 700)

#pragma hdrfile ( see page 700)

#pragma hdrstop ( see page 701)

#pragma inline ( see page 701)

#pragma intrinsic ( see page 701)

697
C++ Language Guide RAD Studio 3.1 C++ Reference

#pragma link ( see page 701)

#pragma message ( see page 702)

#pragma nopushoptwarn ( see page 702)

#pragma obsolete ( see page 702)

#pragma option ( see page 702)

#pragma pack ( see page 704)

#pragma package ( see page 706)

#pragma region/end_region ( see page 707)

#pragma resource ( see page 707)

#pragma startup ( see page 700)

#pragma undefineonoption ( see page 700)

#pragma warn ( see page 707)

3.1.3.6.7.2 #pragma alignment


Syntax
#pragma alignment
Description

This pragma prints out the current byte alignment and enum size.

For instance, the pragma


#pragma alignment
might print out this:

The alignment is 4 bytes, the enum size is 4 bytes

3.1.3.6.7.3 #pragma anon_struct


Syntax
#pragma anon_struct on
#pragma anon_struct off
Description

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.
}

3.1.3.6.7.4 #pragma argsused


Syntax
#pragma argsused
Description

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"

3.1.3.6.7.5 #pragma checkoption


Syntax
#pragma checkoption <switches>
where <switches> are any command line switches.

Description

This pragma checks a set of options.

For instance, the following pragma


#pragma checkoption -w- -Vx
checks if the options -w- and -Vx are active. If not, you get the error:

Error E2471 filename: pragma checkoption failed: options are not as expected

3.1.3.6.7.6 #pragma codeseg


Syntax
#pragma codeseg <seg_name> <"seg_class"> <group>
Description

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.

3.1.3.6.7.7 #pragma comment


Syntax
#pragma comment (comment type, "string")
3
Description

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.

3.1.3.6.7.8 #pragma defineonoption and #pragma undefineonoption


Syntax
#pragma defineonoption <macroname>
<switches>
#pragma undefineonoption <macroname>
<switches>
where <macroname> is a name to define or undefine, and <switches> are any command line switches.

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.

For instance, the following pragma


#pragma defineonoption DEBUG -v
results in the macro DEBUG being defined when the option -v is set.

In contrast, this pragma


#pragma undefineonoption DEBUG -v
results in the macro DEBUG being undefined when the option -v is set.

3.1.3.6.7.9 #pragma exit and #pragma startup


Syntax
#pragma startup function-name <priority>
#pragma exit function-name <priority>
Description

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.

3.1.3.6.7.10 #pragma hdrfile


Syntax

700
3.1 C++ Reference RAD Studio C++ Language Guide

#pragma hdrfile "filename.csm"


Description

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.

3.1.3.6.7.11 #pragma hdrstop


Syntax
#pragma hdrstop
Description

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.

3.1.3.6.7.12 #pragma inline


Syntax
#pragma inline
Description

This directive is equivalent to the -B command-line compiler option.

This is best placed at the top of the file, because the compiler restarts itself with the -B option when it encounters #pragma
inline.

3.1.3.6.7.13 #pragma intrinsic


Syntax
#pragma intrinsic [-]function-name
Description
3
Use #pragma intrinsic to override command-line switches or project options to control the inlining of functions.

When inlining an intrinsic function, always include a prototype for that function before using it.

3.1.3.6.7.14 #pragma link


Syntax
#pragma link "[path]modulename[.ext]"

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.

By default, the linker assumes a .obj extension.

3.1.3.6.7.15 #pragma message


Syntax
#pragma message ("text" ["text"["text" ...]])
#pragma message text
Description

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.

User-defined messages are displayed as messages, not warnings.

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)

3.1.3.6.7.16 #pragma nopushoptwarn


Syntax
#pragma nopushoptwarn
Description

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

pragma. The warning states that the identifier is obsolete.

3.1.3.6.7.18 #pragma option


Syntax
#pragma option options
#pragma option push options
#pragma option pop
#pragma nopushoptwarn
Description

Use #pragma option to include command-line options within your program code. #pragma option can also be used with the
push or pop arguments.

#pragma option [options...]

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.

Options that cannot appear in a pragma option include:

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.

#pragma option using push or pop

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.

The following generates a warning about an empty stack:


#pragma option push
#pragma option pop
#pragma option pop /* Warning */
We do not recommend it, but you can turn off this warning with the directive: #pragma warn -nop.

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 .

3.1.3.6.7.19 #pragma pack


Syntax

704
3.1 C++ Reference RAD Studio C++ Language Guide

#pragma pack([{push | pop}[,]] [identifier[,]] [n])


Description

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.

#pragma pack #pragma option


#pragma pack(n) #pragma option -an
#pragma pack(push, n) #pragma option push -an
#pragma pack(pop) #pragma option pop

The #pragma pack directive also supports an identifier argument which must be used in combination with either push or pop.

#pragma pack with no arguments


#pragma pack()
Using #pragma pack with no arguments will set the packing size to the starting –aX alignment (which defaults to 8). The starting
-aX alignment is considered the alignment at the start of the compile AFTER all command-line options have been processed.

#pragma pack using a value for n


#pragma pack(8)
Using #pragma pack with a value for 'n' will set the current alignment to 'n'. Valid alignments for ‘n’ are: 1,2,4,8, and 16.

#pragma pack using push


#pragma pack(push)
Using #pragma pack with push will push the current alignment on an internal stack of alignments.

#pragma pack using push, identifier


#pragma pack(push, ident)
Using #pragma pack with push and an identifier will associate the pushed alignment with 'identifier'.

#pragma pack using push and n


#pragma pack(push, 8)
#pragma pack(push, ident, 8)
Using #pragma pack with push with a value for 'n', will execute pragma pack push or pragma pack push identifier, and
afterwards set the current alignment to 'n'.

#pragma pack using pop


#pragma pack(pop)
Using #pragma pack with pop will pop the alignment stack and set the alignment to the last alignment pushed. If the pop does
not find a corresponding push, the entire stack of alignments is popped, and a warning is issued, and the alignment reverts to the 3
starting -aX alignment..

#pragma pack using pop, identifier


#pragma pop(pop, ident)
Using #pragma pack with pop and an identifier will pop the stack until the identifier is found and set the alignment to the
alignment pushed by the previous corresponding #pragma pack(push, identifier). If the pop with identifier does not find the
corresponding push with an identifier, the entire stack of alignments is popped, and a warning is issued to the user:

705
C++ Language Guide RAD Studio 3.1 C++ Reference

W8083: Pragma pack pop with no matching pack push


The alignment will then be reset to the starting -aX alignment.

#pragma pack using pop and n


#pragma pack(pop, 8)
#pragma pack(pop, ident, 8)
Using #pragma pack with pop and a value for 'n', will execute pragma pack pop or pragma pack pop identifier. Afterwards the
current alignment is set to 'n', unless pop fails to find a corresponding push, in which case 'n' is ignored, a warning is issued, and
the alignment reverts to the starting -aX alignment.

Error conditions

Specifying an 'identifier' without push or pop is an error.

Specifying an alignment different from 1,2,4,8,16 is an error.

Warning conditions

Using #pragma pop without a corresponding push issues a warning.

3.1.3.6.7.20 #pragma package


Syntax
#pragma package(smart_init)
#pragma package(smart_init, weak)
Description: smart_init argument

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)

3.1.3.6.7.21 #pragma region and #pragma end_region


Syntax
#pragma region <name> #pragma end_region
Description

These two pragmas allow the program to specify a region that can be collapsed and expanded, similar to the facility
automatically provided for functions.

Use these pragmas by enclosing the code section as follows:


#pragma region name code to be collapsed/expanded ... #pragma
end_region
The name is optional.

3.1.3.6.7.22 #pragma resource


Syntax
#pragma resource "*.xdfm"
Description

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;

3.1.3.6.7.23 #pragma warn


Syntax
#pragma warn [+|-|.]xxx
Description
3
The warn pragma lets you override specific -wxxx command-line options or check Display Warnings. xxx is the three-letter or
four-digit message identifier used by the command-line option.
+ turns on a warning while - disables the warning. The '.' restores a warning to the setting in Project Options.

3.1.3.6.8 Predefined Macros Overview


This section contains Predefined Macros Overview topics.

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.

3.1.3.6.8.1 Predefined Macros


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.

Macro Value Description


__BCOPT__ 1 Defined only in compilers that support optimization, therefore
always defined.
__BCPLUSPLUS__ • 0x0570 for BDS 2006 Defined if you've selected C++ compilation; will increase in
later releases.
• 0x0590 for C++Builder
2007
• 0x0591 for update 1 to
C++Builder 2007
• 0x0592 for RAD Studio
2007
• 0x0593 for the December
update to RAD Studio
2007
• 0x0610 for C++Builder
2009 and for C++Builder
2009 Update 1

__BOOL__ 1 Indicates that the bool keyword is accepted.


__BORLANDC__ • 0x0570 for BDS 2006 Version number.

• 0x0590 for C++Builder


2007
• 0x0591 for update 1 to
C++Builder 2007
• 0x0592 for RAD Studio
2007
3 • 0x0593 for the December
update to RAD Studio
2007
• 0x0610 for C++Builder
2009 and for C++Builder
2009 Update 1

__CDECL__ 1 Defined if Calling Convention is set to cdecl; otherwise


undefined.

708
3.1 C++ Reference RAD Studio C++ Language Guide

_CHAR_UNSIGNED 1 Undefined by default. Using the -K switch to make the default


character unsigned causes this macro to be defined.
Ultimately, the -K option controls how a char is extended
when converted to an int. By default, the compiler
sign-extends, but if you enable _CHAR_UNSIGNED_, then
the compiler zero-extends characters when converting to int.
__CODEGEARC__ 0x0610 for C++Builder 2009 Version number.
__CODEGUARD__ Defined whenever one of the CodeGuard compiler options is
used; otherwise it is undefined.
__CONSOLE__ 1 When defined, the macro indicates that the program is a
console application.
_CPPUNWIND 1 Enable stack unwinding. This is true by default; use
-xd-!ALink(OSCGExceptions1) to disable.
__cplusplus 1 Defined if in C++ mode; otherwise, undefined.
__DATE__ String literal Date when processing began on the current file.
__DLL__ 1 Defined whenever the -WD compiler option is used;
otherwise it is undefined.
__FILE__ String literal Name of the current file being processed.
__FLAT__ 1 Defined when compiling in 32-bit flat memory model.
__FUNC__ String literal Name of the current function being processed. More details.
__LINE__ Decimal constant Number of the current source file line being processed.
_M_IX86 0x12c Always defined. The default value is 300. You can change
the value to 400 or 500 by using the /4 or /5 compiler options.
__MT__ 1 Defined only if the -tWM option is used. It specifies that the
multithread library is to be linked.
__PASCAL__ 1 Defined if Calling Convention is set to Pascal; otherwise
undefined.
_PUSHPOP_SUPPORTED 1 Always defined; allows Microsoft standard headers to use
push and pop to verify whether a feature is supported.
_STDCALL_SUPPORTED 1 Always defined; defines the Microsoft stdcall calling
convention.
__STDC__ 1 Defined if you compile with the -A compiler option; otherwise,
it is undefined.
__TCPLUSPLUS__ 0x0570 Version number.
0x0610 for C++Builder 2009
__TEMPLATES__ 1 Defined as 1 for C++ files (meaning that templates are
supported); otherwise, it is undefined.
__TIME__ String literal Time when processing began on the current file.
__TLS__ 1 Thread Local Storage. Always true. 3

709
C++ Language Guide RAD Studio 3.1 C++ Reference

__TURBOC__ • 0x0570 for BDS 2006 Will increase in later releases.

• 0x0590 for C++Builder


2007
• 0x0591 for update 1 to
C++Builder 2007
• 0x0592 for RAD Studio
2007
• 0x0593 for the December
update to RAD Studio
2007
• 0x0610 for C++Builder
2009 and for C++Builder
2009 Update 1

_WCHAR_T Defined only for C++ programs to indicate that wchar_t is an


intrinsically defined data type.
_WCHAR_T_DEFINED Defined only for C++ programs to indicate that wchar_t is an
intrinsically defined data type.
_Windows 1 Defined when compiling on the Windows platform.
__WIN32__ 1 Defined for console and GUI applications on the Windows
platform.

Note: The predefined macros __DATE__

, __FILE__ , __FUNC__, __LINE__, __STDC__, and __TIME__ cannot be redefined or undefined.

See Also
Side Effects And Other Dangers ( see page 696)

Using The Backslash (\) For Line Continuation ( see page 695)

Converting To Strings With # ( see page 695)

3.1.3.6.9 Preprocessor Directives


This section contains C++ Preprocessor Directive topics.

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

# (null directive) #ifdef ( see page 688)


#define ( see page 690) #ifndef ( see page 688)
#elif ( see page 688) #undef ( see page 691)
#else ( see page 688) #include ( see page 692)
#endif ( see page 688) #line ( see page 693)
#error ( see page 692) #pragma ( see page 696)
#if ( see page 688) #import ( see page 692)

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).

3.1.3.6.9.2 # (null Directive)


Syntax
#
Description

The null directive consists of a line containing the single character #. This line is always ignored.

3.1.4 C Runtime Library Reference


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
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

_heapmin ( see page 717) Header File


malloc.h
Category
Memory Routines
Prototype
int _heapmin(void);
Description
Release unused heap areas.
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
_heapmin returns 0 if it is successful, or -1 if an error occurs.
Portability
_heapset ( see page 717) Header File
malloc.h
Category
Memory Routines
Prototype
int _heapset(unsigned int fillvalue);
Description
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
One of the following values:
_msize ( see page 720) Header File
malloc.h
Category
Memory Routines
Prototype
size_t _msize(void *block);
Description
Returns the size of a heap block.
_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
_msize returns the size of the block in bytes.
Example
_rtl_heapwalk ( see page 720) Header File
malloc.h
Category
Memory Routines
Prototype
int _rtl_heapwalk(_HEAPINFO *hi);
Description
Inspects the heap node by node.
Note: This function replaces _heapwalk which is obsolete.
_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 3
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... more ( see page 720)

713
C Runtime Library Reference RAD Studio 3.1 C++ Reference

calloc ( see page 721) Header File


alloc.h, stdlib.h
Category
Memory Routines
Prototype
void *calloc(size_t nitems, size_t size);
Description
Allocates main memory.
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.
calloc allocates a block of size nitems * size. The block is initialized to 0.
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
free ( see page 722) Header File
alloc.h, stdlib.h
Category
Memory Routines
Prototype
void free(void *block);
Description
Frees allocated block.
free deallocates a memory block allocated by a previous call to calloc, malloc, or
realloc.
Return Value
None.
Example
heapcheck ( see page 723) Header File
alloc.h
Category
Memory Routines
Prototype
int heapcheck(void);
Description
Checks and verifies the heap.
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:
heapcheckfree ( see page 724) Header File
alloc.h
Category
Memory Routines
Prototype
int heapcheckfree(unsigned int fillvalue);
Description
Checks the free blocks on the heap for a constant value.
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:

714
3.1 C++ Reference RAD Studio C Runtime Library Reference

heapchecknode ( see page 725) Header File


alloc.h
Category
Memory Routines
Prototype
int heapchecknode(void *node);
Description
Checks and verifies a single node on the heap.
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
One of the following values:
heapfillfree ( see page 726) Header File
alloc.h
Category
Memory Routines
Prototype
int heapfillfree(unsigned int fillvalue);
Description
Fills the free blocks on the heap with a constant value.
Return Value
One of the following values:
heapwalk ( see page 727) Header File
alloc.h
Category
Memory Routines
Prototype
int heapwalk(struct heapinfo *hi);
Description
heapwalk is used to “walk” through the heap, node by node.
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... more
( see page 727)
malloc ( see page 728) 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... more ( see page 728)
3

715
C Runtime Library Reference RAD Studio 3.1 C++ Reference

realloc ( see page 729) Header File


alloc.h, stdlib.h
Category
Memory Routines
Prototype
void *realloc(void *block, size_t size);
Description
Reallocates main memory.
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... more ( see page
729)
stackavail ( see page 729) Header File
malloc.h
Category
Memory Routines
Prototype
size_t stackavail(void);
Description
Gets the amount of available stack memory.
stackavail returns the number of bytes available on the stack. This is the amount
of dynamic memory that alloca can access.
Return Value
stackavail returns a size_t value indicating the number of bytes available.
Example

3.1.4.1.1 _heapchk
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:


3
_HEAPBADNODE A corrupted heap block has been found
_HEAPEMPTY No heap exists
_HEAPOK The heap appears to be uncorrupted

Portability

716
3.1 C++ Reference RAD Studio C Runtime Library Reference

POSIX Win32 ANSI C ANSI C++


+

3.1.4.1.2 _heapmin
Header File

malloc.h

Category

Memory Routines

Prototype
int _heapmin(void);

Description

Release unused heap areas.

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

_heapmin returns 0 if it is successful, or -1 if an error occurs.

Portability

POSIX Win32 ANSI C ANSI C++


+

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

One of the following values:

717
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_HEAPOK The heap appears to be uncorrupted


_HEAPEMPTY No heap exists
_HEAPBADNODE A corrupted heap block has been found

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

WS_OVERLAPPEDWINDOW, // Window style.


CW_USEDEFAULT, // Default horizontal position.
CW_USEDEFAULT, // Default vertical position.
CW_USEDEFAULT, // Default width.
CW_USEDEFAULT, // Default height.
NULL, // Overlapped windows have no parent.
NULL, // Use the window class menu.
hInstance, // This instance owns this window.
NULL // Pointer not needed.
);
/* If window could not be created, return "failure" */
if (!hWnd)
return (FALSE);
/* Make the window visible; update its client area; and return "success" */
ShowWindow(hWnd, nCmdShow); // Show the window
UpdateWindow(hWnd); // Sends WM_PAINT message
return (hWnd); // Returns the value from PostQuitMessage
}
void ExampleHeapSet(HWND hWnd)
{
int hsts;
char *buffer;
if ( (buffer = (char *)malloc( 1 )) == NULL )
exit(0);
hsts = _heapset( 'Z' );
switch (hsts)
{
case _HEAPOK:
MessageBox(hWnd,"Heap is OK","Heap",MB_OK|MB_ICONINFORMATION);
break;
case _HEAPEMPTY:
MessageBox(hWnd,"Heap is empty","Heap",MB_OK|MB_ICONINFORMATION);
break;
case _HEAPBADNODE:
MessageBox(hWnd,"Bad node in heap","Heap",MB_OK|MB_ICONINFORMATION);
break;
default:
break;
}
free (buffer);
}
#pragma argsused
LRESULT FAR PASCAL _export MainWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CREATE:
{
//Example _heapset
ExampleHeapSet(hWnd);
return NULL;
}
case WM_QUIT:
case WM_DESTROY: // message: window being destroyed
PostQuitMessage(0);
break;
default: // Passes it on if unprocessed 3
return (DefWindowProc(hWnd, message, wParam, lParam));
}
}
Portability

POSIX Win32 ANSI C ANSI C++


+

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

Returns the size of a heap block.

_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

_msize returns the size of the block in bytes.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.1.5 _rtl_heapwalk
Header File

malloc.h

Category
3 Memory Routines

Prototype
int _rtl_heapwalk(_HEAPINFO *hi);

Description

Inspects the heap node by node.

Note: This function replaces _heapwalk which is obsolete.

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.

hi._size holds the size of the block in bytes.


hi._useflag is a flag that is set to _USEDENTRY if the block is currently in use. If the block is free, hi._useflag is
set to _FREEENTRY.

Return Value

This function returns one of the following values:

_HEAPBADNODE A corrupted heap block has been found


_HEAPBADPTR The _pentry field does not point to a valid heap block
_HEAPEMPTY No heap exists
_HEAPEND The end of the heap has been reached
_HEAPOK The _heapinfo block contains valid information about the next heap block

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

Allocates main memory.

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.

calloc allocates a block of size nitems * size. The block is initialized to 0.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

Frees allocated block.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.1.8 heapcheck
Header File

alloc.h

Category

Memory Routines

Prototype
int heapcheck(void);

Description

Checks and verifies the heap.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.1.9 heapcheckfree
Header File

alloc.h

Category

Memory Routines

Prototype
int heapcheckfree(unsigned int fillvalue);

Description

Checks the free blocks on the heap for a constant value.

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:

_BADVALUE A value other than the fill value was found


_HEAPCORRUPT Heap has been corrupted
_HEAPEMPTY No heap
_HEAPOK Heap is accurate

3
Portability

POSIX Win32 ANSI C ANSI C++


+

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

Checks and verifies a single node on the heap.

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

One of the following values:

_BADNODE Node could not be found


_FREEENTRY Node is a free block
_HEAPCORRUPT Heap has been corrupted
_HEAPEMPTY No heap
_USEDENTRY Node is a used block

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

printf( "Free entry.\n" );


break;
case _USEDENTRY:
printf( "Used entry.\n" );
break;
default:
printf( "Unknown return code.\n" );
break;
}
}
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.1.11 heapfillfree
Header File

alloc.h

Category

Memory Routines

Prototype
int heapfillfree(unsigned int fillvalue);

Description

Fills the free blocks on the heap with a constant value.

Return Value

One of the following values:

_HEAPCORRUPT Heap has been corrupted


_HEAPEMPTY No heap
_HEAPOK Heap is accurate

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

printf( "Heap corrupted.\n" );


return 1;
}
for( i = 1; i < NUM_PTRS; i += 2 )
memset( array[ i ], 0, NUM_BYTES );
res = heapcheckfree( 1 );
if( res < 0 )
switch( res )
{
case _HEAPCORRUPT:
printf( "Heap corrupted.\n" );
return 1;
case _BADVALUE:
printf( "Bad value in free space.\n" );
return 1;
default:
printf( "Unknown error.\n" );
return 1;
}
printf( "Test successful.\n" );
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.1.12 heapwalk
Header File

alloc.h

Category

Memory Routines

Prototype
int heapwalk(struct heapinfo *hi);

Description

heapwalk is used to “walk” through the heap, node by node.

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

One of the following values:

_HEAPEMPTY No heap exists


_HEAPEND The end of the heap has been reached
_HEAPOK The heapinfo block contains valid information about the next heap block

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

Reallocates main memory.

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 block cannot be reallocated, realloc returns NULL.

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

POSIX Win32 ANSI C ANSI C++ 3


+ + + +

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

Gets the amount of available stack memory.

stackavail returns the number of bytes available on the stack. This is the amount of dynamic memory that alloca can access.

Return Value

stackavail returns a size_t value indicating the number of bytes available.

Example
#include <malloc.h>
#include <stdio.h>

int main(void)
{
char *buf;

printf("\nThe stack: %u\tstack pointer: %u", stackavail(), _SP);


buf = (char *) alloca(100 * sizeof(char));
printf("\nNow, the stack: %u\tstack pointer: %u", stackavail(), _SP);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

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 ( see page 731) Header File


assert.h
Category
Diagnostic Routines
Prototype
void assert(int test);
Description
Tests a condition and possibly aborts.
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:
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... more ( see page 731)

3.1.4.2.1 NDEBUG #define


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.

3.1.4.2.2 assert
Header File

assert.h

Category

Diagnostic Routines

Prototype
void assert(int test);

Description

Tests a condition and possibly aborts.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

clreol ( see page 742) Header File


conio.h
Category
Console I/O Routines
Prototype
void clreol(void);
Description
Clears to end of line in text window.
clreol clears all characters from the cursor position to the end of the line within
the current text window, without moving the cursor.
Note: This function should not be used in Win32 GUI applications.
Return Value
None.
Example
clrscr ( see page 743) Header File
conio.h
Category
Console I/O Routines
Prototype
void clrscr(void);
Description
Clears the text-mode window.
clrscr clears the current text window and places the cursor in the upper left corner
(at position 1,1).
Note: Do not use this function in Win32 GUI applications.
Return Value
None.
Example
cprintf ( see page 744) Header File
conio.h
Category
Console I/O Routines
Prototype
int cprintf(const char *format[, argument, ...]);
Description
Writes formatted output to the screen.
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.
For details details on format specifiers, see printf Format Specifiers.
The string is written either directly to screen memory or by way of a BIOS call,
depending on the value of the global... more ( see page 744)
cputs ( see page 745) Header File
conio.h
Category
Console I/O Routines
Prototype
int cputs(const char *str);
Description
Writes a string to the screen.
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 3
does not translate linefeed characters (\n) into carriage-return/linefeed character
pairs (\r\n).
Note: Do not use this function in Win32 GUI applications.
Return Value
cputs returns the last character printed.
Example

733
C Runtime Library Reference RAD Studio 3.1 C++ Reference

cscanf ( see page 746) Header File


conio.h
Category
Console I/O Routines
Prototype
int cscanf(char *format[, address, ...]);
Description
Scans and formats input from the console.
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.... more ( see page
746)
delline ( see page 747) Header File
conio.h
Category
Console I/O Routines
Prototype
void delline(void);
Description
Deletes line in text window.
delline deletes the line containing the cursor and moves all lines below it one line
up. delline operates within the currently active text window.
Note: Do not use this function in Win32 GUI applications.
Return Value
None.
Example
getch ( see page 747) Header File
conio.h
Category
Console I/O Routines
Prototype
int getch(void);
Description
Gets character from keyboard, does not echo to screen.
getch reads a single character directly from the keyboard, without echoing to the
screen.
Note: Do not use this function in Win32 GUI applications.
Return Value
getch returns the character read from the keyboard.
Example
getche ( see page 748) Header File
conio.h
Category
Console I/O Routines
Prototype
int getche(void);
Description
Gets character from the keyboard, echoes to screen.
getche reads a single character from the keyboard and echoes it to the current
text window using direct video or BIOS.
Note: Do not use this function in Win32 GUI applications.
3 Return Value
getche returns the character read from the keyboard.
Example

734
3.1 C++ Reference RAD Studio C Runtime Library Reference

getpass ( see page 749) Header File


conio.h
Category
Console I/O Routines
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).
Note: Do not use this function in Win32 GUI applications.
Return Value
The return value is a pointer to a static string that is overwritten with each call.
Example
gettext ( see page 750) Header File
conio.h
Category
Console I/O Routines
Prototype
int gettext(int left, int top, int right, int bottom, void
*destin);
Description
Copies text from text mode screen to memory.
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... more ( see page 750)
gettextinfo ( see page 751) Header File
conio.h
Category
Console I/O Routines
Prototype
void gettextinfo(struct text_info *r);
Description
Gets text mode video information.
gettextinfo fills in the text_info structure pointed to by r with the current text video
information.
The text_info structure is defined in conio.h as follows:
struct text_info {
unsigned char winleft; /* left window coordinate */
unsigned char wintop; /* top window coordinate */
unsigned char winright; /* right window coordinate */
unsigned char winbottom; /* bottom window coordinate */
unsigned char attribute; /* text attribute */
unsigned char normattr; /* normal attribute */
unsigned char currmode; /* BW40, BW80, C40, C80,... more
( see page 751)

735
C Runtime Library Reference RAD Studio 3.1 C++ Reference

gotoxy ( see page 752) Header File


conio.h
Category
Console I/O Routines
Prototype
void gotoxy(int x, int y);
Description
Positions cursor in text window.
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.
Note:Do not use this function in Win32 GUI applications.
Return Value
None.
Example
highvideo ( see page 752) Header File
conio.h
Category
Console I/O Routines
Prototype
void highvideo(void);
Description
Selects high-intensity characters.
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.
Note: Do not use this function in Win32 GUI applications.
Return Value
None.
Example
insline ( see page 753) Header File
conio.h
Category
Console I/O Routines
Prototype
void insline(void);
Description
Inserts a blank line in the text window.
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.
Note: Do not use this function in Win32 GUI applications.
Return Value
None.
Example
kbhit ( see page 754) Header File
conio.h
Category
Console I/O Routines
Prototype
int kbhit(void);
3 Description
Checks for currently available keystrokes.
kbhit checks to see if a keystroke is currently available. Any available keystrokes
can be retrieved with getch or getche.
Note: Do not use this function in Win32 GUI applications.
Return Value
If a keystroke is available, kbhit returns a nonzero value. Otherwise, it returns 0.
Example

736
3.1 C++ Reference RAD Studio C Runtime Library Reference

lowvideo ( see page 755) Header File


conio.h
Category
Console I/O Routines
Prototype
void lowvideo(void);
Description
Selects low-intensity characters.
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.
Note: Do not use this function in Win32 GUI applications.
Return Value
None.
Example
movetext ( see page 755) Header File
conio.h
Category
Console I/O Routines
Prototype
int movetext(int left, int top, int right, int bottom, int
destleft, int desttop);
Description
Copies text onscreen from one rectangle to another.
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.
movetext is a text mode function performing direct video output.
Note:Do not use this function in Win32 GUI applications.
Return Value
On success, movetext... more ( see page 755)
normvideo ( see page 756) Header File
conio.h
Category
Console I/O Routines
Prototype
void normvideo(void);
Description
Selects normal-intensity characters.
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.
Note: Do not use this function in Win32 GUI applications.
Return Value
None.
Example

737
C Runtime Library Reference RAD Studio 3.1 C++ Reference

putch ( see page 757) Header File


conio.h
Category
Console I/O Routines
Prototype
int putch(int c);
Description
Outputs character to screen.
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.
Note: This function should not be used in Win32 GUI applications.
Return Value
On success, putch returns the character printed, c. On error, it returns EOF....
more ( see page 757)
puttext ( see page 758) Header File
conio.h
Category
Console I/O Routines
Prototype
int puttext(int left, int top, int right, int bottom, void
*source);
Description
Copies text from memory to the text mode screen.
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... more ( see
page 758)
textattr ( see page 759) Header File
conio.h
Category
Console I/O Routines
Prototype
void textattr(int newattr);
Description
Sets text attributes.
Note: Do not use this function in Win32 GUI applications.
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.
The color information is encoded in the newattr parameter as follows:
In this 8-bit newattr parameter:

• bits 0-3 contain the 4-bit... more ( see page 759)

738
3.1 C++ Reference RAD Studio C Runtime Library Reference

textbackground ( see page 760) Header File


conio.h
Category
Console I/O Routines
Prototype
void textbackground(int newcolor);
Description
Selects new text background color.
Note: Do not use this function in Win32 GUI applications.
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... more ( see page 760)
textcolor ( see page 761) Header File
conio.h
Category
Console I/O Routines
Prototype
void textcolor(int newcolor);
Description
Selects new character color in text mode.
Note: Do not use this function in Win32 GUI applications.
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... more ( see page 761)
textmode ( see page 762) Header File
conio.h
Category
Console I/O Routines
Prototype
void textmode(int newmode);
Description
Puts screen in text mode.
Note: Do not use this function in Win32 GUI applications.
textmode selects a specific text mode.
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.
ungetch ( see page 764) Header File
conio.h
Category
Console I/O Routines
Prototype
int ungetch(int ch);
Description
Pushes a character back to the keyboard buffer.
Note: Do not use this function in Win32 GUI applications. 3
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
On success, ungetch returns the character ch.
On error, it returns EOF.
Example

739
C Runtime Library Reference RAD Studio 3.1 C++ Reference

wherex ( see page 764) Header File


conio.h
Category
Console I/O Routines
Prototype
int wherex(void);
Description
Gives horizontal cursor position within window.
Note: Do not use this function in Win32 GUI applications.
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
wherey ( see page 765) Header File
conio.h
Category
Console I/O Routines
Prototype
int wherey(void);
Description
Gives vertical cursor position within window.
Note: Do not use this function in Win32 GUI applications.
wherey returns the y-coordinate of the current cursor position (within the current
text window).
Return Value
wherey returns an integer in the range 1 to the number of rows in the current
video mode.
Portability
window ( see page 766) Header File
conio.h
Category
Console I/O Routines
Prototype
void window(int left, int top, int right, int bottom);
Description
Defines active text mode window.
Note: Do not use this function in Win32 GUI applications.
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... more ( see page 766)

3.1.4.3.1 _setcursortype
Header File

conio.h

Category
3
Console I/O Routines

Prototype
void _setcursortype(int cur_t);

Description

Selects cursor appearance.

740
3.1 C++ Reference RAD Studio C Runtime Library Reference

Sets the cursor type to

_NOCURSOR Turns off the cursor


_NORMALCURSOR Normal underscore cursor
_SOLIDCURSOR Solid block cursor

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.2 cgets
Header File 3
conio.h

Category

Console I/O Routines

Prototype
char *cgets(char *str);

741
C Runtime Library Reference RAD Studio 3.1 C++ Reference

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.

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.

Note: Do not use this function for Win32 GUI applications.

Return Value

On success, cgets returns a pointer to str[2].

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.3 clreol
Header File
3 conio.h

Category

Console I/O Routines

Prototype
void clreol(void);

Description

742
3.1 C++ Reference RAD Studio C Runtime Library Reference

Clears to end of line in text window.

clreol clears all characters from the cursor position to the end of the line within the current text window, without moving the cursor.

Note: This function should not be used in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.4 clrscr
Header File

conio.h

Category

Console I/O Routines

Prototype
void clrscr(void);

Description

Clears the text-mode window.

clrscr clears the current text window and places the cursor in the upper left corner (at position 1,1).

Note: Do not use this function in Win32 GUI applications.

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

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


cprintf("%d\r\n", i);
cprintf("\r\nPress any key to clear screen");
getch();
clrscr();
cprintf("The screen has been cleared!");
getch();
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.5 cprintf
Header File

conio.h

Category

Console I/O Routines

Prototype
int cprintf(const char *format[, argument, ...]);

Description

Writes formatted output to the screen.

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.

For details details on format specifiers, see printf Format Specifiers.

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.

Note: Do not use this function in Win32 GUI applications.

Return Value

cprintf returns the number of characters output.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.6 cputs
Header File

conio.h

Category

Console I/O Routines

Prototype
int cputs(const char *str);

Description

Writes a string to the screen.

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).

Note: Do not use this function in Win32 GUI applications.

Return Value

cputs returns the last character printed.

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

POSIX Win32 ANSI C ANSI C++


+

745
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.3.7 cscanf
Header File

conio.h

Category

Console I/O Routines

Prototype
int cscanf(char *format[, address, ...]);

Description

Scans and formats input from the console.

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.

Note: For details on format specifiers, see scanf Format Specifiers.

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.

Note: Do not use this function in Win32 GUI applications.

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.

If cscanf attempts to read at end-of-file , the return value is EOF.

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

POSIX Win32 ANSI C ANSI C++


+

746
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.3.8 delline
Header File

conio.h

Category

Console I/O Routines

Prototype
void delline(void);

Description

Deletes line in text window.

delline deletes the line containing the cursor and moves all lines below it one line up. delline operates within the currently active
text window.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.9 getch
Header File 3
conio.h

Category

Console I/O Routines

Prototype
int getch(void);

747
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Description

Gets character from keyboard, does not echo to screen.

getch reads a single character directly from the keyboard, without echoing to the screen.

Note: Do not use this function in Win32 GUI applications.

Return Value

getch returns the character read from the keyboard.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.10 getche
Header File

conio.h

Category

Console I/O Routines

Prototype
int getche(void);

Description

Gets character from the keyboard, echoes to screen.

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

getche returns the character read from the keyboard.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.11 getpass
Header File

conio.h

Category

Console I/O Routines

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).

Note: Do not use this function in Win32 GUI applications.

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;

password = getpass("Input a password:");


cprintf("The password is: %s\r\n", password);
return 0;
}
Portability 3

POSIX Win32 ANSI C ANSI C++


+

749
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.3.12 gettext
Header File

conio.h

Category

Console I/O Routines

Prototype
int gettext(int left, int top, int right, int bottom, void *destin);

Description

Copies text from text mode screen to memory.

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

bytes = (h rows) x (w columns) x 2

Note: Do not use this function in Win32 GUI applications.

Return Value

gettext returns 1 if the operation succeeds.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.13 gettextinfo
Header File

conio.h

Category

Console I/O Routines

Prototype
void gettextinfo(struct text_info *r);

Description

Gets text mode video information.

gettextinfo fills in the text_info structure pointed to by r with the current text video information.

The text_info structure is defined in conio.h as follows:


struct text_info {
unsigned char winleft; /* left window coordinate */
unsigned char wintop; /* top window coordinate */
unsigned char winright; /* right window coordinate */
unsigned char winbottom; /* bottom window coordinate */
unsigned char attribute; /* text attribute */
unsigned char normattr; /* normal attribute */
unsigned char currmode; /* BW40, BW80, C40, C80, or C4350 */
unsigned char screenheight; /* text screen's height */
unsigned char screenwidth; /* text screen's width */
unsigned char curx; /* x-coordinate in current window */
unsigned char cury; /* y-coordinate in current window */
};

Note: Do not use this function in Win32 GUI applications.

Return Value

None. Results are returned in the structure pointed to by r. 3


Example
#include <conio.h>
int main(void)
{
struct text_info ti;
gettextinfo(&ti);
cprintf("window left %2d\r\n",ti.winleft);
cprintf("window top %2d\r\n",ti.wintop);

751
C Runtime Library Reference RAD Studio 3.1 C++ Reference

cprintf("window right %2d\r\n",ti.winright);


cprintf("window bottom %2d\r\n",ti.winbottom);
cprintf("attribute %2d\r\n",ti.attribute);
cprintf("normal attribute %2d\r\n",ti.normattr);
cprintf("current mode %2d\r\n",ti.currmode);
cprintf("screen height %2d\r\n",ti.screenheight);
cprintf("screen width %2d\r\n",ti.screenwidth);
cprintf("current x %2d\r\n",ti.curx);
cprintf("current y %2d\r\n",ti.cury);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.14 gotoxy
Header File

conio.h

Category

Console I/O Routines

Prototype
void gotoxy(int x, int y);

Description

Positions cursor in text window.

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.

Note:Do not use this function in Win32 GUI applications.

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

Console I/O Routines

Prototype
void highvideo(void);

Description

Selects high-intensity characters.

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.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.16 insline
Header File

conio.h

Category

Console I/O Routines

Prototype
void insline(void); 3
Description

Inserts a blank line in the text window.

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.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.17 kbhit
Header File

conio.h

Category

Console I/O Routines

Prototype
int kbhit(void);

Description

Checks for currently available keystrokes.

kbhit checks to see if a keystroke is currently available. Any available keystrokes can be retrieved with getch or getche.

Note: Do not use this function in Win32 GUI applications.

Return Value

If a keystroke is available, kbhit returns a nonzero value. Otherwise, it returns 0.


3 Example
#include <conio.h>
int main(void)
{
cprintf("Press any key to continue:");
while (!kbhit()) /* do nothing */ ;
cprintf("\r\nA key was pressed...\r\n");
return 0;
}

754
3.1 C++ Reference RAD Studio C Runtime Library Reference

Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.18 lowvideo
Header File

conio.h

Category

Console I/O Routines

Prototype
void lowvideo(void);

Description

Selects low-intensity characters.

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.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+
3

3.1.4.3.19 movetext
Header File

conio.h

Category

755
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Console I/O Routines

Prototype
int movetext(int left, int top, int right, int bottom, int destleft, int desttop);

Description

Copies text onscreen from one rectangle to another.

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.

movetext is a text mode function performing direct video output.

Note:Do not use this function in Win32 GUI applications.

Return Value

On success, movetext returns nonzero.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.20 normvideo
Header File

conio.h

Category
3
Console I/O Routines

Prototype
void normvideo(void);

Description

Selects normal-intensity characters.

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.

Note: Do not use this function in Win32 GUI applications.

Return Value

None.

Example
#include <conio.h>
int main(void)
{
normvideo();
cprintf("NORMAL Intensity Text\r\n");
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.21 putch
Header File

conio.h

Category

Console I/O Routines

Prototype
int putch(int c);

Description

Outputs character to screen.

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.

Note: This function should not be used in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.22 puttext
Header File

conio.h

Category

Console I/O Routines

Prototype
int puttext(int left, int top, int right, int bottom, void *source);

Description

Copies text from memory to the text mode screen.

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

bytes = (h rows) x (w columns) x 2

puttext is a text mode function performing direct video output.

Note:This function should not be used in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.23 textattr
Header File

conio.h

Category

Console I/O Routines

Prototype
void textattr(int newattr);

Description

Sets text attributes.

Note: Do not use this function in Win32 GUI applications.

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.

The color information is encoded in the newattr parameter as follows:

In this 8-bit newattr parameter:

• bits 0-3 contain the 4-bit foreground color (0 to 15).


• bits 4-6 contain the 3-bit background color (0 to 7).
• bit 8 is the blink-enable bit.
If the blink-enable bit is on, the character blinks. This can be accomplished by adding the constant BLINK to the attribute.
• If you use the symbolic color constants defined in conio.h for creating text attributes with textattr, note the following limitations 3
on the color you select for the background:
• You can select only one of the first eight colors for the background.
• You must shift the selected background color left by 4 bits to move it into the correct bit positions.
These symbolic constants are listed in the following table:
Return Value
None.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.24 textbackground
Header File

conio.h

Category

Console I/O Routines

Prototype
void textbackground(int newcolor);

Description

Selects new text background color.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.25 textcolor
Header File

conio.h

Category

Console I/O Routines

Prototype
void textcolor(int newcolor);

Description

Selects new character color in text mode.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.26 textmode
Header File

conio.h

Category

3 Console I/O Routines

Prototype
void textmode(int newmode);

Description

Puts screen in text mode.

Note: Do not use this function in Win32 GUI applications.

762
3.1 C++ Reference RAD Studio C Runtime Library Reference

textmode selects a specific text mode.

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.

LASTMODE Previous text mode


BW40 Black and white, 40 columns
C40 Color, 40 columns
BW80 Black and white, 80 columns
C80 Color, 80 columns
MONO Monochrome, 80 columns
C4350 EGA 43-line and VGA 50-line modes

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

POSIX Win32 ANSI C ANSI C++


+

763
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.3.27 ungetch
Header File

conio.h

Category

Console I/O Routines

Prototype
int ungetch(int ch);

Description

Pushes a character back to the keyboard buffer.

Note: Do not use this function in Win32 GUI applications.

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

On success, ungetch returns the character ch.

On error, it returns EOF.

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

POSIX Win32 ANSI C ANSI C++


+
3
3.1.4.3.28 wherex
Header File

conio.h

Category

764
3.1 C++ Reference RAD Studio C Runtime Library Reference

Console I/O Routines

Prototype
int wherex(void);

Description

Gives horizontal cursor position within window.

Note: Do not use this function in Win32 GUI applications.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.29 wherey
Header File

conio.h

Category

Console I/O Routines

Prototype
int wherey(void);

Description

Gives vertical cursor position within window.

Note: Do not use this function in Win32 GUI applications.


3
wherey returns the y-coordinate of the current cursor position (within the current text window).

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.3.30 window
Header File

conio.h

Category

Console I/O Routines

Prototype
void window(int left, int top, int right, int bottom);

Description

Defines active text mode window.

Note: Do not use this function in Win32 GUI applications.

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

isalpha, __iscsymf, iswalpha, _ismbcalpha ( see page 775) Header File


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
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
isalpha returns nonzero if c is a letter.
__iscsymf returns true if and only if the argument c is... more ( see page 775)
isascii, iswascii ( see page 776) Header File
ctype.h, wctype.h
Category
Classification Routines
Prototype
int isascii(int c);
int iswascii(wint_t c);
Description
Character classification macro.
These functions depend on the LC_CTYPE
isascii is a macro that classifies ASCII-coded integer values by table lookup. It is
a predicate returning nonzero for true and 0 for false.
isascii is defined on all integer values.
Return Value
isascii returns nonzero if c is in the range 0 to 127 (0x00-0x7F).
iswascii returns nonzero if c is is a wide-character representation of an ASCII
character.
Each of these routines returns 0 if c does not satisfy the test condition.
Example... more ( see page 776)
iscntrl, iswcntrl ( see page 777) Header File
ctype.h
Category
Classification Routines
Prototype
int iscntrl(int c);
int iswcntrl(wint_t c);
Description
Tests for a control character.
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
iscntrl returns nonzero if c is a delete character or ordinary control character.
Example

768
3.1 C++ Reference RAD Studio C Runtime Library Reference

isdigit, iswdigit, _ismbcdigit ( see page 778) Header File


ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isdigit(int c);
int iswdigit(wint_t c);
int _ismbcdigit(unsigned int c);
Description
Tests for decimal-digit character.
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
isdigit returns nonzero if c is a digit.
_ismbcdigit returns true if and only if the argument c is a single-byte
representation of an ASCII digit.... more ( see page 778)
isgraph, iswgraph, _ismbcgraph ( see page 779) Header File
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int isgraph(int c);
int iswgraph(wint_t c);
int _ismbcgraph( unsigned int c);
Description
Tests for printing character.
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
isgraph returns nonzero if c is a printing character.
Example
islower, iswlower, _ismbclower ( see page 779) Header File
ctype.h, mbstring.h
Category
Classification Routines
Prototype
int islower(int c);
int iswlower(wint_t c);
int _ismbclower(unsigned int c);
Description
Tests for lowercase character.
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
islower returns nonzero if c is a lowercase letter.
Example

769
C Runtime Library Reference RAD Studio 3.1 C++ Reference

isprint, iswprint, _ismbcprint ( see page 780) Header File


ctype.h, wctype.h, mbstring.h
Category
Classification Routines
Prototype
int isprint(int c);
int iswprint(wint_t c);
int _ismbcprint(unsigned int c);
Description
Tests for printing character.
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
isprint returns nonzero if c is a printing character.
Example
ispunct, iswpunct, _ismbcpunct ( see page 781) Header File
ctype.h, wctype.h, mbstring.h
Category
Classification Routines
Prototype
int ispunct(int c);
int iswpunct(wint_t c);
int _ismbcpunct(unsigned int c);
Description
Tests for punctuation character.
ispunct 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 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
ispunct returns nonzero if c is a punctuation character.
Example
isspace, iswspace, _ismbcspace ( see page 782) Header File
ctype.h, wctype.h, mbstring.h
Category
Classification Routines
Prototype
int isspace(int c);
int iswspace(wint_t c);
int _ismbcspace(unsigned int c);
Description
Tests for space character.
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.
Example

770
3.1 C++ Reference RAD Studio C Runtime Library Reference

isupper, iswupper, _ismbcupper ( see page 783) Header File


ctype.h, wctype.h, mbstring.h
Category
Classification Routines
Prototype
int isupper(int c);
int iswupper(wint_t c);
int _ismbcupper(unsigned int c);
Description
Tests for uppercase character.
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
isupper returns nonzero if c is an uppercase letter.
Example
isxdigit, iswxdigit ( see page 784) Header File
ctype.h, wctype.h
Category
Classification Routines
Prototype
int isxdigit(int c);
int iswxdigit(wint_t c);
Description
Tests for hexadecimal character.
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
toascii ( see page 784) Header File
ctype.h
Category
Conversion Routines
Prototype
int toascii(int c);
Description
Translates characters to ASCII format.
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
toascii returns the converted value of c.
Portability
tolower, _mbctolower, towlower ( see page 785) Header File
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 3
Translates characters to lowercase.
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

771
C Runtime Library Reference RAD Studio 3.1 C++ Reference

toupper, _mbctoupper, towupper ( see page 786) Header File


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
Translates characters to uppercase.
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.
towupper is the Unicode version of toupper. It is available when Unicode is
defined.
Return Value
toupper returns the converted value of ch if it is lowercase; it returns all others
unchanged.
Example

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.

3.1.4.4.2 _IS_xxx #defines


Header File

ctype.h

Description

Bit settings in the _ctype[] used by the is... character macros.

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).

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
#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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.4.4 _toupper
Header File

ctype.h

Category

Conversion Routines 3
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

773
C Runtime Library Reference RAD Studio 3.1 C++ Reference

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
#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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.4.5 isalnum, __iscsym, iswalnum, _ismbcalnum


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

3 Tests for an alphanumeric character.

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.

774
3.1 C++ Reference RAD Studio C Runtime Library Reference

isalnum returns nonzero if c is a letter or a digit.

__iscsym returns nonzero if c is a letter, underscore, or digit.

iswalnum returns nonzero if iswalpha or iswdigit return true for c.

_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

POSIX Win32 ANSI C ANSI C++


isalnum + + + +
__iscsym +
_ismbcalnum +
iswalnum + + +

3.1.4.4.6 isalpha, __iscsymf, iswalpha, _ismbcalpha


Header File

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

isalpha returns nonzero if c is a letter.

775
C Runtime Library Reference RAD Studio 3.1 C++ Reference

__iscsymf returns true if and only if the argument c is a letter or an underscore.

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

POSIX Win32 ANSI C ANSI C++


isalpha + + + +
__iscsymf +
_ismbcalpha +
iswalpha + + +

3.1.4.4.7 isascii, iswascii


Header File

ctype.h, wctype.h

Category

Classification Routines

Prototype
int isascii(int c);
int iswascii(wint_t c);

Description

Character classification macro.

These functions depend on the LC_CTYPE

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.

isascii is defined on all integer values.

Return Value

isascii returns nonzero if c is in the range 0 to 127 (0x00-0x7F).

iswascii returns nonzero if c is is a wide-character representation of an ASCII character.

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

POSIX Win32 ANSI C ANSI C++


isascii +
iswascii +

3.1.4.4.8 iscntrl, iswcntrl


Header File

ctype.h

Category

Classification Routines

Prototype
int iscntrl(int c);
int iswcntrl(wint_t c);

Description

Tests for a control character.

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

iscntrl returns nonzero if c is a delete character or ordinary control character.

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

POSIX Win32 ANSI C ANSI C++


iscntrl + + + +
iswcntrl + + +

3.1.4.4.9 isdigit, iswdigit, _ismbcdigit


Header File

ctype.h, mbstring.h

Category

Classification Routines

Prototype
int isdigit(int c);
int iswdigit(wint_t c);
int _ismbcdigit(unsigned int c);

Description

Tests for decimal-digit character.

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

isdigit returns nonzero if c is a digit.

_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

POSIX Win32 ANSI C ANSI C++


isdigit + + + +
_ismbcdigit +
iswdigit + + +

778
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.4.10 isgraph, iswgraph, _ismbcgraph


Header File

ctype.h, mbstring.h

Category

Classification Routines

Prototype
int isgraph(int c);
int iswgraph(wint_t c);
int _ismbcgraph( unsigned int c);

Description

Tests for printing character.

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

isgraph returns nonzero if c is a printing character.

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

POSIX Win32 ANSI C ANSI C++


isgraph + + + +
_ismbcgraph +
iswgraph + + +

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

Tests for lowercase character.

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

islower returns nonzero if c is a lowercase letter.

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

POSIX Win32 ANSI C ANSI C++


islower + + + +
_ismbclower +
iswlower + + +

3.1.4.4.12 isprint, iswprint, _ismbcprint


Header File

ctype.h, wctype.h, mbstring.h

Category

Classification Routines

3 Prototype
int isprint(int c);
int iswprint(wint_t c);
int _ismbcprint(unsigned int c);

Description

Tests for printing character.

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

isprint returns nonzero if c is a printing character.

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

POSIX Win32 ANSI C ANSI C++


isprint + + + +
_ismbcprint +
iswprint +

3.1.4.4.13 ispunct, iswpunct, _ismbcpunct


Header File

ctype.h, wctype.h, mbstring.h

Category

Classification Routines

Prototype
int ispunct(int c);
int iswpunct(wint_t c);
int _ismbcpunct(unsigned int c);

Description

Tests for punctuation character.

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

ispunct returns nonzero if c is a punctuation character.

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

POSIX Win32 ANSI C ANSI C++


ispunct + + + +
_ismbcpunt +
iswpunct + + +

3.1.4.4.14 isspace, iswspace, _ismbcspace


Header File

ctype.h, wctype.h, mbstring.h

Category

Classification Routines

Prototype
int isspace(int c);
int iswspace(wint_t c);
int _ismbcspace(unsigned int c);

Description

Tests for space character.

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

POSIX Win32 ANSI C ANSI C++


isspace + + + +
_ismbcspace +
iswspace + + +

3.1.4.4.15 isupper, iswupper, _ismbcupper


Header File

ctype.h, wctype.h, mbstring.h

Category

Classification Routines

Prototype
int isupper(int c);
int iswupper(wint_t c);
int _ismbcupper(unsigned int c);

Description

Tests for uppercase character.

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

isupper returns nonzero if c is an uppercase letter.

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

POSIX Win32 ANSI C ANSI C++


isupper + + + +
_ismbcupper +
iswupper + + +

783
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.4.16 isxdigit, iswxdigit


Header File

ctype.h, wctype.h

Category

Classification Routines

Prototype
int isxdigit(int c);
int iswxdigit(wint_t c);

Description

Tests for hexadecimal character.

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

POSIX Win32 ANSI C ANSI C++


isxdigit + + + +
iswxdigit + + +

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

Translates characters to ASCII format.

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

toascii returns the converted value of c.

Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.4.18 tolower, _mbctolower, towlower


Header File

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

Translates characters to lowercase.

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

POSIX Win32 ANSI C ANSI C++


tolower + + + +
_mbctolower +
towlower + + +

3.1.4.4.19 toupper, _mbctoupper, towupper


Header File

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

Translates characters to uppercase.

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.

towupper is the Unicode version of toupper. It is available when Unicode is defined.

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

POSIX Win32 ANSI C ANSI C++


toupper + + + +
_mbctoupper +
towupper + + +

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.

3.1.4.5.1 __pfnDliNotifyHook, __pfnDliFailureHook


Header File

delayimp.h 3
Category

Delay load hook notification Routines

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

LPCSTR szDll; /* name of dll */


DelayLoadProc dlp; /* name or ordinal of procedure */
HMODULE hmodCur; /* the hInstance of the library we
have loaded */
FARPROC pfnCur; /* the actual function that will be
called */
DWORD dwLastError;/* error received (if an error
notification) */
} DelayLoadInfo, *PDelayLoadInfo;

Delay load import hook notifications

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

Note: The “failure” hook is assigned to:


extern DelayedLoadHook _EXPDATA __pfnDliFailureHook;

This hook is called with the following notification flags:


dliNotify ==
{
dliFailLoadLibrary |
dliFailGetProcAddress
}

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

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.

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

_getdcwd, _wgetdcwd ( see page 791) Header File


direct.h
Category
Directory Control Routines
Prototype
char * _getdcwd(int drive, char *buffer, int buflen);
wchar_t * _wgetdcwd(int drive, wchar_t *buffer, int buflen);
Description
Gets current directory for specified drive.
_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... more
( see page 791)

3.1.4.6.1 _chdrive
Header File

direct.h

Category

Directory Control Routines

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
#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++
+

3.1.4.6.2 _getdcwd, _wgetdcwd


Header File

791
C Runtime Library Reference RAD Studio 3.1 C++ Reference

direct.h

Category

Directory Control Routines

Prototype
char * _getdcwd(int drive, char *buffer, int buflen);
wchar_t * _wgetdcwd(int drive, wchar_t *buffer, int buflen);

Description

Gets current directory for specified drive.

_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:

ENOMEM Not enough memory to allocate a buffer (buffer is NULL)


ERANGE Directory name longer than buflen (buffer is not NULL)

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

POSIX Win32 ANSI C ANSI C++


_getdcwd +
_wgetdcwd NT only
3

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

rewinddir, wrewinddir ( see page 797) Header File


dirent.h
Category
Directory Control Routines
Prototype
void rewinddir(DIR *dirp);
void wrewinddir(wDIR *dirp);
Description
Resets a directory stream to the first entry.
rewinddir is available on POSIX-compliant UNIX systems.
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.
wrewinddir is the Unicode version of rewinddir.
Return Value
None.
Example

3.1.4.7.1 closedir, wclosedir


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

EBADF The dirp argument does not point to a valid open directory stream

Example

3 /* opendir.c - test opendir(), readdir(), closedir() */

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>

void scandir(char *dirname)


{
DIR *dir;
struct dirent *ent;

794
3.1 C++ Reference RAD Studio C Runtime Library Reference

printf("First pass on '%s':\n",dirname);


if ((dir = opendir(dirname)) == NULL)
{
perror("Unable to open directory");
exit(1);
}
while ((ent = readdir(dir)) != NULL)
printf("%s\n",ent->d_name);

printf("Second pass on '%s':\n",dirname);


rewinddir(dir);
while ((ent = readdir(dir)) != NULL)
printf("%s\n",ent->d_name);
if (closedir(dir) != 0)
perror("Unable to close directory");
}

void main(int argc,char *argv[])


{
if (argc != 2)
{
printf("usage: opendir dirname\n");
exit(1);
}
scandir(argv[1]);
exit(0);
}
Portability

POSIX Win32 ANSI C ANSI C++


+ +

3.1.4.7.2 opendir, wopendir


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. 3


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 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

stream when it is no longer needed.

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

ENOENT The directory does not exist


ENOMEM Not enough memory to allocate a DIR object

Example
/* opendir.c - test opendir(), readdir(), closedir() */

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>

void scandir(char *dirname)


{
DIR *dir;
struct dirent *ent;

printf("First pass on '%s':\n",dirname);


if ((dir = opendir(dirname)) == NULL)
{
perror("Unable to open directory");
exit(1);
}
while ((ent = readdir(dir)) != NULL)
printf("%s\n",ent->d_name);

printf("Second pass on '%s':\n",dirname);


rewinddir(dir);
while ((ent = readdir(dir)) != NULL)
printf("%s\n",ent->d_name);
if (closedir(dir) != 0)
perror("Unable to close directory");
}

void main(int argc,char *argv[])


{
if (argc != 2)
{
printf("usage: opendir dirname\n");
exit(1);
}
scandir(argv[1]);
exit(0);
}
Portability

3 POSIX Win32 ANSI C ANSI C++


opendir + +
wopendir

3.1.4.7.3 readdir, wreaddir


Header File

796
3.1 C++ Reference RAD Studio C Runtime Library Reference

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 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

POSIX Win32 ANSI C ANSI C++


readdir + +
wreaddir +

3
3.1.4.7.4 rewinddir, wrewinddir
Header File

dirent.h

Category

Directory Control Routines

797
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Prototype
void rewinddir(DIR *dirp);
void wrewinddir(wDIR *dirp);

Description

Resets a directory stream to the first entry.

rewinddir is available on POSIX-compliant UNIX systems.

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.

wrewinddir is the Unicode version of rewinddir.

Return Value

None.

Example
/* opendir.c - test opendir(), readdir(), closedir() */

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>

void scandir(char *dirname)


{
DIR *dir;
struct dirent *ent;

printf("First pass on '%s':\n",dirname);


if ((dir = opendir(dirname)) == NULL)
{
perror("Unable to open directory");
exit(1);
}
while ((ent = readdir(dir)) != NULL)
printf("%s\n",ent->d_name);

printf("Second pass on '%s':\n",dirname);


rewinddir(dir);
while ((ent = readdir(dir)) != NULL)
printf("%s\n",ent->d_name);
if (closedir(dir) != 0)
perror("Unable to close directory");
}

void main(int argc,char *argv[])


{
if (argc != 2)
{
3 printf("usage: opendir dirname\n");
exit(1);
}
scandir(argv[1]);
exit(0);
}
Portability

798
3.1 C++ Reference RAD Studio C Runtime Library Reference

POSIX Win32 ANSI C ANSI C++


rewind + +
wrewinddir +

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.

• Under Windows, only the current process is affected.


Return Value
Upon successful completion, chdir returns a value of 0.
Otherwise, it returns a value of -1, and the global
variable... more ( see page 803)
MAXxxxx #defines (fnsplit) ( see page 804) Header File
dir.h
Description
These symbols define the maximum number of characters in a file specification
for fnsplit (including room for a terminating NULL).
findclose, _wfindclose ( see page 804) Header File
dir.h
Category
Directory Control Routines
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
findclose returns 0 on successfully closing the handle. On failure: 3
• -1 is returned
• errno is set to

799
C Runtime Library Reference RAD Studio 3.1 C++ Reference

findfirst, _wfindfirst ( see page 805) Header File


dir.h
Category
Directory Control Routines
Prototype
int findfirst(const char *pathname, struct ffblk *ffblk,
int attrib);
int _wfindfirst( const wchar_t *pathname, struct _wffblk
*ffblk, int attrib);
Description
Searches a disk directory.
findfirst begins a search of a disk directory for files specified by attributes or
wildcards.
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,... more ( see page 805)
findnext, _wfindnext ( see page 807) Header File
dir.h
Category
Directory Control Routines
Prototype
int findnext(struct ffblk *ffblk );
int _wfindnext(struct _wffblk *ffblk );
Description
Continues findfirst search.
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... more ( see page 807)
fnmerge, _wfnmerge ( see page 808) Header File
dir.h
Category
Directory Control Routines
Prototype
void fnmerge(char *path, const char *drive, const char
*dir, const char *name, const char *ext);
void _wfnmerge(wchar_t *path, const wchar_t *drive, const
wchar_t *dir, const wchar_t *name, const wchar_t *ext );
Description
Builds a path from component parts.
fnmerge makes a path name from its components. The new path name is
X:\DIR\SUBDIR\NAME.EXT
where:
fnsplit, _wfnsplit ( see page 810) Header File
dir.h
Category
Directory Control Routines
Prototype
int fnsplit(const char *path, char *drive, char *dir, char
*name, char *ext);
3 int _wfnsplit(const wchar_t *path, wchar_t *drive, wchar_t
*dir, wchar_t *name, wchar_t *ext );
Description
Splits a full path name into its components.
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... more ( see page 810)

800
3.1 C++ Reference RAD Studio C Runtime Library Reference

Bit Definitions for fnsplit ( see page 811) Header File


dir.h
Description
Bit definitions returned from fnsplit to identify which pieces of a file name were
found during the split.
getcurdir, _wgetcurdir ( see page 811) Header File
dir.h
Category
Directory Control Routines
Prototype
int getcurdir(int drive, char *directory);
int _wgetcurdir(int drive, wchar_t *directory );
Description
Gets current directory for specified drive.
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
getcurdir returns 0 on success or -1 in the event... more ( see page 811)
getcwd, _wgetcwd ( see page 812) Header File
dir.h
Category
Directory Control Routines
Prototype
char *getcwd(char *buf, int buflen);
wchar_t *_wgetcwd(wchar_t *buf, int buflen);
Description
Gets current working directory.
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.
Return Value... more ( see page 812)
getdisk, setdisk ( see page 813) Header File
dir.h
Category
Directory Control Routines
Prototype
int getdisk(void);
int setdisk(int drive);
Description
Gets or sets the current drive number.
getdisk gets the current drive number. It returns an integer: 0 for A, 1 for B, 2 for
C, and so on.
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
3

801
C Runtime Library Reference RAD Studio 3.1 C++ Reference

mkdir, _wmkdir ( see page 814) Header File


dir.h
Category
Directory Control Routines
Prototype
int mkdir(const char *path);
int _wmkdir(const wchar_t *path);
Description
Creates a directory.
mkdir is available on UNIX, though it then takes an additional parameter.
mkdir creates a new directory from the given path name path.
Return Value
mkdir returns the value 0 if the new directory was created.
A return value of -1 indicates an error, and the global variable errno is set to one
of the following values:
_mktemp, _wmktemp ( see page 815) Header File
dir.h
Category
Directory Control Routines
Prototype
char *_mktemp(char *template);
wchar_t *_wmktemp(wchar_t *template);
Description
Makes a unique file name.
_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... more ( see page 815)
_rmdir, _wrmdir ( see page 816) Header File
dir.h
Category
Directory Control Routines
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:

802
3.1 C++ Reference RAD Studio C Runtime Library Reference

searchpath, wsearchpath ( see page 817) Header File


dir.h
Category
Miscellaneous Routines
Prototype
char *searchpath(const char *file);
wchar_t *wsearchpath( const wchar_t *file );
Description
Searches the operating system path for a file.
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,... more ( see page
817)

3.1.4.8.1 chdir
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.

• Under Windows, only the current process is affected.


Return Value
Upon successful completion, chdir returns a value of 0. Otherwise, it returns a value of -1, and the global variable errno is set to

ENOENT Path or file name not found

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

POSIX Win32 ANSI C ANSI C++


chdir + +
_wchdir NT only

3.1.4.8.2 MAXxxxx #defines (fnsplit)


Header File

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

3 3.1.4.8.3 findclose, _wfindclose


Header File

dir.h

Category

Directory Control Routines

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

findclose returns 0 on successfully closing the handle. On failure:

• -1 is returned
• errno is set to

EINVDAT Invalid data

Portability

POSIX Win32 ANSI C ANSI C++


findclose +
_wfindclose NT only

See Also
findfirst ( see page 805)

findnext ( see page 807)

3.1.4.8.4 findfirst, _wfindfirst


Header File

dir.h

Category

Directory Control Routines

Prototype
int findfirst(const char *pathname, struct ffblk *ffblk, int attrib);
int _wfindfirst( const wchar_t *pathname, struct _wffblk *ffblk, int attrib);

Description

Searches a disk directory.

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];
};

For Win32, the format of the structure ffblk is as follows:


struct ffblk {
long ff_reserved;
long ff_fsize; /* file size */
unsigned long ff_attrib; /* attribute found */
unsigned short ff_ftime; /* file time */
unsigned short ff_fdate; /* file date */
char ff_name[256]; /* found file name */
};

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:

FA_RDONLY Read-only attribute


FA_HIDDEN Hidden file
FA_SYSTEM System file
FA_LABEL Volume label
FA_DIREC Directory
FA_ARCH Archive

A combination of constants can be OR’ed together.

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:

Bits 0-4 Day


Bits 5-8 Month
Bits 9-15 Years since 1980 (for example 9 here means 1989)

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

findfirst 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

ENOENT Path or file name not found

• _doserrno is set to one of the following values:

ENMFILE No more files


ENOENT Path or file name not found

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

POSIX Win32 ANSI C ANSI C++


findfirst +
_wfindfirst NT only

See Also
findclose ( see page 804)

findnext ( see page 807)


3
3.1.4.8.5 findnext, _wfindnext
Header File

dir.h

Category

Directory Control Routines

807
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Prototype
int findnext(struct ffblk *ffblk );
int _wfindnext(struct _wffblk *ffblk );

Description

Continues findfirst search.

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

ENOENT Path or file name not found

_doserrno is set to one of the following values:

ENMFILE No more files


ENOENT Path or file name not found

Portability

POSIX Win32 ANSI C ANSI C++


findnext +
_wfindnext NT only

See Also
findfirst ( see page 805)

3.1.4.8.6 fnmerge, _wfnmerge


Header File

dir.h

Category

Directory Control Routines


3 Prototype
void fnmerge(char *path, const char *drive, const char *dir, const char *name, const char
*ext);
void _wfnmerge(wchar_t *path, const wchar_t *drive, const wchar_t *dir, const wchar_t *name,
const wchar_t *ext );

Description

808
3.1 C++ Reference RAD Studio C Runtime Library Reference

Builds a path from component parts.

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 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.

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

POSIX Win32 ANSI C ANSI C++


fnmerge +
_wfnmerge NT only

809
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.8.7 fnsplit, _wfnsplit


Header File

dir.h

Category

Directory Control Routines

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

Splits a full path name into its components.

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.

• When fnsplit splits path it treats the punctuation as follows:


• drive includes the colon (C:, A:, and so on)
• dir includes the leading and trailing backslashes (\BC\include\, \source\ ,and so on)
• name includes the file name
• ext includes the dot preceding the extension (.C, .EXE, and so on).
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
fnsplit returns an integer (composed of five flags defined in dir.h) indicating which of the full path name components were present
in path. These flags and the components they represent are

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

POSIX Win32 ANSI C ANSI C++


fnsplit +
_wfnsplit NT only

3.1.4.8.8 Bit Definitions for fnsplit


Header File

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 ?)

3.1.4.8.9 getcurdir, _wgetcurdir


Header File

dir.h
3
Category

Directory Control Routines

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

Gets current directory for specified drive.

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

getcurdir returns 0 on success or -1 in the event of error.

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

POSIX Win32 ANSI C ANSI C++


getcurdir +
_wgetcurdir NT only

3.1.4.8.10 getcwd, _wgetcwd


Header File

dir.h

Category

Directory Control Routines

Prototype
char *getcwd(char *buf, int buflen);

3 wchar_t *_wgetcwd(wchar_t *buf, int buflen);

Description

Gets current working directory.

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

• getcwd returns the following values:


• If buf is not NULL on input, getcwd returns buf on success, NULL on error.
• If buf is NULL on input, getcwd returns a pointer to the allocated buffer.
In the event of an error return, the global variable errno is set to one of the following values:

ENODEV No such device


ENOMEM Not enough memory to allocate a buffer (buf is NULL)
ERANGE Directory name longer than buflen (buf is not NULL)

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

POSIX Win32 ANSI C ANSI C++


getcwd + +
_wgetcwd NT only

3.1.4.8.11 getdisk, setdisk


Header File

dir.h

Category

Directory Control Routines

Prototype
int getdisk(void);
int setdisk(int drive);

Description

Gets or sets the current drive number.

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;
}

3.1.4.8.12 mkdir, _wmkdir


Header File

dir.h

Category

Directory Control Routines

Prototype
int mkdir(const char *path);
int _wmkdir(const wchar_t *path);

Description

Creates a directory.

mkdir is available on UNIX, though it then takes an additional parameter.

mkdir creates a new directory from the given path name path.

Return Value

mkdir returns the value 0 if the new directory was created.

A return value of -1 indicates an error, and the global variable errno is set to one of the following values:

EACCES Permission denied


ENOENT No such file or directory

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

POSIX Win32 ANSI C ANSI C++


mkdir + +
_wmkdir NT only

3.1.4.8.13 _mktemp, _wmktemp


Header File

dir.h

Category

Directory Control Routines

Prototype
char *_mktemp(char *template);
wchar_t *_wmktemp(wchar_t *template);

Description

Makes a unique file name.

_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

POSIX Win32 ANSI C ANSI C++


mktemp + +
_wmktemp +

3.1.4.8.14 _rmdir, _wrmdir


Header File

dir.h

Category

Directory Control Routines

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:

EACCES Permission denied


ENOENT Path or file function not found

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

POSIX Win32 ANSI C ANSI C++


_rmdir + +
_wrmdir NT only

3.1.4.8.15 searchpath, wsearchpath


Header File

dir.h

Category

Miscellaneous Routines

Prototype
char *searchpath(const char *file);
wchar_t *wsearchpath( const wchar_t *file );

Description

Searches the operating system path for a file.

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

POSIX Win32 ANSI C ANSI C++


searchpath +
wsearchpath NT only

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

_osminor ( see page 823) 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.
_osversion ( see page 823) Header File
dos.h
Syntax
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.)
_osversion is functionally identical to _version.
_sleep ( see page 824) Header File
dos.h
Category
Process Control Routines
Prototype
void _sleep(unsigned seconds);
Description
Suspends execution for an interval (seconds).
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
_version ( see page 824) Header File
dos.h
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.)
disable, _disable, enable, _enable ( see page 825) Header File
dos.h
Category
Miscellaneous Routines
Prototype
void disable(void);
void _disable(void);
void enable(void);
void _enable(void);
Description
Disables and enables interrupts.
3
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

819
C Runtime Library Reference RAD Studio 3.1 C++ Reference

dostounix ( see page 825) Header File


dos.h
Category
Time and Date Routines
Prototype
long dostounix(struct date *d, struct time *t);
Description
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
Returns UNIX version of current date and time parameters: number of seconds
since 00:00:00 on January 1, 1970 (GMT).
Example
geninterrupt ( see page 826) Header File
Category
Prototype
void geninterrupt(int intr_num);
Description
Return Value
Portability
getdate, setdate ( see page 826) Header File
dos.h
Category
Time and Date Routines
Prototype
void getdate(struct date *datep);
void setdate(struct date *datep);
Description
Gets and sets system date.
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.
The date structure is defined as follows:
struct date{
int da_year; /* current year */
char da_day; /* day of the... more ( see page 826)
getdfree ( see page 827) Header File
dos.h
Category
Directory Control Routines, Miscellaneous Routines
Prototype
void getdfree(unsigned char drive, struct dfree *dtable);
Description
Gets disk free space.
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 disk attributes.
The dfree structure is defined as follows:
struct dfree {
unsigned df_avail; /* available clusters */
3 unsigned df_total; /* total clusters */
unsigned df_bsec; /* bytes per sector */
unsigned df_sclus; /* sectors per cluster */
};
Return Value
getdfree returns no value. In the event of an error, df_sclus... more ( see page
827)

820
3.1 C++ Reference RAD Studio C Runtime Library Reference

gettime, settime ( see page 828) Header File


dos.h
Category
Time and Date Routines
Prototype
void gettime(struct time *timep);
void settime(struct time *timep);
Description
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 */
unsigned char ti_hour; /* hours */
unsigned char ti_hund; /* hundredths of
seconds */
unsigned char ti_sec; /* seconds */
};
Return Value
None.
Example
unixtodos ( see page 829) Header File
dos.h
Category
Time and Date Routines
Prototype
void unixtodos(long time, struct date *d, struct time *t);
Description
Converts date and time from UNIX to DOS format.
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
_unlink, _wunlink ( see page 830) Header File
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
3
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.
Note: If the file is open, it must be closed before unlinking it.
_wunlink is the Unicode version of _wunlink. The Unicode version accepts a
filename that is a wchar_t character string. Otherwise, the functions perform...
more ( see page 830)

821
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.9.1 FA_xxxx #defines


Header File

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

3.1.4.9.2 NFDS #define


Header File

dos.h

Description

Maximum number of file descriptors.

3.1.4.9.3 _getdrive
Header File

dos.h

Category

Directory Control Routines

Prototype
int _getdrive(void);

Description

Gets the current drive.

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.)

_osversion is functionally identical to _version.

823
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.9.7 _sleep
Header File

dos.h

Category

Process Control Routines

Prototype
void _sleep(unsigned seconds);

Description

Suspends execution for an interval (seconds).

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

POSIX Win32 ANSI C ANSI C++


+

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

3.1.4.9.9 disable, _disable, enable, _enable


Header File

dos.h

Category

Miscellaneous Routines

Prototype
void disable(void);
void _disable(void);
void enable(void);
void _enable(void);

Description

Disables and enables interrupts.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.9.10 dostounix
Header File

dos.h

Category

Time and Date Routines

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.9.11 geninterrupt
Header File

Category

Prototype
void geninterrupt(int intr_num);

Description

Return Value

Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.9.12 getdate, setdate


Header File
3 dos.h

Category

Time and Date Routines

Prototype
void getdate(struct date *datep);
void setdate(struct date *datep);

826
3.1 C++ Reference RAD Studio C Runtime Library Reference

Description

Gets and sets system date.

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.

The date structure is defined as follows:


struct date{
int da_year; /* current year */
char da_day; /* day of the month */
char da_mon; /* month (1 = Jan) */
};

Return Value

getdate and setdate do not return a 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

Directory Control Routines, Miscellaneous Routines

Prototype
void getdfree(unsigned char drive, struct dfree *dtable);

Description

Gets disk free space.

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.

The dfree structure is defined as follows:


struct dfree {
unsigned df_avail; /* available clusters */
unsigned df_total; /* total clusters */

827
C Runtime Library Reference RAD Studio 3.1 C++ Reference

unsigned df_bsec; /* bytes per sector */


unsigned df_sclus; /* sectors per cluster */
};

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.9.14 gettime, settime


Header File

dos.h

Category

Time and Date Routines

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

unsigned char ti_hour; /* hours */


unsigned char ti_hund; /* hundredths of seconds */
unsigned char ti_sec; /* seconds */
};
Return Value
None.
Example
#include <stdio.h>
#include <dos.h>
int main(void)
{
struct time t;
gettime(&t);
printf("The current time is: %2d:%02d:%02d.%02d\n",
t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
return 0;
}

3.1.4.9.15 unixtodos
Header File

dos.h

Category

Time and Date Routines

Prototype
void unixtodos(long time, struct date *d, struct time *t);

Description

Converts date and time from UNIX to DOS format.

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

val = dostounix(&dt, &tm);


/* subtract 42 days worth of seconds */
val -= (SECONDS_PER_DAY * 42);
/* convert back to dos time and date */
unixtodos(val, &dt, &tm);
printf("42 days ago it was %d %s %d\n",
dt.da_day, month[dt.da_mon], dt.da_year);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.9.16 _unlink, _wunlink


Header File

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.

Note: If the file is open, it must be closed before unlinking it.

_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 success, _unlink returns 0.

On error, it returns -1 and sets the global variable errno to one of the following values:

EACCES Permission denied

3 ENOENT Path or file name not found

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

POSIX Win32 ANSI C ANSI C++


_unlink + +
_wunlink NT only

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

Error Numbers in errno ( see page 834) Header File


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.
Also, perror will display messages.
perror,_wperror ( see page 835) Header File
errno.h, stdio.h
Category
Diagnostic Routines, Input/output Routines
Prototype
void perror(const char *s);
void _wperror(const wchar_t *s);
Description
Prints a system error message.
perror prints to the stderr stream (normally the console) the system error
message for the last library routine that set the global 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... more ( see page 835)
_sys_errlist ( see page 837) Header File
errno.h
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... more ( see
page 837)
_sys_nerr ( see page 838) 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.
This variable is defined as the number of error message strings in _sys_errlist.

3.1.4.10.1 EDOM, ERANGE, #defines


Header File

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.

E2BIG Bad environ


EACCES Access denied
EACCES Bad access
EACCES Is current dir
EBADF Bad handle
EFAULT Reserved
EINVAL Bad data
EINVAL Bad function
EMFILE Too many open
ENOENT No such file or directory
ENOEXEC Bad format
ENOMEM Mcb destroyed
ENOMEM Out of memory
ENOMEM Bad block
EXDEV Bad drive
EXDEV Not same device

3.1.4.10.3 errno (C Runtime Library Reference)


Header File

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.

3.1.4.10.4 Error Numbers in errno


Header File

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.

Also, perror will display 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

Diagnostic Routines, Input/output Routines

Prototype 3
void perror(const char *s);
void _wperror(const wchar_t *s);

Description

Prints a system error message.

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.

The following messages are generated by perror:

Note: For Win32 GUI applications, stderr must be redirected.

Arg list too big

Attempted to remove current directory

Bad address

Bad file number

Block device required

Broken pipe

Cross-device link

Error 0

Exec format error

Executable file in use

File already exists

File too large

Illegal seek

Inappropriate I/O control operation

Input/output error

Interrupted function call

Invalid access code

Invalid argument Resource busy

Invalid dataResource temporarily unavailable

Invalid environment

Invalid format

Invalid function number


3
Invalid memory block address

Is a directory

Math argument

Memory arena trashed

Name too long

836
3.1 C++ Reference RAD Studio C Runtime Library Reference

No child processes

No more files

No space left on device

No such device

No such device or address

No such file or directory

No such process

Not a directory

Not enough memory

Not same device

Operation not permitted

Path not found

Permission denied

Possible deadlock

Read-only file system

Resource busy

Resource temporarily unavailable

Result too large

Too many links

Too many open files

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

POSIX Win32 ANSI C ANSI C++


perror + + + +
_wperror + 3

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.

This variable is defined as the number of error message strings in _sys_errlist.

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

__throwLineNumber ( see page 840) 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.
set_terminate ( see page 840) Header File
except.h
Syntax
typedef void (*terminate_handler)();
terminate_handler set_terminate(terminate_handler t_func);
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... more ( see page 840)
set_unexpected ( see page 841) 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... more ( see
page 841)
terminate ( see page 841) Header File
except.h
Syntax
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... more ( see
page 841)
unexpected ( see page 842) Header File
except.h
Syntax
void unexpected();
Description 3
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
None, although unexpected may throw an exception.

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

typedef void (*terminate_handler)();


terminate_handler set_terminate(terminate_handler t_func);

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 previous function given to set_terminate will be the 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 previous function given to set_unexpected will be the 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.

unexpected_func can also call abort, exit, or terminate. 3

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

None, although unexpected may throw an exception.

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.

3.1.4.12.1 Using fastmath math routines


Header File

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.

Math Routine Fastmath Routine Math Routine Fastmath Routine


acos _fm_acos asin _fm_asin
atan _fm_atan atan2 _fm_atan2
cos _fm_cos cosh _fm_cosh
exp _fm_exp fabs _fm_fabs
asin _fm_asin atan _fm_atan
atan2 _fm_atan2 cos _fm_cos
cosh _fm_cosh exp _fm_exp
fabs _fm_fabs frexp _fm_frexp
hypot _fm_hypot ldexp _fm_ldexp
log _fm_log log10 _fm_log10
sin _fm_sin sinh _fm_sinh
sqrt _fm_sqr tan _fm_tan
tanh _fm_tanh sincos _fm_sincos
acosl _fm_acosl asinl _fm_asinl
atan2l _fm_atan2l atanl _fm_atanl
coshl _fm_coshl cosl _fm_cosl
expl _fm_expl fabsl _fm_fabsl
frexpl _fm_frexpl hypotl _fm_hypotl
ldexpl _fm_ldexpl log10l _fm_log10l
logl _fm_logl sinhl _fm_sinhl
sinl _fm_sinl sqrtl _fm_sqrtl
tanhl _fm_tanhl tanl _fm_tanl
sincosl _fm_sincosl atanhl _fm_atanhl
acoshl _fm_acoshl asinhl _fm_asinhl

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

long double _FMAPI _fm_acoshl (long double __x);


long double _FMAPI _fm_asinhl (long double __x);
__inline void _fm_fwait(void)
unsigned int _FMAPI _fm_init(void);

_fm_fwait is a special inline function that performs an intrinsic FWAIT instruction.

_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

_pipe ( see page 847) Header File


io.h, fcntl.h
Category
Input/output Routines
Syntax
int _pipe(int *handles, unsigned int size, int mode);
Description
Creates a read/write pipe.
The _pipe function creates an anonymous pipe that can be used to pass
information between processes. The pipe is opened for 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... more ( see page 847)
open, _wopen ( see page 849) Header File
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
Opens a file for reading or writing.
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...
more ( see page 849)
_sopen, _wsopen ( see page 850) Header File
fcntl.h, sys\stat.h, share.h, io.h, stdio.h
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
Opens a shared file.
_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
You can use only one... more ( see page 850)

3.1.4.13.1 O_xxxx #defines


Header File

fcntl.h 3
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

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

O_RDONLY Open for reading only


O_WRONLY Open for writing only
O_RDWR Open for reading and writing
Other access flags

O_NDELAY Not used; for UNIX compatibility.


O_APPEND Append to end of file
If set, the file pointer is set to the end of the file prior to each write.
O_CREAT Create and open file
If the file already exists, has no effect.
If the file does not exist, the file is created.
O_EXCL Exclusive open: Used only with O_CREAT.
If the file already exists, an error is returned.
O_TRUNC Open with truncation
If the file already exists, its length is truncated to 0. The file attributes remain
unchanged.
Binary-mode/Text-mode
flags
O_BINARY No translation: Explicitly opens the file in binary mode
O_TEXT CR-LF translation: Explicitly opens the file in text mode
Additional values
available using
_rtl_open
O_NOINHERIT Child processes inherit file
O_DENYALL Error if opened for read/write
3 O_DENYWRITE Error if opened for write
O_DENYREAD Error if opened for read
O_DENYNONE Allow concurrent access

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.

In binary mode, no such translation occurs.

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

Creates a read/write pipe.

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.

The translation mode is specified by mode, as follows:

847
C Runtime Library Reference RAD Studio 3.1 C++ Reference

O_BINARY The pipe is opened in binary mode


O_TEXT The pipe is opened in text mode

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].

On error, it returns -1 and sets errno to one of the following values:

EMFILE Too many open files


ENOMEM Out of memory

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

// wait for the child to finish


wait(NULL);
return(0);
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.13.4 open, _wopen


Header File

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

Opens a file for reading or writing.

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.

These symbolic constants are defined in fcntl.h.

O_RDONLY Open for reading only.


O_WRONLY Open for writing only.
O_RDWR Open for reading and writing.
3

O_NDELAY Not used; for UNIX compatibility.


O_APPEND If set, the file pointer will be set to the end of the file prior to each write.
O_CREAT If the file exists, this flag has no effect. If the file does not exist, the file is created, and the bits of
mode are used to set the file attribute bits as in chmod.
O_TRUNC If the file exists, its length is truncated to 0. The file attributes remain unchanged.

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.

S_IWRITE Permission to write


S_IREAD Permission to read
S_IREAD|S_IWRITE Permission to read and write

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:

EACCES Permission denied


EINVACC Invalid access code
EMFILE Too many open files
ENOENT No such file or directory

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

3 POSIX Win32 ANSI C ANSI C++


open + +
_wopen NT only

3.1.4.13.5 _sopen, _wsopen


Header File

850
3.1 C++ Reference RAD Studio C Runtime Library Reference

fcntl.h, sys\stat.h, share.h, io.h, stdio.h

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

Opens a shared file.

_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

You can use only one of the following flags:

O_RDONLY Open for reading only.


O_WRONLY Open for writing only.
O_RDWR Open for reading and writing.

Other access flags

You can use any logical combination of the following flags:

O_NDELAY Not used; for UNIX compatibility.


O_APPEND If set, the file pointer is set to the end of the file prior to each write.
O_CREA If the file exists, this flag has no effect. If the file does not exist, the file is created, and the bits of
mode are used to set the file attribute bits as in chmod.
O_TRUNC If the file exists, its length is truncated to 0. The file attributes remain unchanged.
O_EXCL Used only with O_CREAT. If the file already exists, an error is returned.
O_BINARY This flag can be given to explicitly open the file in binary mode.
O_TEXT This flag can be given to explicitly open the file in text mode.
O_NOINHERIT The file is not passed to child programs.

Note: These O_... symbolic constants are defined in fcntl.h.

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.

S_IWRITE Permission to write


S_IREAD Permission to read
S_IREAD|S_IWRITE Permission to read/write

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

SH_COMPAT Sets compatibility mode.


SH_DENYRW Denies read/write access
SH_DENYWR Denies write access
SH_DENYRD Denies read access
SH_DENYNONE Permits read/write access
SH_DENYNO Permits read/write access

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.

On error, it returns -1, and the global variable errno is set to

EACCES Permission denied


EINVACC Invalid access code
EMFILE Too many open files
ENOENT Path or file function not found

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

POSIX Win32 ANSI C ANSI C++


_sopen +
_wsopen +

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

_control87, _controlfp ( see page 858) Header File


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
Manipulates the floating-point control word.
_control87 retrieves or changes the floating-point control word.
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... more ( see page 858)
_copysign, _copysignl ( see page 859) Header File
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
_finite, _finitel ( see page 859) Header File
float.h
Category
Math Routines
Prototype
int _finite(double d);
int _finitel(long double ld);
Description
Determines whether a given double-precision floating point value d is finite.
_finitel is the long double version; it takes a long double argument.
Return Value
Returns non-zero if the argument is finite, and 0 if it is not.
Portability
_fpclass, _fpclassl ( see page 860) Header File
float.h
Category
Math Routines
Prototype
int _fpclass(double d);
int _fpclassl(long double ld);
Description
3 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

854
3.1 C++ Reference RAD Studio C Runtime Library Reference

_fpreset ( see page 860) Header File


float.h
Category
Math Routines
Prototype
void _fpreset(void);
Description
Reinitializes floating-point math package.
_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.

• If you use an 80x87 take the following precautions:


• Do not call system or an exec... or spawn... function while
a... more ( see page 860)
_isnan, _isnanl ( see page 861) Header File
float.h
Category
Classification Routines, Math Routines
Prototype
int _isnan(double d);
int _isnanl(long double ld);
Description
Tests whether a given double-precision floating-point value d is a NaN.
_isnanl is the long double version; it takes a long double argument.
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
_logb, _logbl ( see page 862) Header File
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
Returns the unbiased exponent of the value passed in.
Portability

855
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_nextafter, _nextafterl ( see page 862) Header File


float.h
Category
Math Routines
Prototype
double _nextafter(double da, double db);
long double _nextafterl(long double lda, long double ldb);
Description
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... more ( see page 862)
_scalb, _scalbl ( see page 863) Header File
float.h
Category
Math Routines
Prototype
double _scalb(double d, long exp);
long double _scalbl(long double ld, long exp);
Description
Scales the argument d by a power of 2.
_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
_status87, _statusfp ( see page 863) Header File
float.h
Category
Math Routines
Prototype
unsigned int _status87(void);
unsigned int _statusfp(void);
Description
Gets floating-point status.
_status87 gets the floating-point status word, which is a combination of the 80x87
status word and other conditions detected by the 80x87 exception handler.
_statusfp is identical to _status87 and is for Microsoft compatibility.
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.14.1 CW_DEFAULT #define


Header File

3 float.h

Description

Default control word for 80x87 math coprocessor.

3.1.4.14.2 _chgsign, _chgsignl


Header File

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

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

POSIX Win32 ANSI C ANSI C++


_chgsign +
_chgsignl +

3.1.4.14.3 _clear87, _clearfp


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 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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.14.4 _control87, _controlfp


Header File

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

Manipulates the floating-point control word.

_control87 retrieves or changes the floating-point control word.

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.

Here is a simple illustration:

Original control word: 0100 0011 0110 0011


mask: 1000 0001 0100 1111
newcw: 1110 1001 0000 0101
Changing bits: 1xxx xxx1 x0xx 0101
3
If mask equals 0, _control87 returns the floating-point control word without altering it.

_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

POSIX Win32 ANSI C ANSI C++


_control87 +
_controlfp +

3.1.4.14.5 _copysign, _copysignl


Header File

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

POSIX Win32 ANSI C ANSI C++


_copysign +
_copysignl +

3.1.4.14.6 _finite, _finitel


Header File

float.h

Category

Math Routines
3
Prototype
int _finite(double d);
int _finitel(long double ld);

Description

Determines whether a given double-precision floating point value d is finite.

_finitel is the long double version; it takes a long double argument.

859
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Return Value

Returns non-zero if the argument is finite, and 0 if it is not.

Portability

POSIX Win32 ANSI C ANSI C++


_finite +
_finitel +

3.1.4.14.7 _fpclass, _fpclassl


Header File

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

POSIX Win32 ANSI C ANSI C++


_fpclass +
_fpclassl +

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

Reinitializes floating-point math package.

_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.

• If you use an 80x87 take the following precautions:


• Do not call system or an exec... or spawn... function while a floating-point expression is being evaluated.
Call _fpreset to reset the floating-point state after using system exec... or spawn... if there is any chance that the child process
performed a floating-point operation with the 80x87.
Return Value
None.
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.14.9 _isnan, _isnanl


Header File

float.h

Category

Classification Routines, Math Routines

Prototype
int _isnan(double d);
int _isnanl(long double ld);

Description

Tests whether a given double-precision floating-point value d is a NaN.

_isnanl is the long double version; it takes a long double argument.

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

3.1.4.14.10 _logb, _logbl


Header File

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

Returns the unbiased exponent of the value passed in.

Portability

POSIX Win32 ANSI C ANSI C++


_logb +
_logbl +

3.1.4.14.11 _nextafter, _nextafterl


Header File

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

POSIX Win32 ANSI C ANSI C++


_nextafter +
_nextafterl +

3.1.4.14.12 _scalb, _scalbl


Header File

float.h

Category

Math Routines

Prototype
double _scalb(double d, long exp);
long double _scalbl(long double ld, long exp);

Description

Scales the argument d by a power of 2.

_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

POSIX Win32 ANSI C ANSI C++


_scalb +
_scalbl +

3.1.4.14.13 _status87, _statusfp


Header File

float.h

Category

Math Routines
3
Prototype
unsigned int _status87(void);
unsigned int _statusfp(void);

Description

Gets floating-point status.

_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

the 80x87 exception handler.

_statusfp is identical to _status87 and is for Microsoft compatibility.

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

POSIX Win32 ANSI C ANSI C++


_status87 +
_statusfp +

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

_findfirsti64, _wfindfirsti64 ( see page 875) Header File


io.h, wchar.h
Category
Directory Control Routines
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...
more ( see page 875)
_findnext, __wfindnext ( see page 875) Header File
io.h, wchar.h
Category
Directory Control Routines
Prototype
long _findnext(long handle, struct _finddata_t *fileinfo);
long __wfindnext(long handle, struct _wfinddata_t
*fileinfo);
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.
These functions are... more ( see page 875)
_findnexti64, _wfindnexti64 ( see page 876) Header File
io.h, wchar.h
Category
Directory Control Routines
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).
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... more ( see page 876)
_get_osfhandle ( see page 877) Header File
io.h
Category
Input/output Routines
Prototype
long _get_osfhandle(int filehandle); 3
Description
Associates file handles.
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

865
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_open_osfhandle ( see page 879) Header File


io.h
Category
Input/output Routines
Prototype
int _open_osfhandle(long osfhandle, int flags);
Description
Associates file handles.
The _open_osfhandle function allocates a runtime file handle and sets it to point
to the operating system file handle specified by osfhandle.
The value flags is a bitwise OR combination of one or more of the following
manifest constants (defined in fcntl.h):
_rtl_chmod, _wrtl_chmod ( see page 880) Header File
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
Gets or sets file attributes.
Note: The _rtl_chmod function replaces _chmod
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.
attrib can be one of the following symbolic constants (defined in dos.h):
_rtl_close ( see page 881) Header File
io.h
Category
Input/output Routines
Prototype
int _rtl_close(int handle);
Description
Closes a file.
Note: This function replaces _close which is obsolete
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 success, _rtl_close returns 0.
On error (if it fails because handle is not the handle of a valid, open file),
_rtl_close... more ( see page 881)
_rtl_creat, _wrtl_creat ( see page 882) Header File
io.h
Category
Input/output Routines
Prototype
int _rtl_creat(const char *path, int attrib);
int _wrtl_creat(const wchar_t *path, int attrib);
Description
Creates a new file or overwrites an existing one.
Note: The _rtl_creat function replaces _creat,
which is obsolete_rtl_creat opens the file specified by path. The file is always
3 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... more ( see page 882)

866
3.1 C++ Reference RAD Studio C Runtime Library Reference

_rtl_open, _wrtl_open ( see page 883) Header File


io.h
Category
Input/output Routines
Prototype
int _rtl_open(const char *filename, int oflags);
int _wrtl_open(const wchar_t *path, int oflags);
Description
Opens a file for reading or writing.
Note: The _rtl_open function replaces _open which is obsolete.
_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...
more ( see page 883)
_rtl_read ( see page 885) Header File
io.h
Category
Input/output Routines
Prototype
int _rtl_read(int handle, void *buf, unsigned len);
Description
Reads from file.
Note: This function replaces _read which is obsolete.
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... more
( see page 885)
_rtl_write ( see page 886) Header File
io.h
Category
Input/output Routines
Prototype
int _rtl_write(int handle, void *buf, unsigned len);
Description
Writes to a file.
Note: This function replaces _write which is obsolete.
_rtl_write attempts to write len bytes from the buffer pointed to by buf to the file
associated with handle.
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... more ( see page 886)
access, _waccess ( see page 887) Header File
io.h
Category
Input/output Routines
Prototype
int access(const char *filename, int amode);
int _waccess(const wchar_t *filename, int amode); 3
Description
Determines accessibility of a file.
access checks the file named by filename to determine if it exists, and whether it
can be read, written to, or executed.
The list of amode values is as follows:

867
C Runtime Library Reference RAD Studio 3.1 C++ Reference

chmod, _wchmod ( see page 889) Header File


io.h
Category
Input/output Routines
Prototype
int chmod(const char *path, int amode);
int _wchmod(const wchar_t *path, int amode);
Description
Changes file access mode.
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).
chsize ( see page 890) Header File
io.h
Category
Input/output Routines
Prototype
int chsize(int handle, long size);
Description
Changes the file size.
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... more ( see page 890)
close ( see page 891) 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
Upon successful completion, close returns 0.
On error (if it fails because handle is not the handle of a valid, open file), close
returns a value of -1 and the... more ( see page 891)
_creat, _wcreat ( see page 892) Header File
io.h
Category
Input/output Routines
Prototype
int creat(const char *path, int amode);
int _wcreat(const wchar_t *path, int amode);
Description
Creates a new file or overwrites an existing one.
3 Note: Remember that a backslash in a path requires '\\'.
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... more ( see page 892)

868
3.1 C++ Reference RAD Studio C Runtime Library Reference

creatnew ( see page 893) Header File


io.h
Category
Input/output Routines
Prototype
int creatnew(const char *path, int mode);
Description
Creates a new file.
creatnew is identical to _rtl_creat with one exception: If the file exists, creatnew
returns an error and leaves the file untouched.
The mode argument to creatnew can be zero or an OR-combination of any one
of the following constants (defined in dos.h):
creattemp ( see page 894) Header File
io.h
Category
Input/output Routines
Prototype
int creattemp(char *path, int attrib);
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 automatically deleted when the program... more ( see page 894)
dup ( see page 895) Header File
io.h
Category
Input/output Routines
Prototype
int dup(int handle);
Description
Duplicates a file handle.

• 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... more ( see page
895)

869
C Runtime Library Reference RAD Studio 3.1 C++ Reference

dup2 ( see page 896) Header File


io.h
Category
Input/output Routines
Prototype
int dup2(int oldhandle, int newhandle);
Description
Duplicates a file handle (oldhandle) onto an existing file handle (newhandle).

• 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...
more ( see page 896)
eof ( see page 898) Header File
io.h
Category
Input/output Routines
Prototype
int eof(int handle);
Description
Checks for end-of-file.
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
filelength ( see page 899) Header File
io.h
Category
Input/output Routines
Prototype
long filelength(int handle);
Description
Gets file size in bytes.
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
getftime, setftime ( see page 899) Header File
io.h
Category
Input/output Routines
Prototype
int getftime(int handle, struct ftime *ftimep);
3 int setftime(int handle, struct ftime *ftimep);
Description
Gets and sets the file date and time.
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... more ( see page 899)

870
3.1 C++ Reference RAD Studio C Runtime Library Reference

isatty ( see page 901) Header File


io.h
Category
Input/output Routines
Prototype
int isatty(int handle);
Description
Checks for device type.
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
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

read ( see page 905) Header File


io.h
Category
Input/output Routines
Prototype
int read(int handle, void *buf, unsigned len);
Description
Reads from file.
read attempts to read len bytes from the file associated with handle into the
buffer pointed to by buf.
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... more ( see page 905)
setmode ( see page 906) Header File
io.h
Category
Input/output Routines
Prototype
int setmode(int handle, int amode);
Description
Sets mode of an open file.
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
tell ( see page 907) Header File
io.h
Category
Input/output Routines
Prototype
long tell(int handle);
Description
Gets the current position of a file pointer.
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
umask ( see page 908) Header File
io.h, sys\stat.h
Category
Input/output Routines
Prototype
unsigned umask(unsigned mode);
Description
Sets file read/write permission mask.
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:
3

872
3.1 C++ Reference RAD Studio C Runtime Library Reference

unlock ( see page 909) Header File


io.h
Category
Input/output Routines
Prototype
int unlock(int handle, long offset, long length);
Description
Releases file-sharing locks.
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
On success, unlock returns 0
O error, it returns -1.
Example
vsscanf ( see page 910) Header File
io.h
Category
Memory and String Manipulation Routines
Prototype
int vsscanf(const char *buffer, const char *format, va_list
arglist);
Description
Scans and formats input from a stream.
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.
Note: For details on format specifiers, see Scanf Format Specifiers.
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...
more ( see page 910)
write ( see page 911) Header File
io.h
Category
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... more ( see page 911)

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

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

POSIX Win32 ANSI C ANSI C++


_findclose +

See Also
_findfirst ( see page 874)

_findnext ( see page 875)

3.1.4.15.2 _findfirst, __wfindfirst


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 structure is filled with the file-directory information.

These functions are provided for Microsoft compatibility.

Return Value

On success, returns a unique search handle to a file or group of files matching the filter specification.

Otherwise, returns –1 and sets errno to one of the following values:

ENOENTPath or file name not found

EINVALInvalid filename specification


3
Portability

POSIX Win32 ANSI C ANSI C++


_findfirst +
__wfindfirst NT only

874
3.1 C++ Reference RAD Studio C Runtime Library Reference

See Also
_findclose ( see page 873)

_findnext ( see page 875)

3.1.4.15.3 _findfirsti64, _wfindfirsti64


Header File

io.h, wchar.h

Category

Directory Control Routines

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.

Otherwise, returns –1 and sets errno to one of the following values:

ENOENTFile specification that could not be matched

EINVALInvalid filename specification

Portability

POSIX Win32 ANSI C ANSI C++


_findfirsti64 +
_wfindfirsti64 NT only

3.1.4.15.4 _findnext, __wfindnext


Header File

io.h, wchar.h 3
Category

Directory Control Routines

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.

These functions are 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

POSIX Win32 ANSI C ANSI C++


_findnext +
__wfindnext NT only

See Also
_findclose ( see page 873)

_findfirst ( see page 874)

3.1.4.15.5 _findnexti64, _wfindnexti64


Header File

io.h, wchar.h

Category

Directory Control Routines

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

Otherwise, returns –1 and sets errno to:

ENOENTFile specification that could not be matched

Portability

POSIX Win32 ANSI C ANSI C++


_findnexti64 +
_wfindnexti64 NT only

3.1.4.15.6 _get_osfhandle
Header File

io.h

Category

Input/output Routines

Prototype
long _get_osfhandle(int filehandle);

Description

Associates file handles.

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

EBADF an invalid file handle

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

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.
/* 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 _get_osfhandle _open_osfhandle (32 bit)", // Text for window title bar.
WS_OVERLAPPEDWINDOW, // Window style.
CW_USEDEFAULT, // Default horizontal position.
CW_USEDEFAULT, // Default vertical position.
CW_USEDEFAULT, // Default width.
CW_USEDEFAULT, // Default height.
NULL, // Overlapped windows have no parent.
NULL, // Use the window class menu.
hInstance, // This instance owns this window.
NULL // Pointer not needed.
);
/* If window could not be created, return "failure" */
if (!hWnd)
return (FALSE);
/* Make the window visible; update its client area; and return "success" */
ShowWindow(hWnd, nCmdShow); // Show the window
UpdateWindow(hWnd); // Sends WM_PAINT message
return (hWnd); // Returns the value from PostQuitMessage
}
#pragma argsused
3 LRESULT FAR PASCAL _export MainWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
Example_get_osfhandle(hWnd);
return NULL;
}

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.7 _open_osfhandle
Header File

io.h

Category

Input/output Routines

Prototype
int _open_osfhandle(long osfhandle, int flags);

Description

Associates file handles.

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

On success, _open_osfhandle returns a C runtime file handle. Otherwise, it returns -1.

Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.8 _rtl_chmod, _wrtl_chmod


Header File

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

Gets or sets file attributes.

Note: The _rtl_chmod function replaces _chmod

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.

attrib can be one of the following symbolic constants (defined in dos.h):

FA_RDONLY Read-only attribute


FA_HIDDEN Hidden file
FA_SYSTEM System file
FA_LABEL Volume label
FA_DIREC Directory
FA_ARCH Archive

Return Value

On success, _rtl_chmod returns the file attribute word.

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

int get_file_attrib(char *filename);


int main(void)
{
char filename[128];
int attrib;
printf("Enter a filename:");
scanf("%s", filename);
attrib = get_file_attrib(filename);
if (attrib == -1)
switch(errno)
{
case ENOENT : printf("Path or file not found.\n");
break;
case EACCES : printf("Permission denied.\n");
break;
default: printf("Error number: %d", errno);
break;
}
else
{
if (attrib & FA_RDONLY)
printf("%s is read-only.\n", filename);
if (attrib & FA_HIDDEN)
printf("%s is hidden.\n", filename);
if (attrib & FA_SYSTEM)
printf("%s is a system file.\n", filename);
if (attrib & FA_DIREC)
printf("%s is a directory.\n", filename);
if (attrib & FA_ARCH)
printf("%s is an archive file.\n", filename);
}
return 0;
}
/* returns the attributes of a DOS file */
int get_file_attrib(char *filename)
{
return(_rtl_chmod(filename, 0));
}
Portability

POSIX Win32 ANSI C ANSI C++


_rtl_chmod +
_wrtl_chmod NT only

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

Note: This function replaces _close which is obsolete

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 success, _rtl_close returns 0.

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

EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.10 _rtl_creat, _wrtl_creat


Header File

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

Creates a new file or overwrites an existing one.

Note: The _rtl_creat function replaces _creat,

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):

FA_RDONLY Read-only attribute


FA_HIDDEN Hidden file
FA_SYSTEM System file

Return Value

On success, _rtl_creat returns the new file handle (a non-negative integer).

On error, it returns -1 and sets the global variable errno to one of the following values:

EACCESPermission denied

EMFILEToo many open files

ENOENTPath or file name not found

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

POSIX Win32 ANSI C ANSI C++


_rtl_crea +
_wrtl_creat NT only

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

Opens a file for reading or writing.

Note: The _rtl_open function replaces _open which is obsolete.

_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.

O_RDONLY Open for reading.


O_WRONLY Open for writing.
O_RDWR Open for reading and writing.

The following additional values can be included in oflags (using an OR operation):

O_NOINHERIT The file is not passed to child programs.


SH_COMPAT Allow other opens with SH_COMPAT. All other openings of a file with the SH_COMPAT flag must be
opened using SH_COMPAT flag. You can request a file open that uses SH_COMPAT logically OR’ed
with some other flag (for example, SH_COMPAT | SH_DENWR is allowed). The call will fail if the file
has already been opened in any other shared mode.
SH_DENYRW Only the current handle can have access to the file.
SH_DENWR Allow only reads from any other open to the file.
SH_DENYRD Allow only writes from any other open to the file.
SH_DENYNO Allow other shared opens to the file, but not other SH_COMPAT opens.

Note: These symbolic constants are defined in fcntl.h and share.h.

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.

The maximum number of simultaneously open files is defined by HANDLE_MAX.

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:

3 EACCES Permission denied


EINVACC Invalid access code
EMFILE Too many open files
ENOENT Path or file not found

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

POSIX Win32 ANSI C ANSI C++


_rtl_open +
_wrtl_open NT only

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

Reads from file.

Note: This function replaces _read which is obsolete.

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

On success, _rtl_read returns either

• a positive integer, indicating the number of bytes placed in the buffer


• zero, indicating end-of-file
On error, it returns -1 and sets the global variable errno to one of the following values:

885
C Runtime Library Reference RAD Studio 3.1 C++ Reference

EACCES Permission denied


EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


+

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.

Note: This function replaces _write which is obsolete.

_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 success, _rtl_write returns number of bytes written.

On error, it returns -1 and sets the global variable errno to one of the following values:

EACCES Permission denied


EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


3
+

3.1.4.15.14 access, _waccess


Header File

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

Determines accessibility of a file.

access checks the file named by filename to determine if it exists, and whether it can be read, written to, or executed.

The list of amode values is as follows:

06 Check for read and write permission


04 Check for read permission
02 Check for write permission
01 Execute (ignored)
00 Check for existence of file

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:

ENOENT Path or file name not found


EACCES Permission denied

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

POSIX Win32 ANSI C ANSI C++


access + +
_waccess NT only

888
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.15.15 chmod, _wchmod


Header File

io.h

Category

Input/output Routines

Prototype
int chmod(const char *path, int amode);
int _wchmod(const wchar_t *path, int amode);

Description

Changes file access mode.

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).

S_IWRITE Permission to write


S_IREAD Permission to read
S_IREAD | S_IWRITE Permission to read and write (write permission implies read permission)

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:

EACCES Permission denied


ENOENT Path or file name not found

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

POSIX Win32 ANSI C ANSI C++


chmod + +
_wchmod NT only

3.1.4.15.16 chsize
Header File

io.h

Category

Input/output Routines

Prototype
int chsize(int handle, long size);

Description

Changes the file size.

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:

EACCES Permission denied


EBADF Bad file number
ENOSPC No space left on device
3
Example
#include <string.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char buf[11] = "0123456789";

890
3.1 C++ Reference RAD Studio C Runtime Library Reference

/* create text file containing 10 bytes */


handle = open("DUMMY.FIL", O_CREAT);
write(handle, buf, strlen(buf));
/* truncate the file to 5 bytes in size */
chsize(handle, 5);
/* close the file */
close(handle);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

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

Upon successful completion, close returns 0.

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

EBADF Bad file number

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

close(handle); /* close the file */


}
else
{
printf("Error opening file\n");
}
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+ +

3.1.4.15.18 _creat, _wcreat


Header File

io.h

Category

Input/output Routines

Prototype
int creat(const char *path, int amode);
int _wcreat(const wchar_t *path, int amode);

Description

Creates a new file or overwrites an existing one.

Note: Remember that a backslash in a path requires '\\'.

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.

amode can be one of the following (defined in sys\stat.h):

S_IWRITE Permission to write


S_IREAD Permission to read

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

EACCES Permission denied


ENOENT Path or file name not found
EMFILE Too many open files

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

POSIX Win32 ANSI C ANSI C++


creat + +
_wcreat NT only

3.1.4.15.19 creatnew
Header File

io.h

Category

Input/output Routines

Prototype
int creatnew(const char *path, int mode);

Description

Creates a new file.

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):

FA_HIDDEN Hidden file


FA_RDONLY Read-only attribute
FA_SYSTEM System file

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:

EACCES Permission denied


EEXIST File already exists
EMFILE Too many open files
ENOENT Path or file name not found

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

POSIX Win32 ANSI C ANSI C++


+

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

automatically deleted when the program terminates.

The attrib argument to creattemp can be zero or an OR-combination of any one of the following constants (defined in dos.h):

FA_HIDDEN Hidden file


FA_RDONLY Read-only attribute
FA_SYSTEM System file

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:

EACCES Permission denied


EMFILE Too many open files
ENOENT Path or file name not found

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.21 dup
Header File

io.h

Category
3
Input/output Routines

Prototype
int dup(int handle);

Description

Duplicates a file handle.

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:

EBADF Bad file number


EMFILE Too many open files

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

POSIX Win32 ANSI C ANSI C++


+ +
3

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

Duplicates a file handle (oldhandle) onto an existing file handle (newhandle).

• 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

POSIX Win32 ANSI C ANSI C++


+ +

3.1.4.15.23 eof
Header File

io.h

Category

Input/output Routines

Prototype
int eof(int handle);

Description

Checks for end-of-file.

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

EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.24 filelength
Header File

io.h

Category

Input/output Routines

Prototype
long filelength(int handle);

Description

Gets file size in bytes.

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

EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


3
+

3.1.4.15.25 getftime, setftime


Header File

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

Gets and sets the file date and time.

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.

The ftime structure is defined as follows:


struct ftime {
unsigned ft_tsec: 5; /* two seconds */
unsigned ft_min: 6; /* minutes */
unsigned ft_hour: 5; /* hours */
unsigned ft_day: 5; /* days */
unsigned ft_month: 4; /* months */
unsigned ft_year: 7; /* year - 1980*/
};

Return Value

getftime and setftime return 0 on success.

In the event of an error return -1 is returned and the global variable errno is set to one of the following values:

EACCES Permission denied


EBADF Bad file number
EINVFNC Invalid function number

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

printf("File time: %u:%u:%u\n",


ft.ft_hour, ft.ft_min,
ft.ft_tsec * 2);
printf("File date: %u/%u/%u\n",
ft.ft_month, ft.ft_day,
ft.ft_year+1980);
fclose(stream);
return 0;
}

3.1.4.15.26 isatty
Header File

io.h

Category

Input/output Routines

Prototype
int isatty(int handle);

Description

Checks for device type.

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

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

EACCES Locking violation

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

POSIX Win32 ANSI C ANSI C++


+

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

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 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:

EACCES File already locked or unlocked


EBADF Bad file number
EDEADLOCK File cannot be locked after 10 retries (cmd is LK_LOCK or LK_RLCK)
EINVAL Invalid cmd, or SHARE.EXE not loaded

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.29 lseek
Header File

io.h

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):

SEEK_CUR Current file pointer position


SEEK_END End-of-file
SEEK_SET File beginning

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:

EBADF Bad file handle


EINVAL Invalid argument
ESPIPE Illegal seek on device

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

POSIX Win32 ANSI C ANSI C++


+ +

3.1.4.15.30 read
Header File

io.h

Category

Input/output Routines

Prototype
int read(int handle, void *buf, unsigned len);

Description

Reads from file.

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:

EACCES Permission denied


EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


+ +

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

Sets mode of an open file.

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

EINVAL Invalid argument

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

POSIX Win32 ANSI C ANSI C++


+

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

long tell(int handle);

Description

Gets the current position of a file pointer.

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

EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.33 umask
Header File

io.h, sys\stat.h

Category

Input/output Routines

Prototype
3
unsigned umask(unsigned mode);

Description

Sets file read/write permission mask.

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

S_IWRITE Permission to write


S_IREAD Permission to read
S_IREAD|S_IWRITE Permission to read and write

Return Value

The previous value of the mask. There is no error return.

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

POSIX Win32 ANSI C ANSI C++


+ +

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

Releases file-sharing locks.

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

On success, unlock returns 0

O error, it returns -1.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.15.35 vsscanf
3 Header File

io.h

Category

Memory and String Manipulation Routines

Prototype
int vsscanf(const char *buffer, const char *format, va_list arglist);

910
3.1 C++ Reference RAD Studio C Runtime Library Reference

Description

Scans and formats input from a stream.

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.

Note: For details on format specifiers, see Scanf Format Specifiers.

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.

If vsscanf attempts to read at end-of-string, the return value is EOF.

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

POSIX Win32 ANSI C ANSI C++


+ + +
3

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:

EACCES Permission denied


EBADF Bad file number

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

POSIX Win32 ANSI C ANSI C++


+ +

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

3.1.4.16.1 CHAR_xxx #defines


Header File

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.

3.1.4.16.2 INT_xxx #defines


Header File

913
C Runtime Library Reference RAD Studio 3.1 C++ Reference

limits.h

Description

Maximum and minimum value for type int.

Name Meaning
INT_MAX Type int, maximum value
INT_MIN Type int, minimum value

3.1.4.16.3 LONG_xxx #defines


Header File

limits.h

Description

Maximum and minimum value for type long.

Name Meaning
LONG_MAX Type long, maximum value
LONG_MIN Type long, minimum value

3.1.4.16.4 SCHAR_xxx #defines


Header File

limits.h

Description

Name Meaning
SCHAR_MAX Type char, maximum value
SCHAR_MIN Type char, minimum value

3.1.4.16.5 SHRT_xxx #defines


Header File

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

3.1.4.16.6 Uxxxx_MAX #defines


Header File

limits.h

Description

Name Maximum value for type xxx


UCHAR_MAX unsigned char
USHRT_MAX unsigned short
UINT_MAX unsigned integer
ULONG_MAX unsigned long

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

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:

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:

CHAR_MAX No further grouping is to be performed.


0 The previous element is to be used repeatedly for the remainder of the digits.
any other integer Indicates how many digits make up the current group. The next element is read to determine the size
of the next group of digits before the current group.

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:

0 Use parentheses to surround the quantity and currency_symbol.


1 Sign string precedes the quantity and currency_symbol.
2 Sign string succeeds the quantity and currency_symbol.
3 Sign string immediately precedes the quantity and currency_symbol.
4 Sign string immediately succeeds the quantity and currency_symbol.

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 = &ll;
/* 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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.17.2 setlocale, _wsetlocale


3
Header File

locale.h

Category

Miscellaneous Routines

Prototype

917
C Runtime Library Reference RAD Studio 3.1 C++ Reference

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:

LC_ALL Affects all the following categories


LC_COLLATE Affects strcoll and strxfrm
LC_CTYPE Affects single-byte character handling functions. The mbstowcs and mbtowc functions are not
affected.
LC_MONETARY Affects monetary formatting by the localeconv function
LC_NUMERIC Affects the decimal point of non-monetary data formatting. This includes the printf family of functions,
and the information returned by localeconv.
LC_TIME Affects strftime

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 );
.
.
.

An example of the output here could be the following:


LC_COLLATE=English_United States.437;
LC_TIME=English_United States.437;
LC_CTYPE=English_United States.437;

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.

To set all default categories for the specified French locale:


setlocale( LC_ALL, "French_France.850" );

To find out which code page is currently being used:


localenameptr = setlocale( LC_ALL, NULL );

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.

If UNICODE is defined, _wsetlocale returns a wchar_t string.

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

POSIX Win32 ANSI C ANSI C++


setlocale + + + +
_wsetlocale +

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

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
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

POSIX Win32 ANSI C ANSI C++


+

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

atof, _wtof ( see page 933) Header File


stdlib.h, math.h
Category
Conversion Routines, Math Routines
Prototype
double atof(const char *s);
double _wtof(const wchar_t *s);
Description
Converts a string to a floating-point number.

• 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... more ( see page
933)
_atold, _wtold ( see page 933) Header File
math.h
Category
Conversion Routines, Math Routines
Prototype
long double _atold(const char *s);
long double _wtold(const wchar_t *s);
Description
Converts a string to a long double.
_wtold is the wide-character version. It converts a wide-character string to a long
double.
_atof is the floating-point version of _atold.
_atold converts a string pointed to by s to a long double; this functions
recognizes:
An optional string of tabs and spaces
An optional sign
A string of digits and an optional decimal point
An optional e or E followed by an optional signed integer
The first unrecognized character ends... more ( see page 933)
_i64toa, _i64tow ( see page 934) Header File
math.h, stdlib.h
Category
Conversion Routines, Math Routines,
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... more ( see page 934)

922
3.1 C++ Reference RAD Studio C Runtime Library Reference

_matherr, _matherrl ( see page 935) Header File


math.h
Category
Diagnostic Routines, Math Routines
Prototype
int _matherr(struct _exception *e);
int _matherrl(struct _exceptionl *e);
Description
User-modifiable math error handler.
_matherr is called when an error is generated by the math library.
_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... more ( see page 935)
abs ( see page 936) Header File
stdlib.h, math.h
Category
Math Routines, Inline Routines
Prototype
int abs(int x);
Description
Returns the absolute value of an integer.
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
in your program, after the #include <stdlib.h>.
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... more ( see
page 936)
acos, acosl ( see page 937) Header File
math.h
Category
Math Routines
Prototype
double acos(double x);
long double acosl(long double x);
Description
Calculates the arc cosine.
acos returns the arc cosine of the input value.
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:
EDOM Domain error
Return Value
acos and acosl of an argument between -1 and +1 return a value in the range 0
to pi. Error... more ( see page 937)

923
C Runtime Library Reference RAD Studio 3.1 C++ Reference

asin, asinl ( see page 938) Header File


math.h
Category
Math Routines
Prototype
double asin(double x);
long double asinl(long double x);
Description
Calculates the arc sine.
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
EDOM Domain error
Return Value
asin and asinl of a real argument return a value in the range -pi/2 to... more (
see page 938)
atan, atanl ( see page 939) Header File
math.h
Category
Math Routines
Prototype
double atan(double x);
long double atanl(long double x);
Description
Calculates the arc tangent.
atan calculates the arc tangent of the input value.
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
atan2, atan2l ( see page 940) Header File
math.h
Category
Math Routines
Prototype
double atan2(double y, double x);
long double atan2l(long double y, long double x);
Description
Calculates the arc tangent of y/x.
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... more ( see page 940)

924
3.1 C++ Reference RAD Studio C Runtime Library Reference

cabs, cabsl ( see page 940) Header File


math.h
Category
Math Routines
Prototype
double cabs(struct complex z);
long double cabsl(struct _complexl z);
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;
};
where x is the real part, and y is the imaginary part.
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... more ( see page 940)
ceil, ceill ( see page 942) Header File
math.h
Category
Math Routines
Prototype
double ceil(double x);
long double ceill(long double x);
Description
Rounds up.
ceil finds the smallest integer not less than x.
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
cos, cosl ( see page 943) Header File
math.h
Category
Math Routines, Inline Routines
Prototype
double cos(double x);
long double cosl(long double x);
Description
Calculates the cosine of a value.
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

925
C Runtime Library Reference RAD Studio 3.1 C++ Reference

cosh, coshl ( see page 943) Header File


math.h
Category
Math Routines
Prototype
double cosh(double x);
long double coshl(long double x);
Description
Calculates the hyperbolic cosine of a value.
cosh computes the hyperbolic cosine:
coshl is the long double version; it takes a long double argument and returns a
long double result.
Return Value
cosh returns the hyperbolic cosine of the argument.
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... more ( see page 943)
exp, expl ( see page 944) Header File
math.h
Category
Math Routines
Prototype
double exp(double x);
long double expl(long double x);
Description
Calculates the exponential e to the x.
expl is the long double version; it takes a long double argument and returns a
long double result.
Return Value
exp returns e to the x.
Sometimes the arguments passed to these functions produce results that
overflow or are incalculable. When the correct value 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
fabs, fabsl ( see page 945) Header File
math.h
Category
Math Routines
Prototype
double fabs(double x);
long double fabsl(long double x);
Description
Returns the absolute value of a floating-point number.
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.
Return Value
fabs and fabsl return the absolute value of x.
Example
floor, floorl ( see page 946) Header File
math.h
Category
Math Routines
Prototype
double floor(double x);
3 long double floorl(long double x);
Description
Rounds down.
floor finds the largest integer not greater than x.
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

926
3.1 C++ Reference RAD Studio C Runtime Library Reference

fmod, fmodl ( see page 946) Header File


math.h
Category
Math Routines
Prototype
double fmod(double x, double y);
long double fmodl(long double x, long double y);
Description
Calculates x modulo y, the remainder of x/y.
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
frexp, frexpl ( see page 947) Header File
math.h
Category
Math Routines
Prototype
double frexp(double x, int *exponent);
long double frexpl(long double x, int *exponent);
Description
Splits a number into mantissa and exponent.
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 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.... more ( see page 947)
hypot, hypotl ( see page 948) Header File
math.h
Category
Math Routines
Prototype
double hypot(double x, double y);
long double hypotl(long double x, long double y);
Description
Calculates hypotenuse of a right triangle.
hypot calculates the value z where
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)... more
( see page 948)

927
C Runtime Library Reference RAD Studio 3.1 C++ Reference

ldexp, ldexpl ( see page 949) Header File


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
ldiv ( see page 950) Header File
math.h
Category
Math Routines
Prototype
ldiv_t ldiv(long int numer, long int denom);
Description
Divides two longs, returning quotient and remainder.
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.
The ldiv_t type is a structure of longs defined in stdlib.h as follows:
typedef struct {
long int quot; /* quotient */
long int rem; /* remainder */
} ldiv_t;
Return Value
ldiv returns a structure whose elements are quot (the quotient) and rem (the
remainder).
Example
log, logl ( see page 950) Header File
math.h
Category
Math Routines
Prototype
double log(double x);
long double logl(long double x);
Description
Calculates the natural logarithm of x.
log calculates the natural logarithm of x.
logl is the long double version; it takes a long double argument and returns a
long double result.
Return Value
On success, log and logl return the value calculated, ln(x).
errno
log10, log10l ( see page 951) Header File
math.h
Category
Math Routines
3 Prototype
double log10(double x);
long double log10l(long double x);
Description
log10 calculates the base ten logarithm of x.
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

928
3.1 C++ Reference RAD Studio C Runtime Library Reference

modf, modfl ( see page 952) Header File


math.h
Category
Math Routines
Prototype
double modf(double x, double *ipart);
long double modfl(long double x, long double *ipart);
Description
Splits a double or long double into integer and fractional parts.
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
modf and modfl return the fractional part of x.
Example
poly, polyl ( see page 953) Header File
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
Generates a polynomial from arguments.
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
pow, powl ( see page 954) Header File
math.h
Category
Math Routines
Prototype
double pow(double x, double y);
long double powl(long double x, long double y);
Description
Calculates x to the power of y.
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... more ( see page 954)

929
C Runtime Library Reference RAD Studio 3.1 C++ Reference

pow10, pow10l ( see page 955) Header File


math.h
Category
Math Routines
Prototype
double pow10(int p);
long double pow10l(int p);
Description
Calculates 10 to the power of p.
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
sin, sinl ( see page 955) Header File
math.h
Category
Math Routines
Prototype
double sin(double x);
long double sinl(long double x);
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
sin and sinl return the sine of the input value.
Example
sinh, sinhl ( see page 956) Header File
math.h
Category
Math Routines, Inline Routines
Prototype
double sinh(double x);
long double sinhl(long double x);
Description
Calculates hyperbolic sine.
sinh computes the hyperbolic sine.
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
sinh and sinhl return the hyperbolic sine of x.
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

930
3.1 C++ Reference RAD Studio C Runtime Library Reference

sqrt, sqrtl ( see page 957) Header File


math.h
Category
Math Routines
Prototype
double sqrt(double x);
long double sqrtl(long double x);
Description
Calculates the positive square root.
sqrt calculates the positive square root of the argument x.
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... more ( see page 957)
tan, tanl ( see page 958) Header File
math.h
Category
Math Routines
Prototype
double tan(double x);
long double tanl(long double x);
Description
Calculates the tangent.
tan calculates the tangent. Angles are specified in radians.
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
tan and tanl return the tangent of x, sin(x)/cos(x).
Example
tanh, tanhl ( see page 958) Header File
math.h
Category
Math Routines
Prototype
double tanh(double x);
long double tanhl(long double x);
Description
Calculates the hyperbolic tangent.
tanh computes the hyperbolic tangent, sinh(x)/cosh(x).
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
tanh and tanhl return the hyperbolic tangent of x.
Example

3.1.4.19.1 HUGE_VAL #defines


Header File
3
math.h

Description

Overflow value for math functions.

931
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.19.2 M_E, M_LOGxxx, M_LNxx #defines


Header File

math.h

Description

The constant values for logarithm functions.

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)

3.1.4.19.3 M_SQRTxx #defines


Header File

math.h

Description

Constant values for square roots of 2.

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

3.1.4.19.5 atof, _wtof


Header File

stdlib.h, math.h

Category

Conversion Routines, Math Routines

Prototype
double atof(const char *s);
double _wtof(const wchar_t *s);

Description

Converts a string to a floating-point number.

• 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.

3.1.4.19.6 _atold, _wtold


Header File

math.h

Category

Conversion Routines, Math Routines 3


Prototype
long double _atold(const char *s);
long double _wtold(const wchar_t *s);

Description

Converts a string to a long double.

933
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_wtold is the wide-character version. It converts a wide-character string to a long double.

_atof is the floating-point version of _atold.

_atold converts a string pointed to by s to a long double; this functions recognizes:

An optional string of tabs and spaces

An optional sign

A string of digits and an optional decimal point

An optional e or E followed by an optional signed integer

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

Returns the converted value of the input string.

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

POSIX Win32 ANSI C ANSI C++


_atold +
_wtold +

3.1.4.19.7 _i64toa, _i64tow


Header File

math.h, stdlib.h

Category

Conversion Routines, Math Routines,

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

Returns a pointer to string.

934
3.1 C++ Reference RAD Studio C Runtime Library Reference

Portability

POSIX Win32 ANSI C ANSI C++


_i64toa +
_i64tow +

3.1.4.19.8 _matherr, _matherrl


Header File

math.h

Category

Diagnostic Routines, Math Routines

Prototype
int _matherr(struct _exception *e);
int _matherrl(struct _exceptionl *e);

Description

User-modifiable math error handler.

_matherr is called when an error is generated by the math library.

_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.

Here are the _exception and _exceptionl structures (defined in math.h):


struct _exception {
int type;
char *name;
double arg1, arg2, retval;
};
3
struct _exceptionl {
int type;
char *name;
long double arg1, arg2, retval;
};

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:

DOMAIN Argument was not in domain of function, such as log(-1).


SING Argument would result in a singularity, such as pow(0, -2).
OVERFLOW Argument would produce a function result greater than DBL_MAX (or LDBL_MAX), such as
exp(1000).
UNDERFLOW Argument would produce a function result less than DBL_MIN (or LDBL_MIN), such as exp(-1000).
TLOSS Argument would produce function result with total loss of significant digits, such as sin(10e70).

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

Math Routines, Inline Routines

Prototype

936
3.1 C++ Reference RAD Studio C Runtime Library Reference

int abs(int x);

Description

Returns the absolute value of an integer.

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

in your program, after the #include <stdlib.h>.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.19.10 acos, acosl


Header File

math.h

Category

Math Routines

Prototype
double acos(double x);
long double acosl(long double x);

Description

Calculates the arc cosine. 3


acos returns the arc cosine of the input value.

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:

EDOM Domain error

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

POSIX Win32 ANSI C ANSI C++


acos + + + +
acosl + + +

3.1.4.19.11 asin, asinl


Header File

math.h

Category

Math Routines

Prototype
double asin(double x);
long double asinl(long double x);

Description

Calculates the arc sine.

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

EDOM Domain error

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

POSIX Win32 ANSI C ANSI C++


asin + + + +
asinl + + +

3.1.4.19.12 atan, atanl


Header File

math.h

Category

Math Routines

Prototype
double atan(double x);
long double atanl(long double x);

Description

Calculates the arc tangent.

atan calculates the arc tangent of the input value.

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

POSIX Win32 ANSI C ANSI C++


atan + + + +
atanl + + +

939
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.19.13 atan2, atan2l


Header File

math.h

Category

Math Routines

Prototype
double atan2(double y, double x);
long double atan2l(long double y, long double x);

Description

Calculates the arc tangent of y/x.

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

POSIX Win32 ANSI C ANSI C++


atan2 + + + +
atan2l + + +

3.1.4.19.14 cabs, cabsl


3 Header File

math.h

Category

Math Routines

Prototype
double cabs(struct complex z);

940
3.1 C++ Reference RAD Studio C Runtime Library Reference

long double cabsl(struct _complexl z);

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;
};

where x is the real part, and y is the imaginary part.

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

ERANGE Result out of range

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

POSIX Win32 ANSI C ANSI C++


cabs +
cabsl +

3.1.4.19.15 ceil, ceill


Header File

math.h

Category

Math Routines

Prototype
double ceil(double x);
long double ceill(long double x);

Description

Rounds up.

ceil finds the smallest integer not less than x.

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

POSIX Win32 ANSI C ANSI C++


ceil + + + +
ceill + + +

942
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.19.16 cos, cosl


Header File

math.h

Category

Math Routines, Inline Routines

Prototype
double cos(double x);
long double cosl(long double x);

Description

Calculates the cosine of a value.

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

POSIX Win32 ANSI C ANSI C++


cos + + + +
cosl + + +

3.1.4.19.17 cosh, coshl


Header File
3
math.h

Category

Math Routines

Prototype
double cosh(double x);

943
C Runtime Library Reference RAD Studio 3.1 C++ Reference

long double coshl(long double x);

Description

Calculates the hyperbolic cosine of a value.

cosh computes the hyperbolic cosine:

coshl is the long double version; it takes a long double argument and returns a long double result.

Return Value

cosh returns the hyperbolic cosine of the argument.

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

POSIX Win32 ANSI C ANSI C++


cosh + + + +
coshl + + +

3.1.4.19.18 exp, expl


Header File

math.h

Category

Math Routines

Prototype
double exp(double x);
long double expl(long double x);
3 Description

Calculates the exponential e to the x.

expl is the long double version; it takes a long double argument and returns a long double result.

Return Value

exp returns e to the x.

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

ERANGE Result out of range

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

POSIX Win32 ANSI C ANSI C++


exp + + + +
expl + + +

3.1.4.19.19 fabs, fabsl


Header File

math.h

Category

Math Routines

Prototype
double fabs(double x);
long double fabsl(long double x);

Description

Returns the absolute value of a floating-point number.

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

fabs and fabsl return the absolute value of x.

Example
#include <stdio.h>
#include <math.h>
int main(void)
{

945
C Runtime Library Reference RAD Studio 3.1 C++ Reference

float number = -1234.0;

printf("number: %f absolute value: %f\n", number, fabs(number));


return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


fabs + + + +
fabsl + + +

3.1.4.19.20 floor, floorl


Header File

math.h

Category

Math Routines

Prototype
double floor(double x);
long double floorl(long double x);

Description

Rounds down.

floor finds the largest integer not greater than x.

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

POSIX Win32 ANSI C ANSI C++


floor + + + +
floorl + + +

3.1.4.19.21 fmod, fmodl


Header File
3
math.h

Category

Math Routines

Prototype
double fmod(double x, double y);

946
3.1 C++ Reference RAD Studio C Runtime Library Reference

long double fmodl(long double x, long double y);

Description

Calculates x modulo y, the remainder of x/y.

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

POSIX Win32 ANSI C ANSI C++


fmod + + + +
fmodl + + +

3.1.4.19.22 frexp, frexpl


Header File

math.h

Category

Math Routines

Prototype
double frexp(double x, int *exponent);
long double frexpl(long double x, int *exponent);

Description

Splits a number into mantissa and exponent.

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

POSIX Win32 ANSI C ANSI C++


frexp + + + +
frexpl + + +

3.1.4.19.23 hypot, hypotl


Header File

math.h

Category

Math Routines

Prototype
double hypot(double x, double y);
long double hypotl(long double x, long double y);

Description

Calculates hypotenuse of a right triangle.

hypot calculates the value z where

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

POSIX Win32 ANSI C ANSI C++


hypot + + +
hypotl + + +

3.1.4.19.24 ldexp, ldexpl


Header File

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

POSIX Win32 ANSI C ANSI C++


ldexp + + + +

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

Divides two longs, returning quotient and remainder.

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.

The ldiv_t type is a structure of longs defined in stdlib.h as follows:


typedef struct {
long int quot; /* quotient */
long int rem; /* remainder */
} ldiv_t;

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

POSIX Win32 ANSI C ANSI C++


3 + + + +

3.1.4.19.26 log, logl


Header File

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

Calculates the natural logarithm of x.

log calculates the natural logarithm of x.

logl is the long double version; it takes a long double argument and returns a long double result.

Return Value

On success, log and logl return the value calculated, ln(x).

errno

EDOM Domain error

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

POSIX Win32 ANSI C ANSI C++


log + + + +
logl + + +

3.1.4.19.27 log10, log10l


Header File

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

log10 calculates the base ten logarithm of x.

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

EDOM Domain error

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

POSIX Win32 ANSI C ANSI C++


log10 + + + +
log10l + + +

3.1.4.19.28 modf, modfl


Header File

math.h

Category

Math Routines

Prototype
double modf(double x, double *ipart);
long double modfl(long double x, long double *ipart);
3 Description

Splits a double or long double into integer and fractional parts.

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

modf and modfl return the fractional part of x.

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

POSIX Win32 ANSI C ANSI C++


modf + + + +
modfl + + +

3.1.4.19.29 poly, polyl


Header File

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

Generates a polynomial from arguments.

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

POSIX Win32 ANSI C ANSI C++


poly +
polyl +

3.1.4.19.30 pow, powl


Header File

math.h

Category

Math Routines

Prototype
double pow(double x, double y);
long double powl(long double x, long double y);

Description

Calculates x to the power of y.

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

ERANGE Result out of range

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

EDOM Domain error

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

POSIX Win32 ANSI C ANSI C++


pow + + + +

954
3.1 C++ Reference RAD Studio C Runtime Library Reference

powl + + +

3.1.4.19.31 pow10, pow10l


Header File

math.h

Category

Math Routines

Prototype
double pow10(int p);
long double pow10l(int p);

Description

Calculates 10 to the power of p.

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

POSIX Win32 ANSI C ANSI C++


pow10 +
pow10l +

3.1.4.19.32 sin, sinl


3
Header File

math.h

Category

Math Routines

Prototype

955
C Runtime Library Reference RAD Studio 3.1 C++ Reference

double sin(double x);


long double sinl(long double x);

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

sin and sinl return the sine of the input 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

POSIX Win32 ANSI C ANSI C++


sin + + + +
sinl + + +

3.1.4.19.33 sinh, sinhl


Header File

math.h

Category

Math Routines, Inline Routines

Prototype
double sinh(double x);
long double sinhl(long double x);

Description

3 Calculates hyperbolic sine.

sinh computes the hyperbolic sine.

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

sinh and sinhl return the hyperbolic sine of x.

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

POSIX Win32 ANSI C ANSI C++


sinh + + + +
sinhl + + +

3.1.4.19.34 sqrt, sqrtl


Header File

math.h

Category

Math Routines

Prototype
double sqrt(double x);
long double sqrtl(long double x);

Description

Calculates the positive square root.

sqrt calculates the positive square root of the argument x.

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

EDOM Domain error


3
Example
#include <math.h>
#include <stdio.h>
int main(void)
{
double x = 4.0, result;
result = sqrt(x);
printf("The square root of %lf is %lf\n", x, result);

957
C Runtime Library Reference RAD Studio 3.1 C++ Reference

return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


sqrt + + + +
sqrtl + + +

3.1.4.19.35 tan, tanl


Header File

math.h

Category

Math Routines

Prototype
double tan(double x);
long double tanl(long double x);

Description

Calculates the tangent.

tan calculates the tangent. Angles are specified in radians.

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

tan and tanl return the tangent of x, sin(x)/cos(x).

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

3 POSIX Win32 ANSI C ANSI C++


tan + + + +
tanl + + +

3.1.4.19.36 tanh, tanhl


Header File

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

Calculates the hyperbolic tangent.

tanh computes the hyperbolic tangent, sinh(x)/cosh(x).

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

tanh and tanhl return the hyperbolic tangent of x.

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

POSIX Win32 ANSI C ANSI C++


tanh + + + +
tanhl + + +

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:

• The character c is first copied into dest.


• n bytes have been copied into dest.
Return Value
memccpy returns a pointer to the byte in dest immediately
following c, if c was copied; otherwise, memccpy returns
NULL.
Example
memchr, _wmemchr ( see page 963) Header File
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
Searches n bytes for character c.
memchr is available on UNIX System V systems.
memchr searches the first n bytes of the block pointed to by s for... more ( see
page 963)
memcmp ( see page 964) Header File
mem.h, string.h
Category
Memory and String Manipulation Routines, Inline Routines
Prototype
int memcmp(const void *s1, const void *s2, size_t n);
Description
Compares two blocks for a length of exactly n bytes.
memcmp is available on UNIX System V systems.
memcmp compares the first n bytes of the blocks s1 and s2 as unsigned chars.
Return Value
Because it compares bytes as unsigned chars, memcmp returns a value that is
3
• < 0 if s1 is less than s2
• = 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
For... more ( see page 964)

960
3.1 C++ Reference RAD Studio C Runtime Library Reference

memcpy, _wmemcpy ( see page 965) Header File


mem.h, string.h
Category
Memory and String Manipulation Routines, Inline Routines
Prototype
void *memcpy(void *dest, const void *src, size_t n);
void *_wmemcpy(void *dest, const void *src, size_t n);
Description
Copies a block of n bytes.
memcpy is available on UNIX System V systems.
memcpy copies a block of n bytes from src to dest. If src and dest overlap, the
behavior of memcpy is undefined.
Return Value
memcpy returns dest.
Example
memicmp ( see page 965) Header File
mem.h, string.h
Category
Memory and String Manipulation Routines
Prototype
int memicmp(const void *s1, const void *s2, size_t n);
Description
Compares n bytes of two character arrays, ignoring case.
memicmp is available on UNIX System V systems.
memicmp compares the first n bytes of the blocks s1 and s2, ignoring character
case (upper or lower).
Return Value
memicmp returns a value that is

• < 0 if s1 is less than s2


• = 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
Example
memmove ( see page 966) Header File
mem.h, string.h
Category
Memory and String Manipulation Routines
Prototype
void *memmove(void *dest, const void *src, size_t n);
Description
Copies a block of n bytes.
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.
Return Value
memmove returns dest.
Example
memset, _wmemset ( see page 967) Header File
mem.h, string.h
Category
Memory and String Manipulation Routines, Inline Routines
Prototype
void *memset(void *s, int c, size_t n);
void *_wmemset(void *s, int c, size_t n);
3
Description
Sets n bytes of a block of memory to byte c.
memset sets the first n bytes of the array s to the character c.
Return Value
memset returns s.
Example

961
C Runtime Library Reference RAD Studio 3.1 C++ Reference

setmem ( see page 968) Header File


mem.h
Category
Memory and String Manipulation Routines
Prototype
void setmem(void *dest, unsigned length, char value);
Description
Assigns a value to a range of memory.
setmem sets a block of length bytes, pointed to by dest, to the byte value.
Return Value
None.
Example

3.1.4.20.1 memccpy
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:

• The character c is first copied into dest.


• n bytes have been copied into dest.
Return Value
memccpy returns a pointer to the byte in dest immediately following c, if c was copied; otherwise, memccpy returns NULL.
Example
#include <string.h>
#include <stdio.h>
int main(void)
{
char *src = "This is the source string";
char dest[50];
char *ptr;
ptr = (char *) memccpy(dest, src, 'c', strlen(src));
if (ptr)
{
*ptr = '\0';
3 printf("The character was found: %s\n", dest);
}
else
printf("The character wasn't found\n");
return 0;
}
Portability

962
3.1 C++ Reference RAD Studio C Runtime Library Reference

POSIX Win32 ANSI C ANSI C++


+

3.1.4.20.2 memchr, _wmemchr


Header File

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

Searches n bytes for character c.

memchr is available on UNIX System V systems.

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

POSIX Win32 ANSI C ANSI C++


memchr + + + +
_wmemchr +

963
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.20.3 memcmp
Header File

mem.h, string.h

Category

Memory and String Manipulation Routines, Inline Routines

Prototype
int memcmp(const void *s1, const void *s2, size_t n);

Description

Compares two blocks for a length of exactly n bytes.

memcmp is available on UNIX System V systems.

memcmp compares the first n bytes of the blocks s1 and s2 as unsigned chars.

Return Value

Because it compares bytes as unsigned chars, memcmp returns a value that is

• < 0 if s1 is less than s2


• = 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
For example,
memcmp(“\xFF”, “\x7F”, 1)
returns a value greater than 0.
Note: If you are using the intrinsic version of these functions, the case of n = 0 will return NULL.
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *buf1 = "aaa";
char *buf2 = "bbb";
char *buf3 = "ccc";
int stat;
stat = memcmp(buf2, buf1, strlen(buf2));
if (stat > 0)
printf("buffer 2 is greater than buffer 1\n");
else
printf("buffer 2 is less than buffer 1\n");
stat = memcmp(buf2, buf3, strlen(buf2));
if (stat > 0)
3 printf("buffer 2 is greater than buffer 3\n");
else
printf("buffer 2 is less than buffer 3\n");
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

964
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.20.4 memcpy, _wmemcpy


Header File

mem.h, string.h

Category

Memory and String Manipulation Routines, Inline Routines

Prototype
void *memcpy(void *dest, const void *src, size_t n);
void *_wmemcpy(void *dest, const void *src, size_t n);

Description

Copies a block of n bytes.

memcpy is available on UNIX System V systems.

memcpy copies a block of n bytes from src to dest. If src and dest overlap, the behavior of memcpy is undefined.

Return Value

memcpy returns dest.

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

POSIX Win32 ANSI C ANSI C++


memcpy + + + +
_wmemcpy +

3
3.1.4.20.5 memicmp
Header File

mem.h, string.h

Category

Memory and String Manipulation Routines

965
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Prototype
int memicmp(const void *s1, const void *s2, size_t n);

Description

Compares n bytes of two character arrays, ignoring case.

memicmp is available on UNIX System V systems.

memicmp compares the first n bytes of the blocks s1 and s2, ignoring character case (upper or lower).

Return Value

memicmp returns a value that is

• < 0 if s1 is less than s2


• = 0 if s1 is the same as s2
• > 0 if s1 is greater than s2
Example
#include <stdio.h>
#include <string.h>
int main(void)
{
char *buf1 = "ABCDE123";
char *buf2 = "abcde456";
int stat;
stat = memicmp(buf1, buf2, 5);
printf("The strings to position 5 are ");
if (stat)
printf("not ");
printf("the same\n");
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.20.6 memmove
Header File

mem.h, string.h

Category

Memory and String Manipulation Routines

Prototype
3
void *memmove(void *dest, const void *src, size_t n);

Description

Copies a block of n bytes.

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

memmove returns dest.

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

POSIX Win32 ANSI C ANSI C++


memmove + + + +
_fmemmove

3.1.4.20.7 memset, _wmemset


Header File

mem.h, string.h

Category

Memory and String Manipulation Routines, Inline Routines

Prototype
void *memset(void *s, int c, size_t n);
void *_wmemset(void *s, int c, size_t n);

Description

Sets n bytes of a block of memory to byte c.

memset sets the first n bytes of the array s to the character c.

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

POSIX Win32 ANSI C ANSI C++


memset + + + +
_wmemset +

3.1.4.20.8 setmem
Header File

mem.h

Category

Memory and String Manipulation Routines

Prototype
void setmem(void *dest, unsigned length, char value);

Description

Assigns a value to a range of memory.

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

POSIX Win32 ANSI C ANSI C++


+

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

3.1.4.21.2 set_new_handler function


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. 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.

• The user-defined my_handler should do one of the following:


• return after freeing memory
• throw an bad_alloc exception or an exception derived from bad_alloc
• call abort or exit functions
If my_handler returns, then new will again attempt to satisfy the request.
Ideally, my_handler would free up memory and return. new would then be able to satisfy the request and the program would
continue. However, if my_handler cannot provide memory for new, my_handler must throw an exception or terminate the
program. Otherwise, an infinite loop will be created.
Preferably, you should overload operator new() and operator new[]() to take appropriate actions for your applications.
Return Value
set_new_handler returns the old handler, if one has been registered.
The user-defined argument function, my_handler, should not return a value.
Example
#include <iostream>
#include <new.h>
#include <stdlib.h>
using std::cout;
3 using std::hex;
void mem_warn() {
std::cerr << "\nCan't allocate!";
exit(1);
}

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

_beginthreadex ( see page 980) Header File


process.h
Category
Process Control Routines
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... more ( see page
980)
_c_exit ( see page 981) Header File
process.h
Category
Process Control Routines
Prototype
void _c_exit(void);
Description
Performs _exit cleanup without terminating the program.
_c_exit performs the same cleanup as _exit, except that it does not terminate the
calling process.
Return Value
None.
Example
_cexit ( see page 982) Header File
process.h
Category
Process Control Routines
Prototype
void _cexit(void);
Description
Performs exit cleanup without terminating the program.
_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
_endthread ( see page 983) Header File
process.h
Category
Process Control Routines
Prototype
void _endthread(void);
Description
Terminates execution of a thread.
The _endthread function terminates the currently executing thread by closing the
thread handle and calling the ExitThread API. The thread must have been started
3 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
The function does not return a value.

972
3.1 C++ Reference RAD Studio C Runtime Library Reference

_endthreadex ( see page 984) Header File


process.h
Category
Process Control Routines
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.
_expand ( see page 984) Header File
process.h
Category
Memory Routines
Prototype
void *_expand(void *block, size_t size);
Description
Grows or shrinks a heap block in place.
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,... more ( see page 984)
_unadopt_thread ( see page 985) Header File
process.h
Category
Process Control Routines
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
cwait ( see page 985) Header File
process.h
Category
Process Control Routines
Prototype
int cwait(int *statloc, int pid, int action);
Description
Waits for child process to terminate.
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.
3
If the child process terminated normally (by calling exit, or returning from main),
the termination status word is defined as follows:... more ( see page 985)

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

wait ( see page 992) Header File


process.h
Category
Process Control Routines
Prototype
int wait(int *statloc);
Description
Waits for one or more child processes to terminate.
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:

3.1.4.22.1 P_xxxx #defines


Header File

process.h

Description

Modes used by the spawn... functions.

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

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
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

from an outside source, such as ISAPI.

Using _adopt_thread thereby allows C++Builder compiled DLLs to be used from non-C++Builder EXEs. _adopt_thread works by:

• calling the user function (passing in the arglist param)


• unhooking the exception information
• returning a handle to the thread context
This process allows the same function to be used again (without reallocating all that data). At the end of this cycle, the
_unadopt_thread function can be called to finally free up the rest of this data.
The last parameter, free_flag, determines whether the thread data structures are freed upon function exit:
• If free_flag is zero, then when the adoptive function exits only its exception handler is un-hooked. The rest of the RTL specific
data that had been allocated during the thread's adoption, remains valid. If the same thread then calls _adopt_thread again,
the existing data is used, the exception handler is rehooked, and the specified adoptive thread function is called.
• If free_flag is set to non-zero, the thread data structures will be freed before _adopt_thread returns. In this case the returned
thread handle will be NULL since its associated date has already been freed.
Return Value
If the __free_flag parameter is false (zero), _adopt_thread returns a handle (thread context) that can later be used to free these
data structures by passing it to _unadopt_thread().
If the __free_flag parameter to _adopt_thread is non-zero, the thread data is freed before _adopt_thread returns, and the
returned handle is NULL.
If an error has occurred, errno is set to:
ENOMEM Not enough memory
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.22.3 _beginthread
Header File

process.h

Category

Process Control Routines

Prototype
unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void
*__arg);

Description
3 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 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.

This function is available only in the multithread libraries.

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:

EAGAIN Too many threads


EINVAL Invalid stack size (i.e. less than 16 bytes, or equal to zero)
ENOMEM Not enough memory

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

POSIX Win32 ANSI C ANSI C++


+

977
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.22.4 _beginthreadNT
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);

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 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.

_beginthreadNT initializes the thread_id variable with the thread identifier.

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:

3 EAGAIN Too many threads


EINVAL Invalid stack size (i.e. less than 16 bytes, or equal to zero)
ENOMEM Not enough memory

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

#pragma checkoption -tWM


#include <windows.h>
#include <process.h>
#include <stdio.h>
#define NTHREADS 25
static LONG runningThreads = 0;
static HANDLE doneEvent;
/* This function acts as the 'main' function for each new thread */
static void threadMain(void *arg)
{
printf("Thread %2d has an ID of %u\n", (int)arg, GetCurrentThreadId());
/* Use InterlockedDecrement() to modify the global runningThreads in a
* thread safe manner. When the count hits 0, signal the main thread if
* it created an event for us.
*/
if (InterlockedDecrement(&runningThreads) == 0 && doneEvent)
SetEvent(doneEvent);
}
int main(void)
{
HANDLE hThreads[NTHREADS];
int i;
DWORD 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)_beginthreadNT(
threadMain, /* Thread starting address */
4096, /* Thread stack size */
(void *)i, /* Thread start argument */
&sa, /* Thread security */
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;
}
++runningThreads;
printf("Created thread %2d with an ID of %u\n", i, threadId);
}
printf("\nPress ENTER to thaw all threads\n\n");
getchar();
/* Create the event that will signal when all threads are done */
doneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

/* Resume the suspended threads */


for(i = 0; i < NTHREADS; i++)
ResumeThread(hThreads[i]);
/* Wait for all threads to finish execution, if we can */
if (doneEvent) {
WaitForSingleObject(doneEvent, INFINITE);
CloseHandle(doneEvent); 3
}
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

979
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.22.5 _beginthreadex
Header File

process.h

Category

Process Control Routines

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.

If unsuccessful, 0 is returned, and errno is set as follows:

EAGAIN Too many threads


ENOMEM Not enough memory
EINVAL Bad stack value (i.e. less than 16 bytes or equal to zero)

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();

/* Resume the suspended threads */


for(i = 0; i < NTHREADS; i++)
ResumeThread(hThreads[i]);

/* Wait for the threads to run */


WaitForMultipleObjects(NTHREADS, hThreads, TRUE, INFINITE);
/* Close all of the thread handles */
for(i = 0; i < NTHREADS; i++)
CloseHandle(hThreads[i]);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.22.6 _c_exit
Header File

process.h

Category

Process Control Routines

Prototype
3
void _c_exit(void);

Description

Performs _exit cleanup without terminating the program.

_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;

if ((fd = open("_c_exit.c",O_RDONLY)) < 0)


{
printf("Unable to open _c_exit.c for reading\n");
return 1;
}
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d before _c_exit\n",fd);
else
printf("Successfully read from open file handle %d before _c_exit\n",fd);
_c_exit();
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d after _c_exit\n",fd);
else
printf("Successfully read from open file handle %d after _c_exit\n",fd);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.22.7 _cexit
Header File

process.h

Category

Process Control Routines

Prototype
void _cexit(void);

Description

Performs exit cleanup without terminating the program.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.22.8 _endthread
Header File

process.h

Category

Process Control Routines

Prototype
void _endthread(void);

Description

Terminates execution of a thread.

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

The function does not return a value.

983
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.22.9 _endthreadex
Header File

process.h

Category

Process Control Routines

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

Grows or shrinks a heap block in place.

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

printf( "Allocate a 512 element buffer\n" );


if( (bufchar = (char *) calloc(512, sizeof( char ) )) == NULL)
exit( 1 );
printf( "Allocated %d bytes at %Fp\n",
_msize ( bufchar ), (void __far *)bufchar );
if ((newbuf = (char *) _expand (bufchar, 1024)) == NULL)
printf ("cannot expand");
else {
bufchar = newbuf;
printf (" Expanded block to %d bytes at %Fp\n",
_msize( bufchar ) , (void __far *)bufchar );
}
free( bufchar );
exit (0);
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.22.11 _unadopt_thread
Header File

process.h

Category

Process Control Routines

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.22.12 cwait
Header File 3
process.h

Category

Process Control Routines

Prototype
int cwait(int *statloc, int pid, int action);

985
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Description

Waits for child process to terminate.

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:

Bits 0-7 Zero


Bits 8-15 The least significant byte of the return code from the child process. This is the value that is passed to
exit, or is returned from main. If the child process simply exited from main without returning a value,
this value will be unpredictable.

If the child process terminated abnormally, the termination status word is defined as follows:

Bits 0-7Termination information about the child:

1 Critical error abort.


2 Execution fault, protection exception.
3 External termination signal.
Bits 8-15 Zero

Bits 8-15 Zero

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:

ECHILD No child exists or the pid value is bad


EINVAL A bad action value was specified

Portability
3 POSIX Win32 ANSI C ANSI C++
+

986
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.22.13 execl, execle, execlp, execlpe, execv, execve, execvp, execvpe,


_wexecl, _wexecle, _wexeclp, _wexeclpe, _wexecv, _wexecve, _wexecvp,
_wexecvpe
Header File

process.h

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 *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

Loads and runs other programs.

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:

EACCES Permission denied


EMFILE Too many open files
ENOENT Path or file name not found
ENOEXEC Exec format error
3 ENOMEM Not enough memory

Example
/* execl() example */
#include <stdio.h>
#include <process.h>

int main(int argc, char *argv[])


{

988
3.1 C++ Reference RAD Studio C Runtime Library Reference

int loop;
printf("%s running...\n\n", argv[0]);

if (argc == 1) { /* check for only one command-line parameter */


printf("%s calling itself again...\n", argv[0]);
execl(argv[0], argv[0], "ONE", "TWO", "THREE", NULL);
perror("EXEC:");
exit(1);
}
printf("%s called with arguments:\n", argv[0]);
for (loop = 1; loop <= argc; loop++)
puts(argv[loop]); /* Display all command-line parameters */
return 0;
}

3.1.4.22.14 getpid
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
#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

POSIX Win32 ANSI C ANSI C++


+ +
3

3.1.4.22.15 spawnl, spawnle, spawnlp, spawnlpe, spawnv, spawnve, spawnvp,


spawnvpe, _wspawnl, _wspawnle, _wspawnlp, _wspawnlpe, _wspawnv,
_wspawnve, _wspawnvp, _wspawnvpe
Header File

989
C Runtime Library Reference RAD Studio 3.1 C++ Reference

process.h

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, ..., 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:

E2BIG Arg list too long


EINVAL Invalid argument
ENOENT Path or file name not found
ENOEXEC Exec format error

991
C Runtime Library Reference RAD Studio 3.1 C++ Reference

ENOMEM Not enough memory

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

Process Control Routines

Prototype
int wait(int *statloc);

Description

Waits for one or more child processes to terminate.

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:

Bits 0-7 Zero.


Bits 8-15 The least significant byte of the return code from the child process. This is the value that is passed to
exit, or is returned from main. If the child process simply exited from main without returning a value,
this value will be unpredictable. If the child process terminated abnormally, the termination status
word is defined as follows:

3 Bits 0-7 Termination information about the child:

Bits 8-15 Zero.

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:

ECHILD No child process exists

Portability

POSIX Win32 ANSI C ANSI C++


+

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

setjmp ( see page 995) Header File


setjmp.h
Category
Miscellaneous Routines
Prototype
int setjmp(jmp_buf jmpb);
Description
Sets up for nonlocal goto.
setjmp captures the complete task state in jmpb and returns 0.
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.
Under Win32, a task state includes:

• No segment registers are saved


• Register variables
• EBX, EDI, ESI
• Stack pointer (ESP)
• Frame pointer (EBP)
• Flags are not saved
A task state is complete enough that setjmp can be used to
implement co-routines.
setjmp must be called before... more ( see page 995)

3.1.4.23.1 longjmp
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
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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.23.2 setjmp
Header File

setjmp.h

Category

Miscellaneous Routines

Prototype
int setjmp(jmp_buf jmpb);

Description

Sets up for nonlocal goto.


3
setjmp captures the complete task state in jmpb and returns 0.

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.

Under Win32, a task state includes:

• No segment registers are saved


• Register variables

995
C Runtime Library Reference RAD Studio 3.1 C++ Reference

• EBX, EDI, ESI


• Stack pointer (ESP)
• Frame pointer (EBP)
• Flags are not saved
A task state is complete enough that setjmp can be used to implement co-routines.
setjmp must be called before longjmp. The routine that calls setjmp and sets up jmpb must still be active and cannot have
returned before the longjmp is called. If it has returned, the results are unpredictable.
setjmp is useful for dealing with errors and exceptions encountered in a low-level subroutine of a program.
Return Value
setjmp returns 0 when it is initially called. If the return is from a call to longjmp, setjmp returns a nonzero value (as in the
example).
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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

3.1.4.24.1 SH_xxxx #defines


Header File

share.h

Description

File-sharing mode for use with sopen.

SH_COMPAT Sets compatibility mode:


Allows other opens with SH_COMPAT. The call will fail if the file has already been opened in any
other shared mode.
SH_DENYNONE Permits read/write access
Allows other shared opens to the file, but not other SH_COMPAT opens
SH_DENYNO Permits read/write access (provided for compatibility)
SH_DENYRD Denies read access. Allows only writes from any other open to the file
SH_DENYRW Denies read/write access. Only the current handle may have access to the file
SH_DENYWR Denies write access. Allows only reads from any other open to the file
O_NOINHERIT The file is not passed to child programs

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 (C RTL) ( see page 1000) Header File


signal.h
Category
Process Control Routines
Prototype
void (_USERENTRY *signal(int sig, void (_USERENTRY
*func)(int sig[, int subcode])))(int);
Description
Specifies signal-handling actions.
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.... more ( see page 1000)

3.1.4.25.1 SIGxxxx #defines


Header File

signal.h

Description

Signal types used by raise and signal.

Signal Note Meaning Default Action


SIGABRT (*) Abnormal termination = to calling _exit(3)
SIGFPE Bad floating-point operation = to calling _exit(1)
Arithmetic error caused by
division by 0, invalid operation, etc.
SIGILL Illegal operation = to calling _exit(1)
SIGINT Control-C interrupt = to calling _exit(3)
SIGSEGV Invalid access to storage = to calling _exit(1)
SIGTERM (*) Request for program termination = to calling _exit(1)

(*) Signal types marked with a (*) aren't generated by Borland C++ during normal operation. However, they can be generated
with raise.

3.1.4.25.2 SIG_xxx #defines


Header File

signal.h

3 Description

Predefined functions for handling signals generated by raise or by external events.

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

Process Control Routines

Prototype
int raise(int sig);

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:

SIGABRT Abnormal termination


SIGFPE Bad floating-point operation
SIGILL Illegal instruction
SIGINT Ctrl-C interrupt
SIGSEGV Invalid access to storage
SIGTERM Request for program termination
SIGUSR1 User-defined signal
SIGUSR2 User-defined signal
SIGUSR3 User-defined signal
SIGBREAK Ctrl-Break interrupt

Note: SIGABRT isn’t generated by C++Builder during normal operation. It can, however, be generated by abort, raise, or
unhandled exceptions.

Return Value

On success, raise returns 0.

On error it returns nonzero.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.25.4 signal (C RTL)


Header File

signal.h

Category

Process Control Routines

Prototype
void (_USERENTRY *signal(int sig, void (_USERENTRY *func)(int sig[, int subcode])))(int);

Description

Specifies signal-handling actions.

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.

SIG_DFL Terminates the program


SIG_ERR Indicates an error return from signal
SIG_IGN Ignore this type signal

The following table shows signal types and their defaults:

SIGBREAK Keyboard must be in raw mode.


SIGABRT Abnormal termination. Default action is equivalent to calling _exit(3).
SIGFPE Arithmetic error caused by division by 0, invalid operation, and the like. Default action is equivalent to
calling _exit(1).
SIGILL Illegal operation. Default action is equivalent to calling _exit(1).
SIGINT Ctrl-C interrupt. Default action is equivalent to calling _exit(3).
SIGSEGV Illegal storage access. Default action is equivalent to calling _exit(1).
SIGTERM Request for program termination. Default action is equivalent to calling _exit(1).

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.

For example, to have a new SI value on return, do something like this:


*((int*)list_pointer + 2) = new_SI_value;

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.)

FPE_INTOVFLOW INTO executed with OF flag set


FPE_INTDIV0 Integer divide by zero
FPE_INVALID Invalid operation
FPE_ZERODIVIDE Division by zero
FPE_OVERFLOW Numeric overflow
FPE_UNDERFLOW Numeric underflow
FPE_INEXACT Precision
FPE_EXPLICITGEN User program executed raise(SIGFPE) 3
FPE_STACKFAULT Floating-point stack overflow or underflow
FPE_STACKFAULT Stack overflow

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.

The following SIGSEGV-type signals can occur:

1001
C Runtime Library Reference RAD Studio 3.1 C++ Reference

SEGV_BOUND Bound constraint exception


SEGV_EXPLICITGEN raise(SIGSEGV) was executed

The following SIGILL-type signals can occur:

ILL_EXECUTION Illegal operation attempted


ILL_EXPLICITGEN raise(SIGILL) was executed

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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)

3.1.4.26.1 va_arg, va_end, va_start


Header File

stdarg.h

Category

Variable Argument List Routines

Prototype
void va_start(va_list ap, lastfix);
type va_arg(va_list ap, type);
3
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

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 POSIX Win32 ANSI C ANSI C++


+ + + +

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

3.1.4.27.1 NULL #define


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.

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

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

POSIX Win32 ANSI C ANSI C++


+ + +

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

L_tmpnam #define ( see page 1024) Header File


stdio.h
Description
Size of an array large enough to hold a temporary file name string.
TMP_MAX #define ( see page 1024) Header File
stdio.h
Description
Maximum number of unique file names.
_IOxxx #defines ( see page 1025) Header File
stdio.h
Description
Constants for defining buffering style to be used with a file.
_fsopen, _wfsopen ( see page 1025) Header 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
Opens a stream with file sharing.
_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:
_pclose ( see page 1027) Header File
stdio.h
Category
Input/output Routines, Process Control Routines
Prototype
int _pclose(FILE * stream);
Description
Waits for piped command to complete.
_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.
On error, it returns -1.
Portability
_popen, _wpopen ( see page 1027) Header File
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
Creates a command processor pipe.
The _popen function creates a pipe to the command processor. The command
processor is executed asynchronously, and is 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
3
opened in binary or text mode.
The mode string can take one of the following values:

1007
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_snprintf;_snwprintf ( see page 1028) Header File


stdio.h
Category
Memory and String Manipulation Routines
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.
If the number of bytes to output is:

• < 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... more ( see page
1028)
_vsnprintf;_vsnwprintf ( see page 1029) Header File
stdio.h
Category
Memory and String Manipulation Routines
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.
If the number of bytes to output is:

• < 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... more ( see page 1029)
clearerr ( see page 1029) Header File
stdio.h
Category
Input/output Routines
Prototype
void clearerr(FILE *stream);
Description
Resets error indication.
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.
3 Return Value
None.
Example
EOF #define ( see page 1030) Header File
stdio.h
Description
A constant indicating that end-of-file has been reached on a file.

1008
3.1 C++ Reference RAD Studio C Runtime Library Reference

fclose ( see page 1030) Header File


stdio.h
Category
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
fclose returns 0 on success. It returns EOF if any errors were detected.
Portability
_fcloseall ( see page 1031) Header File
stdio.h
Category
Input/output Routines
Prototype
int _fcloseall(void);
Description
Closes open streams.
_fcloseall closes all open streams except
stdauxstdstreams
When _fcloseall flushes the associated buffers before closing a stream. The
buffers allocated by the system are released.
Note: stdprn and stdaux streams are not available in Win32.
Return Value
_fcloseall returns the total number of streams it closed. The _fcloseall function
returns EOF if any errors were detected.
Example
_fdopen, _wfdopen ( see page 1032) Header File
stdio.h
Category
Input/output Routines
Prototype
FILE *_fdopen(int handle, char *type);
FILE *_wfdopen(int handle, wchar_t *type);
Description
Associates a stream with a file handle.
_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:
feof ( see page 1033) Header File
stdio.h
Category
Input/output Routines
Prototype
int feof(FILE *stream);
Description
Detects end-of-file on a stream.
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 3
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 has not been reached.
Example

1009
C Runtime Library Reference RAD Studio 3.1 C++ Reference

ferror ( see page 1034) Header File


stdio.h
Category
Input/output Routines
Prototype
int ferror(FILE *stream);
Description
Detects errors on stream.
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
ferror returns nonzero if an error was detected on the named stream.
Example
fflush ( see page 1035) 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
fflush returns 0 on success. It returns EOF if any errors were detected.
Example
fgetc, fgetwc ( see page 1036) Header File
stdio.h
Category
Input/output Routines
Prototype
int fgetc(FILE *stream);
wint_t fgetwc(FILE *stream);
Description
Gets character from stream.
fgetc returns the next character on the named input stream.
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
_fgetchar, _fgetwchar ( see page 1037) Header File
stdio.h
Category
Console I/O Routines
Prototype
int _fgetchar(void);
wint_t _fgetwchar(void);
Description
Reads a character from stdin.
_fgetchar returns the next character from stdin. It is defined as fgetc(stdin).
Note: For Win32 GUI applications, stdin must be redirected.
3 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

1010
3.1 C++ Reference RAD Studio C Runtime Library Reference

fgetpos ( see page 1037) Header File


stdio.h
Category
Input/output Routines
Prototype
int fgetpos(FILE *stream, fpos_t *pos);
Description
Gets the current file pointer.
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
fgets, fgetws ( see page 1039) Header File
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
Gets a string from a stream.
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... more ( see page 1039)
_fileno ( see page 1040) Header File
stdio.h
Category
Input/output Routines
Prototype
int _fileno(FILE *stream);
Description
Gets the file handle.
_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
_fileno returns the integer file handle associated with stream.
Example
_flushall ( see page 1040) Header File
stdio.h
Category
Input/output Routines
Prototype
int _flushall(void);
Description
Flushes all streams.
_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. 3
Streams stay open after _flushall executes.
Return Value
_flushall returns an integer the number of open input and output streams.
Example

1011
C Runtime Library Reference RAD Studio 3.1 C++ Reference

fopen, _wfopen ( see page 1041) Header File


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.
The mode string used in calls to fopen is one of the following values:
fprintf, fwprintf ( see page 1042) Header File
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
Writes formatted output to a stream.
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.
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
fputc, fputwc ( see page 1043) Header File
stdio.h
Category
Input/output Routines
Prototype
int fputc(int c, FILE *stream);
wint_t fputwc(wint_t c, FILE *stream);
Description
Puts a character on a stream.
fputc outputs character c to the named stream.
Note: For Win32 GUI applications, stdin must be redirected.
Return Value
On success, fputc returns the character c. On error, it returns EOF.
Example
_fputchar, _fputwchar ( see page 1044) Header File
stdio.h
Category
Input/output Routines
Prototype
int _fputchar(int c);
wint_t _fputwchar(wint_t c);
Description
Outputs a character to stdout.
_fputchar outputs character c to stdout. _fputchar(c) is the same as fputc(cstdout).
3 Note: For Win32 GUI applications, stdout must be redirected.
Return Value
On success _fputchar returns the character c.
On error it returns EOF.
Example

1012
3.1 C++ Reference RAD Studio C Runtime Library Reference

fputs, fputws ( see page 1044) Header File


stdio.h
Category
Input/output Routines
Prototype
int fputs(const char *s, FILE *stream);
int fputws(const wchar_t *s, FILE *stream);
Description
Outputs a string on a stream.
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
On success fputs returns a non-negative value.
On error it returns a value of EOF.
Example
fread ( see page 1045) Header File
stdio.h
Category
Input/output Routines
Prototype
size_t fread(void *ptr, size_t size, size_t n, FILE
*stream);
Description
Reads data from a stream.
fread reads n items of data each of length size bytes from the given input stream
into a block pointed to by ptr.
The total number of bytes read is (n * size).
Return Value
On success fread returns the number of items (not bytes) actually read.
On end-of-file or error it returns a short count (possibly 0).
Example
freopen, _wfreopen ( see page 1046) Header File
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
Associates a new file with an open stream.
freopen substitutes the named file in place of the open stream. It closes stream
regardless of whether the open succeeds. freopen is useful for changing the file
attached to stdin, stdout, or stderr.
The mode string used in calls to fopen is one of the following values:
fscanf, fwscanf ( see page 1047) Header File
stdio.h
Category
Input/output Routines
Prototype
int fscanf(FILE *stream, const char *format[, address,
...]);
int fwscanf(FILE *stream, const wchar_t *format[, address,
...]);
Description 3
Scans and formats input from a stream.
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... more (
see page 1047)

1013
C Runtime Library Reference RAD Studio 3.1 C++ Reference

fseek ( see page 1048) Header File


stdio.h
Category
Input/output Routines
Prototype
int fseek(FILE *stream, long offset, int whence);
Description
Repositions a file pointer on a stream.
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.... more ( see page 1048)
fsetpos ( see page 1049) Header File
stdio.h
Category
Input/output Routines
Prototype
int fsetpos(FILE *stream, const fpos_t *pos);
Description
Positions the file pointer of a stream.
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 success fsetpos returns 0.
On failure it returns a nonzero... more ( see page 1049)
ftell ( see page 1050) Header File
stdio.h
Category
Input/output Routines
Prototype
long int ftell(FILE *stream);
Description
Returns the current file pointer.
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... more ( see page 1050)
fwrite ( see page 1051) Header File
stdio.h
Category
Input/output Routines
Prototype
size_t fwrite(const void *ptr, size_t size, size_t n, FILE
*stream);
Description
3 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.
On error it returns a short count.
Example

1014
3.1 C++ Reference RAD Studio C Runtime Library Reference

getc, getwc ( see page 1052) Header File


stdio.h
Category
Input/output Routines
Prototype
int getc(FILE *stream);
wint_t getwc(FILE *stream);
Description
Gets character from stream.
getc returns the next character on the given input stream and increments the
stream's file pointer to point to the next character.
Note: For Win32 GUI applications, stdin must be redirected.
Return Value
On success, getc returns the character read, after converting it to an int without
sign extension.
On end-of-file or error, it returns EOF.
Example
getchar, getwchar ( see page 1052) Header File
stdio.h
Category
Console I/O Routines
Prototype
int getchar(void);
wint_t getwchar(void);
Description
Gets character from stdin.
getchar is a macro that returns the next character on the named input stream
stdin. It is defined to be getc(stdin).
Note: Do not use this function in Win32 GUI applications.
Return Value
On success, getchar returns the character read, after converting it to an int
without sign extension.
On end-of-file or error, it returns EOF.
Example
gets, _getws ( see page 1053) Header File
stdio.h
Category
Console I/O Routines
Prototype
char *gets(char *s);
wchar_t *_getws(wchar_t *s); // Unicode version
Description
Gets a string from stdin.
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.
The gets function is not length-terminated. If the input string is sufficiently large,
data... more ( see page 1053)

1015
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_getw ( see page 1054) Header File


stdio.h
Category
Input/output Routines
Prototype
int _getw(FILE *stream);
Description
Gets an integer from stream.
_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
_getw returns the next integer on the input stream.
On end-of-file or error, _getw returns EOF.
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
printf, wprintf ( see page 1055) Header File
stdio.h
Category
Console I/O Routines
Prototype
int printf(const char *format[, argument, ...]);
int wprintf(const wchar_t *format[, argument, ...]);
Description
Writes formatted output to stdout.
The printf function:

• Accepts a series of arguments


• Applies to each argument a format specifier contained in
the format string *format
• Outputs the formatted data (to the screen, a stream,
stdout, or a string)
There must be enough arguments for the format. If there are
not, the results will be unpredictable and likely disastrous.
Excess arguments (more than required by the format) are
merely ignored.
Note: For Win32 GUI applications, stdout must be
redirected.... more ( see page 1055)
putc, putwc ( see page 1057) Header File
stdio.h
Category
Input/output Routines
Prototype
int putc(int c, FILE *stream);
wint_t putwc(wint_t c, FILE *stream);
Description
Outputs a character to a stream.
putc is a macro that outputs the character c to the stream given by stream.
Return Value
On success, putc returns the character printed, c.
3 On error, putc returns EOF.
Example

1016
3.1 C++ Reference RAD Studio C Runtime Library Reference

putchar, putwchar ( see page 1057) Header File


stdio.h
Category
Console I/O Routines
Prototype
int putchar(int c);
wint_t putwchar(wint_t c);
Description
putchar is a macro defined to be putc(c, stdout).
Note: For Win32 GUI applications, stdout must be redirected.
Return Value
On success, putchar returns the character c. On error, putchar returns EOF.
Example
puts, _putws ( see page 1059) Header File
stdio.h
Category
Console I/O Routines
Prototype
int puts(const char *s);
int _putws(const wchar_t *s);
Description
Outputs a string to stdout.
puts copies the null-terminated string s to the standard output stream stdout and
appends a newline character.
Note: For Win32 GUI applications, stdout must be redirected.
Return Value
On successful completion, puts returns a nonnegative value. Otherwise, it returns
a value of EOF.
Example
_putw ( see page 1059) Header File
stdio.h
Category
Input/output Routines
Prototype
int _putw(int w, FILE *stream);
Description
Writes an integer on a stream.
_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
remove, _wremove ( see page 1060) Header File
stdio.h
Category
Input/output Routines
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.
The filename string can include a full path. 3
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:

1017
C Runtime Library Reference RAD Studio 3.1 C++ Reference

rename, _wrename ( see page 1061) Header File


stdio.h
Category
Input/output Routines
Prototype
int rename(const char *oldname, const char *newname);
int _wrename(const wchar_t *oldname, const wchar_t
*newname);
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... more ( see page 1061)
rewind ( see page 1062) Header File
stdio.h
Category
Input/output Routines
Prototype
void rewind(FILE *stream);
Description
Repositions a file pointer to the beginning of a stream.
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
_rmtmp ( see page 1063) Header File
stdio.h
Category
Input/output Routines
Prototype
int _rmtmp(void);
Description
Removes temporary files.
The _rmtmp function closes and deletes all open temporary file streams which
were previously created with tmpfile. The current directory must the same as
when the files were created, or the files will not be deleted.
Return Value
_rmtmp returns the total number of temporary files it closed and deleted.
Example

1018
3.1 C++ Reference RAD Studio C Runtime Library Reference

scanf, wscanf ( see page 1064) Header File


stdio.h
Category
Console I/O Routines
Prototype
int scanf(const char *format[, address, ...]);
int wscanf(const wchar_t *format[, address, ...]);
Description
Scans and formats input from the stdin stream.
Note: For Win32 GUI applications, stdin must be redirected.
The scanf function:

• scans a series of input fields one character at a time


• formats each field according to a corresponding format
specifier passed in the format string *format.
• vsscanf scans and formats input from a string, using an
argument list
There must be one format specifier and address for each
input field.
scanf might stop scanning a particular field before it... more
( see page 1064)
setbuf ( see page 1066) Header File
stdio.h
Category
Input/output Routines
Prototype
void setbuf(FILE *stream, char *buf);
Description
Assigns buffering to a stream.
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... more ( see page 1066)
setvbuf ( see page 1067) Header File
stdio.h
Category
Input/output Routines
Prototype
int setvbuf(FILE *stream, char *buf, int type, size_t size);
Description
Assigns buffering to a stream.
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.
The parameter size is limited by the constant UINT_MAX as defined... more (
see page 1067)

1019
C Runtime Library Reference RAD Studio 3.1 C++ Reference

snprintf;snwprintf ( see page 1068) Header File


stdio.h
Category
Memory and String Manipulation Routines
Prototype
int snprintf(char* buffer, size_t nsize, const char* fmt,
...);
int snwprintf(wchar_t* buffer, size_t nsize, const wchar_t*
fmt, ...);
Description
Sends formatted output to a buffer of a maximum length specified by nsize.
If the number of bytes to output is:

• < 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... more ( see page
1068)
sprintf, swprintf ( see page 1068) Header File
stdio.h
Category
Memory and String Manipulation Routines
Prototype
int sprintf(char *buffer, const char *format[, argument,
...]);
int swprintf(wchar_t *buffer, const wchar_t *format[,
argument, ...]);
Description
Writes formatted output to a string.
Note: For details on format specifiers, see printf.
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... more ( see page 1068)
sscanf, swscanf ( see page 1069) Header File
stdio.h
Category
Memory and String Manipulation Routines
Syntax
int sscanf(const char *buffer, const char *format[,
address, ...]);
int swscanf(const wchar_t *buffer, const wchar_t *format[,
address, ...]);
Description
Scans and formats input from a string.
Note: For details on format specifiers, see scanf.
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
3 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... more ( see page 1069)
stderr, stdin, stdout ( see page 1070) Header File
stdio.h
Description
Predefined streams automatically opened when the program is started.

1020
3.1 C++ Reference RAD Studio C Runtime Library Reference

_tempnam, _wtempnam ( see page 1071) Header File


stdio.h
Category
Input/output Routines
Prototype
char *_tempnam(char *dir, char *prefix)
wchar_t *_wtempnam(wchar_t *dir, wchar_t *prefix)
Description
Creates a unique file name in specified directory.
The _tempnam function accepts single-byte or multibyte string arguments.
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:

• The directory specified by the TMP environment variable.


• The dir argument to _tempnam.
• The P_tmpdir definition in stdio.h. If you edit stdio.h...
more ( see page 1071)
tmpfile ( see page 1072) Header File
stdio.h
Category
Input/output Routines
Prototype
FILE *tmpfile(void);
Description
Opens a “scratch” file in binary mode.
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
tmpnam, _wtmpnam ( see page 1073) Header File
stdio.h
Category
Input/output Routines
Prototype
char *tmpnam(char *s);
wchar_t *_wtmpnam(wchar_t *s);
Description
Creates a unique file name.
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... more ( see page 1073)
ungetc, ungetwc ( see page 1073) Header File
stdio.h
Category
Input/output Routines
Prototype
3
int ungetc(int c, FILE *stream);
wint_t ungetwc(wint_t c, FILE *stream);
Description
Pushes a character back into input stream.
Note: Do not use this function in Win32 GUI applications.
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,... more ( see page 1073)

1021
C Runtime Library Reference RAD Studio 3.1 C++ Reference

vfprintf, vfwprintf ( see page 1074) Header File


stdio.h
Category
Input/output Routines
Prototype
int vfprintf(FILE *stream, const char *format, va_list
arglist);
int vfwprintf(FILE *stream, const wchar_t *format, va_list
arglist);
Description
Writes formatted output to a stream.
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.
For details on format specifiers, see Printf Format Specifiers.
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... more
( see page 1074)
vfscanf ( see page 1076) Header File
stdio.h
Category
Input/output Routines
Prototype
int vfscanf(FILE *stream, const char *format,va_list
arglist);
Description
Scans and formats input from a stream.
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.
For details on format specifiers, see Scanf Format Specifiers.
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... more ( see page 1076)
vprintf, vwprintf ( see page 1077) Header File
stdio.h
Category
Console I/O Routines
Prototype
int vprintf(const char *format, va_list arglist);
int vwprintf(const wchar_t * format, va_list arglist);
Description
Writes formatted output to stdout.
Note: Do not use this function in Win32 GUI applications.
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.
Note: For details on format specifiers, see Printf Format Specifiers.
vprintf accepts a pointer to a series of arguments, applies to each a format
specifier contained in the... more ( see page 1077)
vscanf ( see page 1078) Header File
stdio.h
Category
Console I/O Routines
Prototype
int vscanf(const char *format, va_list arglist);
3 Description
Scans and formats input from stdin.
Note: Do not use this function in Win32 GUI applications.
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.
Note: For details on format specifiers, see Scanf Format Specifiers.
vscanf scans a series of input fields, one character at a time, reading from stdin.
Then each field is formatted according to a format... more ( see page 1078)

1022
3.1 C++ Reference RAD Studio C Runtime Library Reference

vsnprintf;vsnwprintf ( see page 1079) Header File


stdio.h
Category
Memory and String Manipulation Routines
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 buffer of maximum length specified by nsize.
If the number of bytes to output is:

• < 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... more ( see page 1079)
vsprintf, vswprintf ( see page 1079) Header File
stdio.h
Category
Memory and String Manipulation Routines
Prototype
int vsprintf(char *buffer, const char *format, va_list
arglist);
int vswprintf(wchar_t *buffer, const wchar_t *format,
va_list arglist);
Description
Writes formatted output to a string.
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.... more ( see page 1079)

3.1.4.28.1 BUFSIZ #define


Header File

stdio.h

Description

Default buffer size used by setbuf function.

3.1.4.28.2 _F_xxxx #defines


Header File
3
stdio.h

Description

File status flags of streams

Name Meaning
_F_RDWR Read and write

1023
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_F_READ Read-only file


_F_WRIT Write-only file
_F_BUF Malloc'ed buffer data
_F_LBUF Line-buffered file
_F_ERR Error indicator
_F_EOF EOF indicator
_F_BIN Binary file indicator
_F_IN Data is incoming
_F_OUT Data is outgoing
_F_TERM File is a terminal

3.1.4.28.3 OPEN_MAX #define


Header File

stdio.h

Description

Number of files that can be open simultaneously.

Name Meaning
FOPEN_MAX Maximum files per process
SYS_OPEN Maximum files for system

3.1.4.28.4 L_ctermid #define


Header File

stdio.h

Description

The length of a device id string.

3.1.4.28.5 L_tmpnam #define


Header File

stdio.h
3 Description

Size of an array large enough to hold a temporary file name string.

3.1.4.28.6 TMP_MAX #define


Header File

stdio.h

1024
3.1 C++ Reference RAD Studio C Runtime Library Reference

Description

Maximum number of unique file names.

3.1.4.28.7 _IOxxx #defines


Header File

stdio.h

Description

Constants for defining buffering style to be used with a file.

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.

3.1.4.28.8 _fsopen, _wfsopen


Header 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

Opens a stream with file sharing.

_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:

• output cannot be directly followed by input without an intervening fseek or rewind


• input cannot be directly followed by output without an intervening fseek, rewind, or an input that encounters end-of-file
shflag specifies the type of file-sharing allowed on the file filename. Symbolic constants for shflag are defined in share.h.

SH_COMPAT Sets compatibility mode


SH_DENYRW Denies read/write access
SH_DENYWR Denies write access
SH_DENYRD Denies read access
SH_DENYNONE Permits read/write access
SH_DENYNO Permits read/write access

Return Value

On successful completion _fsopen returns a pointer to the newly opened stream.

On error it returns NULL.

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

POSIX Win32 ANSI C ANSI C++


_fsopen +
_wfsopen NT only

1026
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.28.9 _pclose
Header File

stdio.h

Category

Input/output Routines, Process Control Routines

Prototype
int _pclose(FILE * stream);

Description

Waits for piped command to complete.

_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.

On error, it returns -1.

Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.28.10 _popen, _wpopen


Header File

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

Creates a command processor pipe.

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.

The mode string can take one of the following values:

rt Read child command’s standard output (text).


rb Read child command’s standard output (binary).

1027
C Runtime Library Reference RAD Studio 3.1 C++ Reference

wt Write to child command’s standard input (text).


wb Write to child command’s standard input (binary).

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.

On error, it returns NULL.

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

POSIX Win32 ANSI C ANSI C++


_popen +
_wpopen NT only

3
3.1.4.28.11 _snprintf;_snwprintf
Header File

stdio.h

Category

Memory and String Manipulation Routines

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.

If the number of bytes to output is:

• < 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

Memory and String Manipulation Routines

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.

If the number of bytes to output is:

• < 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

Resets error indication.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.14 EOF #define


Header File

stdio.h

Description

3 A constant indicating that end-of-file has been reached on a file.

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

fclose returns 0 on success. It returns EOF if any errors were detected.

Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.16 _fcloseall
Header File

stdio.h

Category

Input/output Routines

Prototype
int _fcloseall(void);

Description

Closes open streams.

_fcloseall closes all open streams except

stdauxstdstreams

When _fcloseall flushes the associated buffers before closing a stream. The buffers allocated by the system are released.

Note: stdprn and stdaux streams are not available in Win32.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.28.17 _fdopen, _wfdopen


Header File

stdio.h

Category

Input/output Routines

Prototype
FILE *_fdopen(int handle, char *type);
FILE *_wfdopen(int handle, wchar_t *type);

Description

Associates a stream with a file handle.

_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.

If _fmode is set to O_BINARY, files will be opened in binary mode.

If _fmode is set to O_TEXT, files will be opened in text mode.

Note:The O_... constants are defined in fcntl.h.

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,

• output cannot be directly followed by input without an intervening fseek or rewind


• input cannot be directly followed by output without an intervening fseek, rewind, or an input that encounters end-of-file
Return Value
On successful completion _fdopen returns a pointer to the newly opened stream. In the event of error it returns NULL.
Example
#include <sys\stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
FILE *stream;
/* open a file */
handle = open("DUMMY.FIL", O_CREAT,
S_IREAD | S_IWRITE);
/* now turn the handle into a stream */
stream = fdopen(handle, "w");
if (stream == NULL)
printf("fdopen failed\n");
else
{
fprintf(stream, "Hello world\n");
fclose(stream);
}
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


_fdopen + +
_wfdopen +

3.1.4.28.18 feof
Header File

stdio.h

Category

Input/output Routines

Prototype
int feof(FILE *stream);
3
Description

Detects end-of-file on a stream.

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

has not been reached.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.19 ferror
Header File

stdio.h

Category

Input/output Routines

Prototype
int ferror(FILE *stream);

Description

Detects errors on stream.

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

ferror returns nonzero if an error was detected on the named stream.

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

/* reset the error and EOF indicators */


clearerr(stream);
}
fclose(stream);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

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

fflush returns 0 on success. It returns EOF if any errors were detected.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.21 fgetc, fgetwc


Header File

stdio.h

Category

Input/output Routines

Prototype
int fgetc(FILE *stream);
wint_t fgetwc(FILE *stream);

Description

Gets character from stream.

fgetc returns the next character on the named input stream.

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

POSIX Win32 ANSI C ANSI C++


fgetc + + + +
fgetwc + + +

3.1.4.28.22 _fgetchar, _fgetwchar


Header File

stdio.h

Category

Console I/O Routines

Prototype
int _fgetchar(void);
wint_t _fgetwchar(void);

Description

Reads a character from stdin.

_fgetchar returns the next character from stdin. It is defined as fgetc(stdin).

Note: For Win32 GUI applications, stdin must be redirected.

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

POSIX Win32 ANSI C ANSI C++ 3


_fgetchar +
_fgetwchar +

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

Gets the current file pointer.

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

EBADF Bad file number


EINVAL Invalid number

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.24 fgets, fgetws


Header File

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

Gets a string from a stream.

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

POSIX Win32 ANSI C ANSI C++


fgets + + + +
fgetws + + +

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

Gets the file handle.

_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

_fileno returns the integer file handle associated with stream.

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

POSIX Win32 ANSI C ANSI C++


+ +

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

Flushes all streams.

_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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.28.27 fopen, _wfopen


Header File

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:

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).

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,

• output cannot be directly followed by input without an intervening fseek or rewind


• input cannot be directly followed by output without an intervening fseek, rewind, or an input that encounters end-of-file
Return Value
On successful completion fopen returns a pointer to the newly opened stream. In the event of error it returns NULL.
Portability

POSIX Win32 ANSI C ANSI C++


fopen + + + +
_wfopen NT only

3.1.4.28.28 fprintf, fwprintf


Header File

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

Writes formatted output to a stream.

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

POSIX Win32 ANSI C ANSI C++


fprintf + + + +
fwprintf + + +

3.1.4.28.29 fputc, fputwc


Header File

stdio.h

Category

Input/output Routines

Prototype
int fputc(int c, FILE *stream);
wint_t fputwc(wint_t c, FILE *stream);

Description

Puts a character on a stream.

fputc outputs character c to the named stream.

Note: For Win32 GUI applications, stdin must be redirected.

Return Value

On success, fputc returns the character c. On error, it returns EOF.

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

POSIX Win32 ANSI C ANSI C++


fputc + + + +
fputwc + + +

3.1.4.28.30 _fputchar, _fputwchar


Header File

stdio.h

Category

Input/output Routines

Prototype
int _fputchar(int c);
wint_t _fputwchar(wint_t c);

Description

Outputs a character to stdout.

_fputchar outputs character c to stdout. _fputchar(c) is the same as fputc(cstdout).

Note: For Win32 GUI applications, stdout must be redirected.

Return Value

On success _fputchar returns the character c.

On error it returns EOF.

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

POSIX Win32 ANSI C ANSI C++


3 _fputchar +
_fputwchar +

3.1.4.28.31 fputs, fputws


Header File

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

Outputs a string on a stream.

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

On success fputs returns a non-negative value.

On error it returns a value of EOF.

Example
#include <stdio.h>
int main(void)
{
/* write a string to standard output */
fputs("Hello world\n", stdout);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


fputs + + + +
fputws + + +

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

Reads data from a stream.

fread reads n items of data each of length size bytes from the given input stream into a block pointed to by ptr.

The total number of bytes read is (n * size).

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.

On end-of-file or error it returns a short count (possibly 0).

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.33 freopen, _wfreopen


Header File

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

Associates a new file with an open stream.


3
freopen substitutes the named file in place of the open stream. It closes stream regardless of whether the open succeeds.
freopen is useful for changing the file attached to stdin, stdout, or stderr.

The mode string used in calls to fopen is one of the following values:

r Open for reading only.


w Create for writing. .

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,

• output cannot be directly followed by input without an intervening fseek or rewind


• input cannot be directly followed by output without an intervening fseek, rewind, or an input that encounters end-of-file
Return Value
On successful completion freopen returns the argument stream.
On error it returns NULL.
Example
#include <stdio.h>
int main(void)
{
/* redirect standard output to a file */
if (freopen("OUTPUT.FIL", "w", stdout)
== NULL)
fprintf(stderr, "error redirecting stdout\n");
/* this output will go to a file */
printf("This will go into a file.");
/* close the standard output stream */
fclose(stdout);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


freopen + + + +
_wfreopen NT only

3.1.4.28.34 fscanf, fwscanf


Header File

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

Scans and formats input from a stream.

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.

Note: For details on format specifiers, see scanf Format Specifiers.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

Repositions a file pointer on a stream.

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 returns 0 if the pointer is successfully moved and nonzero on failure.

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:

EBADF Bad file pointer


EINVAL Invalid argument
ESPIPE Illegal seek on device

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

int fsetpos(FILE *stream, const fpos_t *pos);

Description

Positions the file pointer of a stream.

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 success fsetpos returns 0.

On failure it returns a nonzero value and also sets the global variable errno to a nonzero value.

Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.37 ftell
Header File

stdio.h

Category

Input/output Routines

Prototype
long int ftell(FILE *stream);

Description

Returns the current file pointer.

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:

EBADF Bad file pointer


ESPIPE Illegal seek on device
3
Example
#include <stdio.h>
int main(void)
{
FILE *stream;
stream = fopen("MYFILE.TXT", "w+");
fprintf(stream, "This is a test");
printf("The file pointer is at byte %ld\n", ftell(stream));
fclose(stream);

1050
3.1 C++ Reference RAD Studio C Runtime Library Reference

return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

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.

On error it returns a short count.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

1051
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.28.39 getc, getwc


Header File

stdio.h

Category

Input/output Routines

Prototype
int getc(FILE *stream);
wint_t getwc(FILE *stream);

Description

Gets character from stream.

getc returns the next character on the given input stream and increments the stream's file pointer to point to the next character.

Note: For Win32 GUI applications, stdin must be redirected.

Return Value

On success, getc 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;
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

POSIX Win32 ANSI C ANSI C++


getc + + + +
getwc + + +

3.1.4.28.40 getchar, getwchar


3
Header File

stdio.h

Category

Console I/O Routines

Prototype

1052
3.1 C++ Reference RAD Studio C Runtime Library Reference

int getchar(void);
wint_t getwchar(void);

Description

Gets character from stdin.

getchar is a macro that returns the next character on the named input stream stdin. It is defined to be getc(stdin).

Note: Do not use this function in Win32 GUI applications.

Return Value

On success, getchar 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)
{
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

POSIX Win32 ANSI C ANSI C++


getchar + + + +
getwchar + + +

3.1.4.28.41 gets, _getws


Header File

stdio.h

Category

Console I/O Routines

Prototype
char *gets(char *s);
wchar_t *_getws(wchar_t *s); // Unicode version 3
Description

Gets a string from stdin.

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.

Note: For Win32 GUI applications, stdin must be redirected.

Return Value

On success, gets returns the string argument s.

On end-of-file or error, it returns NULL

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

POSIX Win32 ANSI C ANSI C++


gets + + + +
_getws +

3.1.4.28.42 _getw
Header File

stdio.h

Category

Input/output Routines

Prototype
int _getw(FILE *stream);

Description

Gets an integer from stream.

_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.

On end-of-file or error, _getw returns EOF.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.28.43 printf, wprintf


Header File

stdio.h

Category

Console I/O Routines

Prototype
3
int printf(const char *format[, argument, ...]);
int wprintf(const wchar_t *format[, argument, ...]);

Description

Writes formatted output to stdout.

The printf function:

1055
C Runtime Library Reference RAD Studio 3.1 C++ Reference

• Accepts a series of arguments


• Applies to each argument a format specifier contained in the format string *format
• Outputs the formatted data (to the screen, a stream, stdout, or a string)
There must be enough arguments for the format. If there are not, the results will be unpredictable and likely disastrous. Excess
arguments (more than required by the format) are merely ignored.
Note: For Win32 GUI applications, stdout must be redirected.
Return Value
On success, printf returns the number of bytes output.
On error, printf returns EOF.
More About printf
Example
#include <stdio.h>
#include <string.h>
#define I 555
#define R 5.5
int main(void)
{
int i,j,k,l;
char buf[7];
char *prefix = buf;
char tp[20];
printf("prefix 6d 6o 8x 10.2e "
"10.2f\n");
strcpy(prefix,"%");
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
for (k = 0; k < 2; k++)
for (l = 0; l < 2; l++)
{
if (i==0) strcat(prefix,"-");
if (j==0) strcat(prefix,"+");
if (k==0) strcat(prefix,"#");
if (l==0) strcat(prefix,"0");
printf("%5s |",prefix);
strcpy(tp,prefix);
strcat(tp,"6d |");
printf(tp,I);
strcpy(tp,"");
strcpy(tp,prefix);
strcat(tp,"6o |");
printf(tp,I);
strcpy(tp,"");
strcpy(tp,prefix);
strcat(tp,"8x |");
printf(tp,I);
strcpy(tp,"");
strcpy(tp,prefix);
strcat(tp,"10.2e |");
3 printf(tp,R);
strcpy(tp,prefix);
strcat(tp,"10.2f |");
printf(tp,R);
printf(" \n");
strcpy(prefix,"%");
}
}
return 0;
}

1056
3.1 C++ Reference RAD Studio C Runtime Library Reference

Portability

POSIX Win32 ANSI C ANSI C++


printf + + + +
_wprintf +

3.1.4.28.44 putc, putwc


Header File

stdio.h

Category

Input/output Routines

Prototype
int putc(int c, FILE *stream);
wint_t putwc(wint_t c, FILE *stream);

Description

Outputs a character to a stream.

putc is a macro that outputs the character c to the stream given by stream.

Return Value

On success, putc returns the character printed, c.

On error, putc returns EOF.

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

POSIX Win32 ANSI C ANSI C++


putc + + + +
putwc + + +
3

3.1.4.28.45 putchar, putwchar


Header File

stdio.h

Category

1057
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Console I/O Routines

Prototype
int putchar(int c);
wint_t putwchar(wint_t c);

Description

putchar is a macro defined to be putc(c, stdout).

Note: For Win32 GUI applications, stdout must be redirected.

Return Value

On success, putchar returns the character c. On error, putchar returns EOF.

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

3.1.4.28.46 puts, _putws


Header File

stdio.h

Category

Console I/O Routines

Prototype
int puts(const char *s);
int _putws(const wchar_t *s);

Description

Outputs a string to stdout.

puts copies the null-terminated string s to the standard output stream stdout and appends a newline character.

Note: For Win32 GUI applications, stdout must be redirected.

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

POSIX Win32 ANSI C ANSI C++


puts + + + +
_putws +

3.1.4.28.47 _putw
Header File

stdio.h

Category
3
Input/output Routines

Prototype
int _putw(int w, FILE *stream);

Description

Writes an integer on a stream.

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

POSIX Win32 ANSI C ANSI C++


+

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.

The filename string can include a full path.

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:

EACCES Permission denied


ENOENT No such file or directory

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

POSIX Win32 ANSI C ANSI C++


remove + + + +
_wremove NT only

3.1.4.28.49 rename, _wrename


Header File

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 success, rename returns 0.

On error (if the file cannot be renamed), it returns -1 and the global variable errno is set to one of the following values:

EEXIST Permission denied: file already exists.


ENOENT No such file or directory
ENOTSAM Not same device

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

POSIX Win32 ANSI C ANSI C++


rename + + + +
_wrename NT only

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

Repositions a file pointer to the beginning of a stream.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.51 _rmtmp
Header File

stdio.h

Category

Input/output Routines

Prototype
int _rmtmp(void);

Description

Removes temporary files. 3


The _rmtmp function closes and deletes all open temporary file streams which were previously created with tmpfile. The current
directory must the same as when the files were created, or the files will not be deleted.

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;

/* Create temporary files */


for (i = 1; i <= 10; i++)
{
if ((stream = tmpfile()) == NULL)
perror("Could not open temporary file\n");
else
printf("Temporary file %d created\n", i);
}
/* Remove temporary files */
if (stream != NULL)
printf("%d temporary files deleted\n", rmtmp());
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.28.52 scanf, wscanf


Header File

stdio.h

Category

Console I/O Routines

Prototype
int scanf(const char *format[, address, ...]);
int wscanf(const wchar_t *format[, address, ...]);

Description

Scans and formats input from the stdin stream.

Note: For Win32 GUI applications, stdin must be redirected.

The scanf function:

• scans a series of input fields one character at a time


• formats each field according to a corresponding format specifier passed in the format string *format.
3 • vsscanf scans and formats input from a string, using an argument list
There must be one format specifier and address for each input field.
scanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace) character, or it might terminate
entirely. For details about why this might happen, see When ...scanf Stops Scanning.
Note: scanf often leads to unexpected results if you diverge from an expected pattern. You must provide information that tells
scanf how to synchronize at the end of a line.
The combination of gets or fgets followed by sscanf is safe and easy, and therefore recommended over scanf.

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

Assigns buffering to a stream.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

Assigns buffering to a stream.

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.

The parameter size is limited by the constant UINT_MAX as defined in limits.h.

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.

• The type parameter is one of the following:

_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 success, setvbuf returns 0.

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

if (setvbuf(input, bufr, _IOFBF, 512) != 0)


printf("failed to set up buffer for input file\n");
else
printf("buffer set up for input file\n");
/* set up output stream for line buffering using space that
will be obtained through an indirect call to malloc */
if (setvbuf(output, NULL, _IOLBF, 132) != 0)
printf("failed to set up buffer for output file\n");
else
printf("buffer set up for output file\n");
/* perform file I/O here */
/* close files */
fclose(input);
fclose(output);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.55 snprintf;snwprintf
Header File

stdio.h

Category

Memory and String Manipulation Routines

Prototype
int snprintf(char* buffer, size_t nsize, const char* fmt, ...);
int snwprintf(wchar_t* buffer, size_t nsize, const wchar_t* fmt, ...);

Description

Sends formatted output to a buffer of a maximum length specified by nsize.

If the number of bytes to output is:

• < 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

Memory and String Manipulation Routines

Prototype
int sprintf(char *buffer, const char *format[, argument, ...]);
int swprintf(wchar_t *buffer, const wchar_t *format[, argument, ...]);

Description

Writes formatted output to a string.

Note: For details on format specifiers, see printf.

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.

On error, sprintf returns EOF.

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

POSIX Win32 ANSI C ANSI C++


sprintf + + + +
swprintf + + +

3.1.4.28.57 sscanf, swscanf


Header File

stdio.h

Category

Memory and String Manipulation Routines


3
Syntax
int sscanf(const char *buffer, const char *format[, address, ...]);
int swscanf(const wchar_t *buffer, const wchar_t *format[, address, ...]);

Description

Scans and formats input from a string.

1069
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Note: For details on format specifiers, see scanf.

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.

If sscanf attempts to read at end-of-string, it returns EOF.

On error (If no fields were stored), it returns 0.

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

POSIX Win32 ANSI C ANSI C++


sscanf + + + +
swscanf + + +

3
3.1.4.28.58 stderr, stdin, stdout
Header File

stdio.h

Description

Predefined streams automatically opened when the program is started.

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

3.1.4.28.59 _tempnam, _wtempnam


Header File

stdio.h

Category

Input/output Routines

Prototype
char *_tempnam(char *dir, char *prefix)
wchar_t *_wtempnam(wchar_t *dir, wchar_t *prefix)

Description

Creates a unique file name in specified directory.

The _tempnam function accepts single-byte or multibyte string arguments.

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:

• The directory specified by the TMP environment variable.


• The dir argument to _tempnam.
• The P_tmpdir definition in stdio.h. If you edit stdio.h and change this definition, _tempnam will not use the new definition.
• The current working directory.
If any of these directories is NULL, or undefined, or does not exist, it is skipped.
The prefix argument specifies the first part of the file name; it cannot be longer than 5 characters, and cannot contain a period (.).
A unique file name is created by concatenating the directory name, the prefix, and 6 unique characters. Space for the
resulting file name is allocated with malloc; when this file name is no longer needed, the caller should call free to free it.
If you do create a temporary file using the name constructed by _tempnam, 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 _tempnam is successful, it returns a pointer to the unique temporary file name, which the caller can pass to free when it is no
longer needed. Otherwise, if _tempnam cannot create a unique file name, it returns NULL.
Example
#include <stdio.h> 3
#include <stdlib.h>
void main(void)
{
FILE *stream;
int i;
char *name;
for (i = 1; i <= 10; i++) {
if ((name = tempnam("\\tmp","wow")) == NULL)
perror("tempnam couldn't create 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

POSIX Win32 ANSI C ANSI C++


_tempnam +
_wtempnam +

3.1.4.28.60 tmpfile
Header File

stdio.h

Category

Input/output Routines

Prototype
FILE *tmpfile(void);

Description

Opens a “scratch” file in binary mode.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.28.61 tmpnam, _wtmpnam


Header File

stdio.h

Category

Input/output Routines

Prototype
char *tmpnam(char *s);
wchar_t *_wtmpnam(wchar_t *s);

Description

Creates a unique file name.

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

POSIX Win32 ANSI C ANSI C++ 3


tmpnam + + + +
_wtmpnam +

3.1.4.28.62 ungetc, ungetwc


Header File

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

Pushes a character back into input stream.

Note: Do not use this function in Win32 GUI applications.

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

On success, ungetc returns the character pushed back.

On error, it returns EOF.

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

POSIX Win32 ANSI C ANSI C++


ungetc + + + +
ungetwc + + +

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

Writes formatted output to a stream.

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.

For details on format specifiers, see Printf Format Specifiers.

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

On success, vfprintf returns the number of bytes output.

On error, it returns EOF.

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

POSIX Win32 ANSI C ANSI C++


vfprintf + + + +
vfwprintf + + +

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

Scans and formats input from a stream.

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.

For details on format specifiers, see Scanf Format Specifiers.

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.

If vfscanf attempts to read at end-of-file the return value is EOF.

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

POSIX Win32 ANSI C ANSI C++


+ + +

3.1.4.28.65 vprintf, vwprintf


Header File

stdio.h

Category

Console I/O Routines

Prototype
int vprintf(const char *format, va_list arglist);
int vwprintf(const wchar_t * format, va_list arglist);

Description

Writes formatted output to stdout.

Note: Do not use this function in Win32 GUI applications.

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.

Note: For details on format specifiers, see Printf Format Specifiers.

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

POSIX Win32 ANSI C ANSI C++


vprintf + + + +
vwprintf + + +

3.1.4.28.66 vscanf
Header File

stdio.h

Category

Console I/O Routines

Prototype
int vscanf(const char *format, va_list arglist);

Description

Scans and formats input from stdin.

Note: Do not use this function in Win32 GUI applications.

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.

Note: For details on format specifiers, see Scanf Format Specifiers.

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.

If vscanf attempts to read at end-of-file, the return value is EOF.

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

POSIX Win32 ANSI C ANSI C++


+ + +

3.1.4.28.67 vsnprintf;vsnwprintf
Header File

stdio.h

Category

Memory and String Manipulation Routines

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 buffer of maximum length specified by nsize.

If the number of bytes to output is:

• < 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.1.4.28.68 vsprintf, vswprintf


Header File

stdio.h
3
Category

Memory and String Manipulation Routines

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

Writes formatted output to a string.

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

POSIX Win32 ANSI C ANSI C++


vsprintf + + + +
vswprintf + + +

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

_argc ( see page 1095) 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.
_argv, _wargv ( see page 1095) Header File
stdlib.h
Syntax
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.
_wargv is the Unicode version of _argv.
Portability
_atoi64, _wtoi64 ( see page 1096) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
__int64 _atoi64(const char *s);
__int64 _wtoi64(const wchar_t *s);
Description
Converts a string to an __int64.
The syntax of the string must be:
__int64 ::= [isspace]* [sign] digit [digit]*
Only decimal integers are acceptable.
_wtoi64 is the wide-character version. It converts a wide-character string to an
__int64.
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... more ( see page 1096)
_crotl, _crotr ( see page 1096) Header File
stdlib.h
Category
Math Routines
Prototype
unsigned char _crotl(unsigned char val, int count);
unsigned char _crotr(unsigned char val, int count);
Description
Rotates an unsigned char left or right.
_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

• The functions return the rotated byte:


• _crotl returns the value of val left-rotated count bits.
• _crotr returns the value of val right-rotated count bits.
3
Portability

1081
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_exit ( see page 1097) Header File


stdlib.h
Category
Process Control Routines
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
_fullpath, _wfullpath ( see page 1098) Header File
stdlib.h
Category
Directory Control Routines
Prototype
char * _fullpath(char *buffer, const char *path, int
buflen);
wchar_t * _wfullpath(wchar_t *buffer, const wchar_t *path,
int buflen);
Description
Converts a path name from relative to absolute.
_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... more ( see page 1098)
_lrand ( see page 1099) 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.
_lrotl, _lrotr ( see page 1099) Header File
stdlib.h
Category
Math Routines
Prototype
unsigned long _lrotl(unsigned long val, int count);
unsigned long _lrotr(unsigned long val, int count);
Description
Rotates an unsigned long integer value to the left or right.
_Irotlrotates the given val to the left count bits. _lrotr rotates the given val to the
right count bits.
3 Return Value
The functions return the rotated integer:

• _lrotl returns the value of val left-rotated count bits.


• _lrotr returns the value of val right-rotated count bits.
Example

1082
3.1 C++ Reference RAD Studio C Runtime Library Reference

_makepath, _wmakepath ( see page 1100) Header File


stdlib.h
Category
Directory Control Routines
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
Builds a path from component parts.
_makepath makes a path name from its components. The new path name is
X:\DIR\SUBDIR\NAME.EXT
where
_rotl, _rotr ( see page 1102) Header File
stdlib.h
Category
Math Routines
Prototype
unsigned short _rotl(unsigned short value, int count);
unsigned short _rotr(unsigned short value, int count);
Description
Bit-rotates an unsigned short integer value to the left or right.
_rotl rotates the given value to the left count bits.
_rotr rotates the given value to the right count bits.
Return Value
_rotl, and _rotr return the rotated integer:

• _rotl returns the value of value left-rotated count bits.


• _rotr returns the value of value right-rotated count bits.
Example
_searchenv, _wsearchenv ( see page 1103) Header File
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
Looks for a file, using an environment variable as the search path.
_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... more ( see page 1103)

1083
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_searchstr, _wsearchstr ( see page 1104) Header File


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
Searches a list of directories for a file.
_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,... more ( see page 1104)
_splitpath, _wsplitpath ( see page 1105) Header File
stdlib.h
Category
Directory Control Routines
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
Splits a full path name into its components.
_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... more ( see page 1105)
_ui64toa, _ui64tow ( see page 1106) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
char *_ui64toa(unsigned __int64 value, char *string, int
radix);
wchar_t *_ui64tow(unsigned __int64 value, wchar_t *string,
int radix);
Description
_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...
more ( see page 1106)

1084
3.1 C++ Reference RAD Studio C Runtime Library Reference

abort ( see page 1107) Header File


stdlib.h
Category
Process Control Routines
Prototype
void abort(void);
Description
Abnormally terminates a program.
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
atexit ( see page 1107) Header File
stdlib.h
Category
Process Control Routines
Prototype
int atexit(void (_USERENTRY * func)(void));
Description
Registers termination function.
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... more ( see page 1107)
atoi, _wtoi ( see page 1108) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
int atoi(const char *s);
int _wtoi(const wchar_t *s);
Description
Converts a string to an integer.

• 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). 3
Return Value
atoi returns the converted value of the input string. If the...
more ( see page 1108)

1085
C Runtime Library Reference RAD Studio 3.1 C++ Reference

atol, _wtol ( see page 1109) Header File


stdlib.h
Category
Conversion Routines, Math Routines
Prototype
long atol(const char *s);
long _wtol(const wchar_t *s);
Description
Converts a string to a long.

• atol converts the string pointed to by s to long. atol


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 atol
(results are undefined).
Return Value
atol returns the converted value of the input string. If the...
more ( see page 1109)
bsearch ( see page 1110) Header File
stdlib.h
Category
Memory and String Manipulation Routines
Prototype
void *bsearch(const void *key, const void *base, size_t
nelem, size_t width, int (_USERENTRY *fcmp)(const void *,
const void *));
Description
Binary search of an array.
bsearch searches a table (array) of nelem elements in memory, and returns the
address of the first entry in the table that 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.
The type size_t is defined... more ( see page 1110)
div ( see page 1111) Header File
stdlib.h
Category
Math Routines
Prototype
div_t div(int numer, int denom);
Description
Divides two integers, returning quotient and remainder.
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.
3 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

1086
3.1 C++ Reference RAD Studio C Runtime Library Reference

ecvt ( see page 1112) Header File


stdlib.h
Category
Conversion Routines, Math Routines
Prototype
char *ecvt(double value, int ndig, int *dec, int *sign);
Description
Converts a floating-point number to a string.
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... more ( see page 1112)
_environ, _wenviron ( see page 1113) Header File
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... more ( see page 1113)
exit ( see page 1114) Header File
stdlib.h
Category
Process Control Routines
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:
fcvt ( see page 1114) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
char *fcvt(double value, int ndig, int *dec, int *sign);
Description
Converts a floating-point number to a string.
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... more
( see page 1114)
3

1087
C Runtime Library Reference RAD Studio 3.1 C++ Reference

gcvt ( see page 1115) Header File


stdlib.h
Category
Conversion Routines, Math Routines
Prototype
char *gcvt(double value, int ndec, char *buf);
Description
Converts floating-point number to a string.
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
gcvt returns the address of the string pointed to by buf.
Example
getenv, _wgetenv ( see page 1116) Header File
stdlib.h
Category
Process Control Routines
Prototype
char *getenv(const char *name);
wchar_t *_wgetenv(const wchar_t *name);
Description
Find or delete an environment variable from the system environment.
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.
To delete the variable from the environment, use getenv("name=").
Note: Environment entries must not be changed directly. If you want to... more
( see page 1116)
itoa, _itow ( see page 1117) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
char *itoa(int value, char *string, int radix);
wchar_t *_itow(int value, wchar_t *string, int radix);
Description
Converts an integer to a string.
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... more ( see page 1117)
labs ( see page 1118) Header File
stdlib.h
Category
Math Routines
Prototype
long labs(long int x);
Description
Gives long absolute value.
3 labs computes the absolute value of the parameter x.
Return Value
labs returns the absolute value of x.
Example

1088
3.1 C++ Reference RAD Studio C Runtime Library Reference

lfind ( see page 1119) Header File


stdlib.h
Category
Memory and String Manipulation Routines
Prototype
void *lfind(const void *key, const void *base, size_t *num,
size_t width, int (_USERENTRY *fcmp)(const void *, const
void *));
Description
Performs a linear search.
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... more ( see page 1119)
lsearch ( see page 1120) Header File
stdlib.h
Category
Memory and String Manipulation Routines
Prototype
void *lsearch(const void *key, void *base, size_t *num,
size_t width, int (_USERENTRY *fcmp)(const void *, const
void *));
Description
Performs a linear search.
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.

• base points to the base (0th element) of the search table.


• num points to an integer containing the number of entries
in... more ( see page 1120)
ltoa, _ltoa, _ltow ( see page 1121) Header File
stdlib.h
Category
Conversion Routines, Math Routines
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... more (
see page 1121)
max ( see page 1122) Header File
stdlib.h
Category
C++ Prototyped Routines
Prototype
(type) max(a, b); 3
template <class T> T max( T t1, T t2 ); // C++ only
Description
Returns the larger of two values.
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
max returns the larger of two values.
Portability

1089
C Runtime Library Reference RAD Studio 3.1 C++ Reference

mblen ( see page 1122) Header File


stdlib.h
Category
Memory and String Manipulation Routines
Prototype
int mblen(const char *s, size_t n);
Description
Determines the length of a multibyte character.
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... more ( see page 1122)
mbstowcs ( see page 1123) Header File
stdlib.h
Category
Conversion Routines, Memory and String Manipulation Routines
Prototype
size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n);
Description
Converts a multibyte string to a wchar_t array.
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... more ( see page 1123)
mbtowc ( see page 1124) Header File
stdlib.h
Category
Conversion Routines, Memory and String Manipulation Routines
Prototype
int mbtowc(wchar_t *pwc, const char *s, size_t n);
Description
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... more ( see page 1124)
min ( see page 1125) Header File
stdlib.h
Category
C++ Prototyped Routines
Prototype
(type) min(a, b); /* macro version */
template <class T> T min( T t1, T t2 );// C++ only
Description
Returns the smaller of two values.
3 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
min returns the smaller of two values.

1090
3.1 C++ Reference RAD Studio C Runtime Library Reference

putenv, _wputenv ( see page 1126) Header File


stdlib.h
Category
Process Control Routines
Prototype
int putenv(const char *name);
int _wputenv(const wchar_t *name);
Description
Adds string to current environment.
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.... more
( see page 1126)
qsort ( see page 1127) Header File
stdlib.h
Category
Memory and String Manipulation Routines
Prototype
void qsort(void *base, size_t nelem, size_t width, int
(_USERENTRY *fcmp)(const void *, const void *));
Description
Sorts using the quicksort algorithm.
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.

• base points to the base (0th element) of the table to be


sorted.
• nelem is the number of entries in the table.
• width is the size of each entry in the table, in bytes.
fcmp, the comparison... more ( see page 1127)
rand ( see page 1128) Header File
stdlib.h
Category
Math Routines
Prototype
int rand(void);
Description
Random number generator.
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
rand returns the generated pseudo-random number.
Example

1091
C Runtime Library Reference RAD Studio 3.1 C++ Reference

random ( see page 1128) Header File


stdlib.h
Category
Math Routines
Prototype
int random(int num);
Description
Random number generator.
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
random returns a number between 0 and (num-1).
Example
randomize ( see page 1129) Header File
stdlib.h, time.h
Category
Math Routines
Prototype
void randomize(void);
Description
Initializes random number generator.
randomize initializes the random number generator with a random value.
Return Value
None.
Example
srand ( see page 1130) Header File
stdlib.h
Category
Math Routines
Prototype
void srand(unsigned seed);
Description
Initializes random number generator.
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
strlen, _mbslen, wcslen, _mbstrlen ( see page 1131) Header File
string.h, mbstring.h, stdlib.h
Category
Memory and String Manipulation Routines, Inline Routines
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
Calculates the length of a string.
strlen calculates the length of s.
_mbslen and _mbstrlen test the string argument to determine the number of
multibyte characters they contain.
3 _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... more ( see page
1131)

1092
3.1 C++ Reference RAD Studio C Runtime Library Reference

strtod, _strtold, wcstod, _wcstold ( see page 1131) Header File


stdlib.h
Category
Conversion Routines, Math Routines
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
Convert a string to a double or long double value.
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:
strtol, wcstol ( see page 1133) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
long strtol(const char *s, char **endptr, int radix);
long wcstol(const wchar_t *s, wchar_t **endptr, int radix);
Description
Converts a string to a long value.
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:
strtoul, wcstoul ( see page 1134) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
unsigned long strtoul(const char *s, char **endptr, int
radix);
unsigned long wcstoul(const wchar_t *s, wchar_t **endptr,
int radix);
Description
Converts a string to an unsigned long in the given radix.
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.
Return Value
strtoul returns the converted value, an unsigned long, or 0 on error.
Example
swab ( see page 1135) Header File
stdlib.h
Category
Memory and String Manipulation Routines
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- 3
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

1093
C Runtime Library Reference RAD Studio 3.1 C++ Reference

system, _wsystem ( see page 1136) Header File


stdlib.h
Category
Process Control Routines
Prototype
int system(const char *command);
int _wsystem(const wchar_t *command);
Description
Issues an operating system command.
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... more ( see page 1136)
ultoa, _ultow ( see page 1137) Header File
stdlib.h
Category
Conversion Routines, Math Routines
Prototype
char *ultoa(unsigned long value, char *string, int radix);
wchar_t *_ultow(unsigned long value, wchar_t *string, int
radix);
Description
Converts an unsigned long to a string.
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... more ( see page 1137)
wcstombs ( see page 1137) Header File
stdlib.h
Category
Conversion Routines, Memory and String Manipulation Routines
Prototype
size_t wcstombs(char *s, const wchar_t *pwcs, size_t n);
Description
Converts a wchar_t array into a multibyte string.
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... more ( see page 1137)
wctomb ( see page 1138) Header File
stdlib.h
Category
Conversion Routines, Memory and String Manipulation Routines
Prototype
int wctomb(char *s, wchar_t wc);
Description
3 Converts wchar_t code to a multibyte character.
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... more ( see page 1138)

1094
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.29.1 EXIT_xxxx #defines


Header File

stdlib.h

Description

Constants defining exit conditions for calls to the exit function.

Name Meaning
EXIT_SUCCESS Normal program termination
EXIT_FAILURE Abnormal program termination

3.1.4.29.2 RAND_MAX #define


Header File

stdlib.h

Syntax

Description

Maximum value returned by rand function.

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.

3.1.4.29.4 _argv, _wargv


Header File

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

_wargv is the Unicode version of _argv.

Portability

POSIX Win32 ANSI C ANSI C++


_argv +
_wargv NT only

3.1.4.29.5 _atoi64, _wtoi64


Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
__int64 _atoi64(const char *s);
__int64 _wtoi64(const wchar_t *s);

Description

Converts a string to an __int64.

The syntax of the string must be:


__int64 ::= [isspace]* [sign] digit [digit]*

Only decimal integers are acceptable.

_wtoi64 is the wide-character version. It converts a wide-character string to an __int64.

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

POSIX Win32 ANSI C ANSI C++


_atoi64 +
_wtoi64 +

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

Rotates an unsigned char left or right.

_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

• The functions return the rotated byte:


• _crotl returns the value of val left-rotated count bits.
• _crotr returns the value of val right-rotated count bits.
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.7 _exit
Header File

stdlib.h

Category

Process Control Routines

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

POSIX Win32 ANSI C ANSI C++


+ +

3.1.4.29.8 _fullpath, _wfullpath


Header File

stdlib.h

Category

Directory Control Routines

Prototype
char * _fullpath(char *buffer, const char *path, int buflen);
wchar_t * _wfullpath(wchar_t *buffer, const wchar_t *path, int buflen);

Description

Converts a path name from relative to absolute.

_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.

On error, this function returns NULL.

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

POSIX Win32 ANSI C ANSI C++


_fullpath +

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.

3.1.4.29.10 _lrotl, _lrotr


Header File

stdlib.h

Category

Math Routines

Prototype
unsigned long _lrotl(unsigned long val, int count);
unsigned long _lrotr(unsigned long val, int count);

Description

Rotates an unsigned long integer value to the left or right.

_Irotlrotates the given val to the left count bits. _lrotr rotates the given val to the right count bits.

Return Value

The functions return the rotated integer:

• _lrotl returns the value of val left-rotated count bits.


• _lrotr returns the value of val right-rotated count bits. 3
Example
#include <stdlib.h>
#include <stdio.h>
/* function prototypes */
int lrotl_example(void);
int lrotr_example(void);
/* lrotl example */
int lrotl_example(void)

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.11 _makepath, _wmakepath


Header File

stdlib.h

Category

Directory Control Routines

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

Builds a path from component parts.

_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 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.

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

POSIX Win32 ANSI C ANSI C++


_makepath +
_wmakepath +

3.1.4.29.12 _rotl, _rotr


Header File

stdlib.h

Category

Math Routines

Prototype
unsigned short _rotl(unsigned short value, int count);
unsigned short _rotr(unsigned short value, int count);

Description

Bit-rotates an unsigned short integer value to the left or right.

_rotl rotates the given value to the left count bits.

_rotr rotates the given value to the right count bits.

Return Value

_rotl, and _rotr return the rotated integer:

• _rotl returns the value of value left-rotated count bits.


• _rotr returns the value of value right-rotated count bits.
Example
#include <stdlib.h>
#include <stdio.h>
/* rotl example */
int rotl_example(void)
{
unsigned value, result;
value = 32767;
result = _rotl(value, 1);
printf("The value %u rotated left one bit is: %u\n", value, result);
return 0;
}
/* rotr example */
int rotr_example(void)
{
unsigned value, result;
3 value = 32767;
result = _rotr(value, 1);
printf("The value %u rotated right one bit is: %u\n", value, result);
return 0;
}
int main(void)
{
rotl_example();
rotr_example();
return 0;
}

1102
3.1 C++ Reference RAD Studio C Runtime Library Reference

Portability

POSIX Win32 ANSI C ANSI C++


_rotl +
_rotr

3.1.4.29.13 _searchenv, _wsearchenv


Header File

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

Looks for a file, using an environment variable as the search path.

_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);

/* looks for nonexistent file */


_searchenv("NOTEXIST.FIL","PATH",buf);
if (buf[0] == '\0')
printf("NOTEXIST.FIL not found\n");
else

1103
C Runtime Library Reference RAD Studio 3.1 C++ Reference

printf("NOTEXIST.FIL found in %s\n", buf);


return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


_searchenv +
_wsearchenv NT only

3.1.4.29.14 _searchstr, _wsearchstr


Header File

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

Searches a list of directories for a file.

_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

POSIX Win32 ANSI C ANSI C++


_searchstr +
_wsearchstr NT only

3.1.4.29.15 _splitpath, _wsplitpath


Header File

stdlib.h

Category

Directory Control Routines

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

Splits a full path name into its components.

_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.

When _splitpath splits path, it treats the punctuation as follows:

• drive includes the colon (C:, A:, and so on).


• dir includes the leading and trailing backslashes (\BC\include\, \source\, and so on). 3
• name includes the file name.
• ext includes the dot preceding the extension (.C, .EXE, and so on).
_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
None.

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

POSIX Win32 ANSI C ANSI C++


_splitpath +
_wsplitpath +

3.1.4.29.16 _ui64toa, _ui64tow


Header File

stdlib.h

Category

Conversion Routines, Math Routines

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

(\0). Can return up to 33 bytes.

Return Value

Returns a pointer to string.

Portability

POSIX Win32 ANSI C ANSI C++


_ui64toa
_ui64tow +

3.1.4.29.17 abort
Header File

stdlib.h

Category

Process Control Routines

Prototype
void abort(void);

Description

Abnormally terminates a program.

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

POSIX Win32 ANSI C ANSI C++


+ + + +
3

3.1.4.29.18 atexit
Header File

stdlib.h

1107
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Category

Process Control Routines

Prototype
int atexit(void (_USERENTRY * func)(void));

Description

Registers termination function.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.19 atoi, _wtoi


Header File

stdlib.h
3
Category

Conversion Routines, Math Routines

Prototype
int atoi(const char *s);
int _wtoi(const wchar_t *s);

1108
3.1 C++ Reference RAD Studio C Runtime Library Reference

Description

Converts a string to an integer.

• 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

POSIX Win32 ANSI C ANSI C++


atoi + + + +
_wtoi +

3.1.4.29.20 atol, _wtol


Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
long atol(const char *s); 3
long _wtol(const wchar_t *s);

Description

Converts a string to a long.

• 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

POSIX Win32 ANSI C ANSI C++


atol + + + +
_wtol +

3.1.4.29.21 bsearch
Header File

stdlib.h

Category

Memory and String Manipulation Routines

Prototype
void *bsearch(const void *key, const void *base, size_t nelem, size_t width, int (_USERENTRY
*fcmp)(const void *, const void *));

Description

Binary search of an array.

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.

The type size_t is defined in stddef.h header file.

• nelem gives the number of elements in the table.


• width specifies the number of bytes in each table entry.
The comparison routine fcmp must be used with the _USERENTRY calling convention.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

Divides two integers, returning quotient and remainder.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.23 ecvt
Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
char *ecvt(double value, int ndig, int *dec, int *sign);

Description

Converts a floating-point number to a string.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.24 _environ, _wenviron


Header File

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

POSIX Win32 ANSI C ANSI C++


_environ +
_wenviron NT only

1113
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.29.25 exit
Header File

stdlib.h

Category

Process Control Routines

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3 3.1.4.29.26 fcvt
Header File

stdlib.h

Category

Conversion Routines, Math Routines

1114
3.1 C++ Reference RAD Studio C Runtime Library Reference

Prototype
char *fcvt(double value, int ndig, int *dec, int *sign);

Description

Converts a floating-point number to a string.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.27 gcvt
Header File

stdlib.h 3
Category

Conversion Routines, Math Routines

Prototype
char *gcvt(double value, int ndec, char *buf);

Description

1115
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Converts floating-point number to a string.

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

gcvt returns the address of the string pointed to by buf.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.28 getenv, _wgetenv


Header File

stdlib.h

Category

Process Control Routines

Prototype
char *getenv(const char *name);
wchar_t *_wgetenv(const wchar_t *name);
3
Description

Find or delete an environment variable from the system environment.

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.

To delete the variable from the environment, use getenv("name=").

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

On success, getenv returns the value associated with name.

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

POSIX Win32 ANSI C ANSI C++


getenv + + + +
_wgetenv +

3.1.4.29.29 itoa, _itow


Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
char *itoa(int value, char *string, int radix);
wchar_t *_itow(int value, wchar_t *string, int radix);
3
Description

Converts an integer to a string.

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

itoa returns a pointer to string.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.30 labs
Header File

stdlib.h

Category

Math Routines

Prototype
long labs(long int x);

Description

Gives long absolute value.

labs computes the absolute value of the parameter x.

Return Value

labs returns the absolute value of x.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.31 lfind
Header File

stdlib.h

Category

Memory and String Manipulation Routines

Prototype
void *lfind(const void *key, const void *base, size_t *num, size_t width, int (_USERENTRY
*fcmp)(const void *, const void *));

Description

Performs a linear search.

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

POSIX Win32 ANSI C ANSI C++


+

1119
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.29.32 lsearch
Header File

stdlib.h

Category

Memory and String Manipulation Routines

Prototype
void *lsearch(const void *key, void *base, size_t *num, size_t width, int (_USERENTRY
*fcmp)(const void *, const void *));

Description

Performs a linear search.

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.

• base points to the base (0th element) of the search table.


• num points to an integer containing the number of entries in the table.
• width contains the number of bytes in each entry.
• key points to the item to be searched for (the search key).
The function fcmp must be used with the _USERENTRY calling convention.
The argument fcmp points to a user-written comparison routine, that compares two items and returns a value based on the
comparison.
To search the table, lsearch makes repeated calls to the routine whose address is passed in fcmp.
On each call to the comparison routine, lsearch passes two arguments:

key a pointer to the item being searched for


elem pointer to the element of base being compared.

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

(int(*)(const void *,const void *))colorscmp);


return(ncolors == oldn);
}
int main(void)
{
int i;
char *key = "Purple";
if (addelem(&key))
printf("%s already in colors table\n", key);
else
{
printf("%s added to colors table\n", key);
}
printf("The colors:\n");
for (i = 0; i < ncolors; i++)
printf("%s\n", colors[i]);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.33 ltoa, _ltoa, _ltow


Header File

stdlib.h

Category

Conversion Routines, Math Routines

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

Returns a pointer to string.

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

POSIX Win32 ANSI C ANSI C++


ltoa +
_ltoa +
_ltow +

3.1.4.29.34 max
Header File

stdlib.h

Category

C++ Prototyped Routines

Prototype
(type) max(a, b);
template <class T> T max( T t1, T t2 ); // C++ only

Description

Returns the larger of two values.

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

max returns the larger of two values.

Portability

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.35 mblen
3 Header File

stdlib.h

Category

Memory and String Manipulation Routines

Prototype
int mblen(const char *s, size_t n);

1122
3.1 C++ Reference RAD Studio C Runtime Library Reference

Description

Determines the length of a multibyte character.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

Converts a multibyte string to a wchar_t array.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.37 mbtowc
Header File

stdlib.h

Category

Conversion Routines, Memory and String Manipulation Routines

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.

The return value never exceeds MB_CUR_MAX or the value of n.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.38 min
Header File

stdlib.h

Category

C++ Prototyped Routines

Prototype
(type) min(a, b); /* macro version */
template <class T> T min( T t1, T t2 );// C++ only 3
Description

Returns the smaller of two values.

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

min returns the smaller of two values.

3.1.4.29.39 putenv, _wputenv


Header File

stdlib.h

Category

Process Control Routines

Prototype
int putenv(const char *name);
int _wputenv(const wchar_t *name);

Description

Adds string to current environment.

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

On success, putenv returns 0; on failure, -1.

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

POSIX Win32 ANSI C ANSI C++


putenv +
_wputenv NT only

3.1.4.29.40 qsort
Header File

stdlib.h

Category

Memory and String Manipulation Routines

Prototype
void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const
void *));

Description

Sorts using the quicksort algorithm.

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.

• base points to the base (0th element) of the table to be sorted.


• nelem is the number of entries in the table.
• width is the size of each entry in the table, in bytes.
fcmp, the comparison function, must be used with the _USERENTRY calling convention.
• fcmp accepts two arguments, elem1 and elem2, each a pointer to an entry in the table. The comparison function compares
each of the pointed-to items (*elem1 and *elem2), and returns an integer based on the result of the comparison.
• *elem1 < *elem2 fcmp returns an integer < 0
• *elem1 == *elem2 fcmp returns 0
• *elem1 > *elem2 fcmp returns an integer > 0
In the comparison, the less-than symbol (<) means the left element should appear before the right element in the final, sorted
sequence. Similarly, the greater-than (>) symbol means the left element should appear after the right element in the final,
sorted sequence.
Return Value
None.
Example
#include <stdio.h>
#include <stdlib.h> 3
#include <string.h>
int sort_function( const void *a, const void *b);
char list[5][4] = { "cat", "car", "cab", "cap", "can" };
int main(void)
{
int x;
qsort((void *)list, 5, sizeof(list[0]), sort_function);
for (x = 0; x < 5; x++)
printf("%s\n", list[x]);
return 0;

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.41 rand
Header File

stdlib.h

Category

Math Routines

Prototype
int rand(void);

Description

Random number generator.

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

rand returns the generated pseudo-random number.

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

POSIX Win32 ANSI C ANSI C++


3 + + + +

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 number generator.

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

random returns a number between 0 and (num-1).

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.43 randomize
Header File

stdlib.h, time.h

Category

Math Routines

Prototype
void randomize(void);

Description

Initializes random number generator.


3
randomize initializes the random number generator with a random value.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.29.44 srand
Header File

stdlib.h

Category

Math Routines

Prototype
void srand(unsigned seed);

Description

Initializes random number generator.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

1130
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.29.45 strlen, _mbslen, wcslen, _mbstrlen


Header File

string.h, mbstring.h, stdlib.h

Category

Memory and String Manipulation Routines, Inline Routines

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

Calculates the length of a string.

strlen calculates the length of s.

_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

POSIX Win32 ANSI C ANSI C++


strlen + + + +
_mbslen +
wcslen + + + 3
_mbstrlen +

3.1.4.29.46 strtod, _strtold, wcstod, _wcstold


Header File

stdlib.h

1131
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Category

Conversion Routines, Math Routines

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

Convert a string to a double or long double value.

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:

[ws] = optional whitespace


[sn] = optional sign (+ or -)
[ddd] = optional digits
[fmt] = optional e or E
[.] = optional decimal point

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

printf("The string is %s the number is %lf\n", input, value);


return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


strtod + + + +
_strtold +
wcstod + + +
_wcstold +

3.1.4.29.47 strtol, wcstol


Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
long strtol(const char *s, char **endptr, int radix);
long wcstol(const wchar_t *s, wchar_t **endptr, int radix);

Description

Converts a string to a long value.

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:

[ws] = optional whitespace


[sn] = optional sign (+ or -)
[0] = optional zero (0)
[x] = optional x or X
[ddd] = optional digits

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

strtol returns the value of the converted string, or 0 on error.

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

POSIX Win32 ANSI C ANSI C++


strtol + + + +
wcstol + + +

3.1.4.29.48 strtoul, wcstoul


Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
unsigned long strtoul(const char *s, char **endptr, int radix);
unsigned long wcstoul(const wchar_t *s, wchar_t **endptr, int radix);

Description

Converts a string to an unsigned long in the given radix.

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

strtoul returns the converted value, an unsigned long, or 0 on error.

Example
#include <stdlib.h>
#include <stdio.h>
int main(void)
{

1134
3.1 C++ Reference RAD Studio C Runtime Library Reference

char *string = "87654321", *endptr;


unsigned long lnumber;
lnumber = strtoul(string, &endptr, 10);
printf("string = %s long = %lu\n",
string, lnumber);
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


strtoul + + + +
wcstoul + + +

3.1.4.29.49 swab
Header File

stdlib.h

Category

Memory and String Manipulation Routines

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

3.1.4.29.50 system, _wsystem


Header File

stdlib.h

Category

Process Control Routines

Prototype
int system(const char *command);
int _wsystem(const wchar_t *command);

Description

Issues an operating system command.

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 a NULL pointer, system returns nonzero if a command processor is available.

If command is not a NULL pointer, system returns 0 if the command processor was successfully started.

If an error occurred, a -1 is returned and errno is set to one of the following:

ENOENT Path or file function not found


ENOEXEC Exec format error
ENOMEM Not enough memory

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

3.1.4.29.51 ultoa, _ultow


Header File

stdlib.h

Category

Conversion Routines, Math Routines

Prototype
char *ultoa(unsigned long value, char *string, int radix);
wchar_t *_ultow(unsigned long value, wchar_t *string, int radix);

Description

Converts an unsigned long to a string.

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

ultoa returns string.

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

POSIX Win32 ANSI C ANSI C++


ultoa +
_ultow +

3.1.4.29.52 wcstombs 3
Header File

stdlib.h

Category

Conversion Routines, Memory and String Manipulation Routines

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

Converts a wchar_t array into a multibyte string.

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!";

printf (" Convert entire wchar string into a multibyte string:\n");


x = wcstombs( pbuf, pwchi,MB_CUR_MAX);
printf ("Character converted: %u\n", x);
printf ("Multibyte string character: %1s\n\n",pbuf);
printf (" Convert when target is NULL\n");
x = wcstombs( pbuf, pwcsEOL, MB_CUR_MAX);
printf ("Character converted: %u\n",x);
printf ("Multibyte string: %1s\n\n",pbuf);

}
Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.29.53 wctomb
Header File

3 stdlib.h

Category

Conversion Routines, Memory and String Manipulation Routines

Prototype
int wctomb(char *s, wchar_t wc);

Description

1138
3.1 C++ Reference RAD Studio C Runtime Library Reference

Converts wchar_t code to a multibyte character.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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

_mbccpy ( see page 1154) Header File


mbstring.h
Category
Memory and String Manipulation Routines
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.
_mbsbtype ( see page 1154) Header File
mbstring.h
Category
Classification Routines
Prototype
int _mbsbtype(const unsigned char *str, size_t nbyte);
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.
Any invalid bytes in str before nbyte are ignored.
Return Value
The value that _mbsbtype returns is... more ( see page 1154)
_mbsnbcmp ( see page 1155) Header File
mbstring.h
Category
Memory and String Manipulation Routines
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.
_mbsnbcmp is case sensitive.
_mbsnbcmp is not affected by locale.
_mbsnbcmp compares bytes based on the current multibyte code page.
Return Value

• _mbsnbcmp returns an integer value based on the result


of comparing s1 (or part of... more ( see page 1155)
_mbsnbcnt, _mbsnccnt, _strncnt, _wcsncnt ( see page 1155) Header File
mbstring.h
Category
Memory and String Manipulation Routines
Prototype
size_t _mbsnbcnt(const unsigned char * str, size_t nmbc);
size_t _mbsnccnt(const unsigned char * str, size_t nbyte);
Description
If _MBCS is defined: 3
_mbsnbcnt is mapped to the portable macro _tcsnbcnt
_mbsnccnt is mapped to the portable macro _tcsnccnt If _UNICODE is defined:
both _mbsnbcnt and _mbsnccnt are mapped to the _wcsncnt macro
If neither _MBCS nor _UNICODE are 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... more ( see page 1155)

1141
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_mbsnbcoll, _mbsnbicoll ( see page 1156) Header File


mbstring.h
Category
Memory and String Manipulation Routines
Prototype
int _mbsnbcoll(const unsigned char *s1, const unsigned char
*s2, maxlen);
int _mbsnbicoll(const unsigned char *s1, const unsigned
char *s2, maxlen);
Description
_mbsnbicoll is the case-insensitive version of _mbsnbcoll.
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... more ( see page 1156)
_mbsnbcpy ( see page 1157) Header File
mbstring.h
Category
Memory and String Manipulation Routines
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
The function returns dest.
_mbsnbicmp ( see page 1157) Header File
mbstring.h
Category
Memory and String Manipulation Routines
Prototype
int _mbsnbicmp(const unsigned char *s1, const unsigned char
s2, size_t maxlen);
Description
_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.
_mbsnbicmp is not case sensitive.
_mbsnbicmp is not affected by locale.
_mbsnbicmp compares bytes based on the current multibyte code page.
Return Value

• _mbsnbicmp returns an integer value based on the result


of comparing s1... more ( see page 1157)
_mbsnbset ( see page 1158) Header File
mbstring.h
Category
Memory and String Manipulation Routines
Prototype
3 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
strset returns str.

1142
3.1 C++ Reference RAD Studio C Runtime Library Reference

_mbsninc, _strninc, _wcsninc ( see page 1158) Header File


mbstring.h
Category
Memory and String Manipulation Routines
Prototype
unsigned char *_mbsninc(const unsigned char *str, size_t
num);
Description
The functions increment the character array str by num number of characters.
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.
_mbsspnp, _strspnp, _wcsspnp ( see page 1158) Header File
mbstring.h
Category
Memory and String Manipulation Routines
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.
_strdec, mbsdec, _wcsdec ( see page 1159) Header File
mbstring.h, tchar.h
Category
Memory and String Manipulation Routines
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.
_strdec is the single-byte version of this function.
_wcsdec is the wide-character version of this function.
Return Value... more ( see page 1159)

1143
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_strerror ( see page 1159) Header File


string.h, stdio.h
Category
Memory and String Manipulation Routines
Prototype
char *_strerror(const char *s);
Description
Builds a customized error message.
_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....
more ( see page 1159)
_strinc, mbsinc, _wcsinc ( see page 1160) Header File
mbstring.h, tchar.h
Category
Memory and String Manipulation Routines
Prototype
unsigned char *_mbsinc(const unsigned char *p);
// From tchar.h
#define _tcsinc _strinc
#define _tcsinc _wcsinc
inline char * strinc(const char * s) { return (char
*)(s+1); }
Description
_mbsinc increments a string pointer by one byte.
_strdec is the single-byte version of this function.
_wcsdec is the wide-character version of this function.
Return Value
Returns a pointer that is forwarded by 1 byte.
_strnextc,_mbsnextc,_wcsnextc ( see page 1161) Header File
tchar.h, mbstring.h
Category
Memory and String Manipulation Routines
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

1144
3.1 C++ Reference RAD Studio C Runtime Library Reference

stpcpy, _wstpcpy, _stpcpy ( see page 1161) Header File


string.h
Category
Memory and String Manipulation Routines
Prototype
char *stpcpy(char *dest, const char *src);
wchar * _wcspcpy(wchar *dest, const wchar *src);
Description
Copies one string into another.
_stpcpy copies the string src to dest, stopping after the terminating null character
of src has been reached.
Return Value
stpcpy returns a pointer to the terminating null character of dest.
If UNICODE is defined, _wcspcpy returns a pointer to the terminating null
character of the wchar_t dest string.
Example
strcat, _mbscat, wcscat ( see page 1162) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
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
Appends one string to another.
strcat appends a copy of src to the end of dest. The length of the resulting string
is strlen(dest) + strlen(src).
Return Value
strcat returns a pointer to the concatenated strings.
Example
strchr, _mbschr, wcschr ( see page 1163) Header File
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
Scans a string for the first occurrence of a given character.
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... more ( see page 1163)
strcmp, _mbscmp, wcscmp ( see page 1164) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
Prototype
int strcmp(const char *s1, const char *s2);
int wcscmp(const wchar_t *s1, const wchar_t *s2); 3
int _mbscmp(const unsigned char *s1, const unsigned char
*s2);
Description
Compares one string to another.
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

1145
C Runtime Library Reference RAD Studio 3.1 C++ Reference

strcmpi ( see page 1165) Header File


string.h, wchar.h
Category
Memory and String Manipulation Routines
Prototype
int strcmpi(const char *s1, const char *s2);
int _wcscmpi(const wchar_t *s1, const wchar_t *s2);
Description
Compares one string to another, without case sensitivity.
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... more ( see page 1165)
strcoll,_stricoll, _mbscoll, _mbsicoll, wcscoll, _wcsicoll ( see page 1166) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines
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
Compares two strings.
strcoll compares the string pointed to by s1 to the string pointed to by s2,
according to the current locale's LC_COLLATE category.
_stricoll performs like strcoll but is not case sensitive.
Note: Note
_stricoll does not compare string according... more ( see page 1166)
strcpy ( see page 1167) Header File
string.h, wchar.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
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 one string into another.
Copies string src to dest, stopping after the terminating null character has been
moved.
Return Value
strcpy returns dest.
Example

1146
3.1 C++ Reference RAD Studio C Runtime Library Reference

strcspn, _mbscspn, wcscspn ( see page 1168) Header File


string.h, wchar.h, mbstring.h
Category
Memory and String Manipulation Routines
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... more ( see page 1168)
strdup, _mbsdup, _wcsdup ( see page 1169) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines
Prototype
char *strdup(const char *s);
wchar_t *_wcsdup(const wchar_t *s);
unsigned char *_mbsdup(const wchar_t *s);
Description
Copies a string into a newly created location.
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
strerror ( see page 1170) Header File
string.h
Category
Memory and String Manipulation Routines
Prototype
char *strerror(int errnum);
Description
Returns a pointer to an error message string.
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
stricmp, _mbsicmp, _wcsicmp ( see page 1170) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines
Prototype
int stricmp(const char *s1, const char *s2);
int _wcsicmp(const wchar_t *s1, const wchar_t *s2); 3
int _mbsicmp(const unsigned char *s1, const unsigned char
*s2);
Description
Compares one string to another, without case sensitivity.
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... more ( see page 1170)

1147
C Runtime Library Reference RAD Studio 3.1 C++ Reference

strlwr, _mbslwr, _wcslwr ( see page 1171) Header File


string.h, mbstring.h
Category
Conversion Routines, Memory and String Manipulation Routines
Prototype
char *strlwr(char *s);
wchar_t *_wcslwr(wchar_t *s);
unsigned char *_mbslwr(unsigned char *s);
Description
Converts uppercase letters in a string to lowercase.
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
strlwr returns a pointer to the string s.
Example
strncat ( see page 1172) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
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
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... more ( see page
1172)
strncmp, _mbsncmp, wcsncmp ( see page 1173) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
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
Compares a portion of one string to a portion of another.
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.... more ( see page 1173)
strncmpi, wcsncmpi ( see page 1174) Header File
string.h
Category
Memory and String Manipulation Routines
3 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
Compares a portion of one string to a portion of another, without case sensitivity.
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... more ( see page 1174)

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

strnset, _mbsnset, _wcsnset ( see page 1177) Header File


string.h
Category
Memory and String Manipulation Routines, Inline Routines
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
Sets a specified number of characters in a string to a given character.
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
Each of these functions return s.
Example
strpbrk, _mbspbrk, wcspbrk ( see page 1178) Header File
string.h, mbstring.h
Category
C++ Prototyped Routines, Memory and String Manipulation Routines
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);
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... more ( see page 1178)
strrchr, _mbsrchr, wcsrchr ( see page 1179) Header File
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
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
Scans a string for the last occurrence of a given character.
strrchr scans a string in the reverse direction, looking for a specific character.
strrchr finds the last occurrence of the character c in the string s. The
null-terminator... more ( see page 1179)

1150
3.1 C++ Reference RAD Studio C Runtime Library Reference

strrev, _mbsrev, _wcsrev ( see page 1180) Header File


string.h, mbstring.h
Category
Memory and String Manipulation Routines
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 string\0 to gnirts\0.)
Return Value
strrev returns a pointer to the reversed string.
Example
strset, _mbsset, _wcsset ( see page 1181) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines, Inline Routines
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
Sets all characters in a string to a given character.
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
strspn, _mbsspn, wcsspn ( see page 1182) Header File
string.h, mbstring.h
Category
Memory and String Manipulation Routines
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
strstr, _mbsstr, wcsstr ( see page 1182) Header File
string.h
Category
C++ Prototyped Routines, Memory and String Manipulation Routines
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
3
wchar_t * wcsstr(const wchar_t *s1, const wchar_t *s2);
unsigned char * _mbsstr(const unsigned char *s1, const
unsigned char *s2);
Description
Scans a string for the occurrence of a given substring.
strstr scans s1 for the first occurrence of the substring s2.
Return Value
strstr returns a pointer to the element in s1, where s2 begins (points... more (
see page 1182)

1151
C Runtime Library Reference RAD Studio 3.1 C++ Reference

strtok, _mbstok, wcstok ( see page 1183) Header File


string.h, mbstring.h
Category
Memory and String Manipulation Routines
Prototype
char *strtok(char *s1, const char *s2);
wchar_t *wcstok(wchar_t *s1, const wchar_t *s2);
unsigned char *_mbstok(unsigned char *s1, const unsigned
char *s2);
Description
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... more ( see page 1183)
strupr, _mbsupr, _wcsupr ( see page 1184) Header File
string.h, mbstring.h
Category
Conversion Routines, Memory and String Manipulation Routines
Prototype
char *strupr(char *s);
wchar_t *_wcsupr(wchar_t *s);
unsigned char *_mbsupr(unsigned char *s);
Description
Converts lowercase letters in a string to uppercase.
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
strxfrm, wcsxfrm ( see page 1185) Header File
string.h
Category
Memory and String Manipulation Routines
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
Transforms a portion of a string to a specified collation.
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.
No more than n characters, including the terminating null character, are copied to
target.
strxfrm transforms a character string... more ( see page 1185)

3.1.4.30.1 _ismbblead, _ismbbtrail


Header File
3
mbstring.h

Category

Classification Routines

Prototype
int _ismbblead(unsigned int c);

1152
3.1 C++ Reference RAD Studio C Runtime Library Reference

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.

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.

3.1.4.30.3 _ismbslead, _ismbstrail


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
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

Memory and String Manipulation Routines

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.

Any invalid bytes in str before nbyte are ignored.

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

Memory and String Manipulation Routines

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.

_mbsnbcmp is case sensitive.

_mbsnbcmp is not affected by locale.

_mbsnbcmp compares bytes based on the current multibyte code page.

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

3.1.4.30.8 _mbsnbcnt, _mbsnccnt, _strncnt, _wcsncnt


Header File

mbstring.h
3
Category

Memory and String Manipulation Routines

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:

_mbsnbcnt is mapped to the portable macro _tcsnbcnt

_mbsnccnt is mapped to the portable macro _tcsnccnt If _UNICODE is defined:

both _mbsnbcnt and _mbsnccnt are mapped to the _wcsncnt macro

If neither _MBCS nor _UNICODE are 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

_mbsnbcnt returns the number of bytes found.

_mbsnccnt returns the number of characters found.

If nmbc or nbyte are less than zero, the functions return 0.

3.1.4.30.9 _mbsnbcoll, _mbsnbicoll


Header File

mbstring.h

Category

Memory and String Manipulation Routines

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

_mbsnbicoll is the case-insensitive version of _mbsnbcoll.

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

leadbyte, it is not compared.

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

Memory and String Manipulation Routines

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

The function returns dest.

3.1.4.30.11 _mbsnbicmp
Header File

mbstring.h

Category

Memory and String Manipulation Routines

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.

_mbsnbicmp is not case sensitive.

_mbsnbicmp is not affected by locale.

_mbsnbicmp compares bytes based on the current multibyte code page.

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

Memory and String Manipulation Routines

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

strset returns str.

3.1.4.30.13 _mbsninc, _strninc, _wcsninc


Header File

mbstring.h

Category

Memory and String Manipulation Routines

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.

3.1.4.30.14 _mbsspnp, _strspnp, _wcsspnp


Header File

1158
3.1 C++ Reference RAD Studio C Runtime Library Reference

mbstring.h

Category

Memory and String Manipulation Routines

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.

3.1.4.30.15 _strdec, mbsdec, _wcsdec


Header File

mbstring.h, tchar.h

Category

Memory and String Manipulation Routines

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.

_strdec is the single-byte version of this function.

_wcsdec is the wide-character version of this function.

Return Value

Returns a pointer back to 1 byte, or null pointer if there is no character before p.


3

3.1.4.30.16 _strerror
Header File

string.h, stdio.h

Category

1159
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Memory and String Manipulation Routines

Prototype
char *_strerror(const char *s);

Description

Builds a customized error message.

_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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.30.17 _strinc, mbsinc, _wcsinc


Header File

mbstring.h, tchar.h

Category

Memory and String Manipulation Routines

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

_mbsinc increments a string pointer by one byte.

1160
3.1 C++ Reference RAD Studio C Runtime Library Reference

_strdec is the single-byte version of this function.

_wcsdec is the wide-character version of this function.

Return Value

Returns a pointer that is forwarded by 1 byte.

3.1.4.30.18 _strnextc,_mbsnextc,_wcsnextc
Header File

tchar.h, mbstring.h

Category

Memory and String Manipulation Routines

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
***/

3.1.4.30.19 stpcpy, _wstpcpy, _stpcpy


Header File 3
string.h

Category

Memory and String Manipulation Routines

Prototype
char *stpcpy(char *dest, const char *src);

1161
C Runtime Library Reference RAD Studio 3.1 C++ Reference

wchar * _wcspcpy(wchar *dest, const wchar *src);

Description

Copies one string into another.

_stpcpy copies the string src to dest, stopping after the terminating null character of src has been reached.

Return Value

stpcpy returns a pointer to the terminating null character of dest.

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

POSIX Win32 ANSI C ANSI C++


_stpcpy +
_wcspcpy +

3.1.4.30.20 strcat, _mbscat, wcscat


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines, Inline Routines

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

Appends one string to another.


3
strcat appends a copy of src to the end of dest. The length of the resulting string is strlen(dest) + strlen(src).

Return Value

strcat returns a pointer to the concatenated strings.

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

POSIX Win32 ANSI C ANSI C++


strcat + + + +
_mbscat +
wcscat + + +

3.1.4.30.21 strchr, _mbschr, wcschr


Header File

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

Scans a string for the first occurrence of a given character.

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)

returns a pointer to the terminating null character of the string strs.

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

char *ptr, c = 'r';


strcpy(string, "This is a string");
ptr = strchr(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

POSIX Win32 ANSI C ANSI C++


strchr + + + +
_mbschr +
wcschr + + +

3.1.4.30.22 strcmp, _mbscmp, wcscmp


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines, Inline Routines

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

Compares one string to another.

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

less than s2 <0


the same as s2 == 0
greater than s2 >0

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

ptr = strcmp(buf2, buf3);


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

POSIX Win32 ANSI C ANSI C++


strcmp + + + +
_mbscmp +
wcscmp + + +

3.1.4.30.23 strcmpi
Header File

string.h, wchar.h

Category

Memory and String Manipulation Routines

Prototype
int strcmpi(const char *s1, const char *s2);
int _wcscmpi(const wchar_t *s1, const wchar_t *s2);

Description

Compares one string to another, without case sensitivity.

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

less than s2 <0


the same as s2 == 0
greater than s2 >0

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

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

POSIX Win32 ANSI C ANSI C++


strcmpi +
_wcscmpi +

3.1.4.30.24 strcoll,_stricoll, _mbscoll, _mbsicoll, wcscoll, _wcsicoll


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines

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

Compares two strings.

strcoll compares the string pointed to by s1 to the string pointed to by s2, according to the current locale's LC_COLLATE
category.

_stricoll performs like strcoll but is not case sensitive.

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

less than s2 <0


the same as s2 == 0
greater than s2 >0

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

POSIX Win32 ANSI C ANSI C++


strcoll + + + +
_stricoll +
_mbscoll +
_mbsicoll +
wcscoll + + +
_wcsicoll +

3.1.4.30.25 strcpy
Header File

string.h, wchar.h, mbstring.h

Category

Memory and String Manipulation Routines, Inline Routines

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 one string into another.

Copies string src to dest, stopping after the terminating null character has been moved.
3
Return Value

strcpy returns dest.

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

POSIX Win32 ANSI C ANSI C++


strcpy + + + +
_mbscpy +
wcscpy + + +

3.1.4.30.26 strcspn, _mbscspn, wcscspn


Header File

string.h, wchar.h, mbstring.h

Category

Memory and String Manipulation Routines

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

POSIX Win32 ANSI C ANSI C++


strcspn + + + +
_mbscspn +
wcscspn + + +

3.1.4.30.27 strdup, _mbsdup, _wcsdup


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines

Prototype
char *strdup(const char *s);
wchar_t *_wcsdup(const wchar_t *s);
unsigned char *_mbsdup(const wchar_t *s);

Description

Copies a string into a newly created location.

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

POSIX Win32 ANSI C ANSI C++


strdup + 3
_mbsdup +
_wcsdup +

1169
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.30.28 strerror
Header File

string.h

Category

Memory and String Manipulation Routines

Prototype
char *strerror(int errnum);

Description

Returns a pointer to an error message string.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.30.29 stricmp, _mbsicmp, _wcsicmp


Header File

string.h, mbstring.h

Category

3 Memory and String Manipulation Routines

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

Compares one string to another, without case sensitivity.

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

less than s2 <0


the same as s2 == 0
greater than s2 >0

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

POSIX Win32 ANSI C ANSI C++


stricmp + + +
_mbsicmp +
_wcsicmp +

3.1.4.30.30 strlwr, _mbslwr, _wcslwr


Header File

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

Converts uppercase letters in a string to lowercase.

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

strlwr returns a pointer to the string s.

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

POSIX Win32 ANSI C ANSI C++


strlwr +
_mbslwr +
_wcslwr +

3.1.4.30.31 strncat
Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines, Inline Routines

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

strncat returns dest.

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

POSIX Win32 ANSI C ANSI C++


strncat + + + +
_mbsncat +
_mbsnbcat +
_wcsncat +

3.1.4.30.32 strncmp, _mbsncmp, wcsncmp


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines, Inline Routines

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

Compares a portion of one string to a portion of another.

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

POSIX Win32 ANSI C ANSI C++


strncmp + + + +
_mbsncmp +
_mbccmp +
wcsncmp + + +

3.1.4.30.33 strncmpi, wcsncmpi


Header File

string.h

Category

Memory and String Manipulation Routines

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

Compares a portion of one string to a portion of another, without case sensitivity.

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

less than s2 <0


the same as s2 == 0
greater than s2 >0

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

POSIX Win32 ANSI C ANSI C++


strncmpi +
wcsncmpi +

3.1.4.30.34 strncoll, strnicoll, _mbsncoll, _mbsnicoll, _wcsncoll, _wcsnicoll


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); 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.

_strnicoll performs like _strncoll but is not case sensitive.

Return Value

1175
C Runtime Library Reference RAD Studio 3.1 C++ Reference

less than s2 <0


the same as s2 == 0
greater than s2 >0

3.1.4.30.35 strncpy, _mbsncpy, wcsncpy


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
#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

POSIX Win32 ANSI C ANSI C++


strncpy + + + +
3 _mbsncpy +
wcsncpy + + +

3.1.4.30.36 strnicmp, _mbsnicmp, _wcsnicmp


Header File

1176
3.1 C++ Reference RAD Studio C Runtime Library Reference

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 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

less than s2 <0


the same as s2 == 0
greater than s2 >0

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

POSIX Win32 ANSI C ANSI C++


strnicmp +
_mbsnicmp +
3
_wcsnicmp +

3.1.4.30.37 strnset, _mbsnset, _wcsnset


Header File

string.h

1177
C Runtime Library Reference RAD Studio 3.1 C++ Reference

Category

Memory and String Manipulation Routines, Inline Routines

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

Sets a specified number of characters in a string to a given character.

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

Each of these functions return s.

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

POSIX Win32 ANSI C ANSI C++


strnset +
_mbsnset +
_wcsnset +

3.1.4.30.38 strpbrk, _mbspbrk, wcspbrk


Header File

string.h, mbstring.h

Category

3 C++ Prototyped Routines, Memory and String Manipulation Routines

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

POSIX Win32 ANSI C ANSI C++


strpbrk + + + +
_mbspbrk +
wcspbrk + + +

3.1.4.30.39 strrchr, _mbsrchr, wcsrchr


Header File

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

Scans a string for the last occurrence of a given character.

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

in the string s. The null-terminator is considered to be part of the string.

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

POSIX Win32 ANSI C ANSI C++


strrchr + + + +
_mbsrchr +
wcsrchr + + +

3.1.4.30.40 strrev, _mbsrev, _wcsrev


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines

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

strrev returns a pointer to the reversed string.

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

POSIX Win32 ANSI C ANSI C++


strrev +
_mbsrev +
_wcsrev +

3.1.4.30.41 strset, _mbsset, _wcsset


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines, Inline Routines

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

Sets all characters in a string to a given character.

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

POSIX Win32 ANSI C ANSI C++


strset +

1181
C Runtime Library Reference RAD Studio 3.1 C++ Reference

_mbsset +
_wcsset +

3.1.4.30.42 strspn, _mbsspn, wcsspn


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines

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

POSIX Win32 ANSI C ANSI C++


strspn + + + +
_mbsspn +
3 wcsspn + + +

3.1.4.30.43 strstr, _mbsstr, wcsstr


Header File

string.h

1182
3.1 C++ Reference RAD Studio C Runtime Library Reference

Category

C++ Prototyped Routines, Memory and String Manipulation Routines

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

Scans a string for the occurrence of a given substring.

strstr scans s1 for the first occurrence of the substring s2.

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

POSIX Win32 ANSI C ANSI C++


strstr + + + +
_mbsstr +
wcsstr + + +

3.1.4.30.44 strtok, _mbstok, wcstok


Header File

string.h, mbstring.h

Category

Memory and String Manipulation Routines 3


Prototype
char *strtok(char *s1, const char *s2);
wchar_t *wcstok(wchar_t *s1, const wchar_t *s2);
unsigned char *_mbstok(unsigned char *s1, const unsigned char *s2);

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.

The separator string, s2, can be different from call to call.

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

POSIX Win32 ANSI C ANSI C++


strtok + + + +
_mbstok +
wcstok + + +

3.1.4.30.45 strupr, _mbsupr, _wcsupr


Header File

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

Converts lowercase letters in a string to uppercase.

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

POSIX Win32 ANSI C ANSI C++


strupr +
_mbsupr +
_wcsupr +

3.1.4.30.46 strxfrm, wcsxfrm


Header File

string.h

Category

Memory and String Manipulation Routines

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

Transforms a portion of a string to a specified collation.

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

POSIX Win32 ANSI C ANSI C++


strxfrm + + + +
wcsxfrm + + +

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

_stati64, _tstati64, stati64, _wstati64 ( see page 1188) Header File


sys\stat.h, tchar.h
Category
Directory Control Routines
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.
The statistics fields are set thus:
st_devset to -1 if S_IFCHR, else set to drive holding the file.
st_ino0
st_modeUnix-style bit-set for file access rights
st_nlink1
st_uid0
st_gid0
st_rdevsame as st_dev
st_sizefile size (0 if S_IFDIR or S_IFCHR)
st_atimetime file last changed (seconds since 1970)
st_mtimesame as st_atime... more ( see page 1188)
fstat, stat, _wstat ( see page 1189) Header File
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
Gets open file information.
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:

3.1.4.31.1 S_Ixxxx #defines


Header File

sys\stat.h

Description

Definitions used for file status and directory functions.

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

S_IREAD Owner can read


S_IWRITE Owner can write
S_IEXEC Owner can execute

3.1.4.31.2 _stati64, _tstati64, stati64, _wstati64


Header File

sys\stat.h, tchar.h

Category

Directory Control Routines

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.

The statistics fields are set thus:

st_devset to -1 if S_IFCHR, else set to drive holding the file.

st_ino0

st_modeUnix-style bit-set for file access rights

st_nlink1

st_uid0

st_gid0

st_rdevsame as st_dev

st_sizefile size (0 if S_IFDIR or S_IFCHR)

st_atimetime file last changed (seconds since 1970)

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.31.3 fstat, stat, _wstat


Header File

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

Gets open file information.

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:

st_mode Bit mask giving information about the file's mode


st_dev Drive number of disk containing the file or file handle if the file is on a device
st_rdev Same as st_dev
st_nlink Set to the integer constant 1
st_size Size of the file in bytes
st_atime Most recent access (Windows) or last time modified (DOS)
st_mtime Same as st_atime
st_ctime Same as st_atime

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:

One of the following bits will be set:

S_IFCHR If handle refers to a device.


3
S_IFREG If an ordinary file is referred to by handle.

One or both of the following bits will be set:

S_IWRITE If user has permission to write to file.


S_IREAD If user has permission to read to file.

The HPFS and NTFS file-management systems make the following distinctions:

1189
C Runtime Library Reference RAD Studio 3.1 C++ Reference

st_atime Most recent access


st_mtime Most recent modify
st_ctime Creation time

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

EBADF Bad file handle

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 ;
};

• 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....
more ( see page 1191)

3.1.4.32.1 ftime
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 ; 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

POSIX Win32 ANSI C ANSI C++


+

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

Defines the value used by the time functions declared in time.h.

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

asctime ( see page 1199) Header File


time.h
Category
Time and Date Routines
Prototype
char *asctime(const struct tm *tblock);
wchar_t *_wasctime(const struct tm *tblock);
Description
asctime converts date and time to ASCII.
_wasctime converts date and time to a wchar_t string.
asctime and _wasctime convert a time stored as a structure to a 26 (wide)
character string in the following form:
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:
tm parameterValid value rangeOutput
tm.mon (month)0-110=Jan, 1=Feb, and so on
tm.day (day-of-the-week)0-60=Sun, 1=Mon, and so on
Return Value
asctime and _wasctime return... more ( see page 1199)
clock ( see page 1200) Header File
time.h
Category
Time and Date Routines
Prototype
clock_t clock(void);
Description
Determines processor time.
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.
On error (if the processor time is not available or its value cannot be
represented), clock returns -1.
Example
clock_t ( see page 1201) Header File
time.h
Syntax
typedef long clock_t;
Description
Defines the data type returned by the clock function.
Portability
ctime, _wctime ( see page 1201) Header File
time.h
Category
Time and Date Routines
Prototype
char *ctime(const time_t *time);
wchar_t *_wctime(const time_t *time);
Description
Converts date and time to a string.
ctime converts a time value pointed to by time (the value returned by the function
3 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
All the fields have constant width.
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... more ( see page 1201)

1194
3.1 C++ Reference RAD Studio C Runtime Library Reference

_daylight ( see page 1202) 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 is not set, the
value of _daylight is obtained from the operating system.
difftime ( see page 1202) Header File
time.h
Category
Time and Date Routines
Prototype
double difftime(time_t time2, time_t time1);
Description
Computes the difference between two times.
difftime calculates the elapsed time in seconds, from time1 to time2.
Return Value
difftime returns the result of its calculation as a double.
Example
gmtime ( see page 1203) Header File
time.h
Category
Time and Date Routines
Prototype
struct tm *gmtime(const time_t *timer);
Description
Converts date and time to Greenwich mean time (GMT).
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 conversion should... more ( see page 1203)
localtime ( see page 1204) Header File
time.h
Category
Time and Date Routines
Prototype
struct tm *localtime(const time_t *timer);
Description
Converts date and time to a structure.
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... more ( see page 1204)

1195
C Runtime Library Reference RAD Studio 3.1 C++ Reference

mktime ( see page 1206) Header File


time.h
Category
Time and Date Routines
Prototype
time_t mktime(struct tm *t);
Description
Converts time to calendar format.
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... more ( see page 1206)
stime ( see page 1207) Header File
time.h
Category
Time and Date Routines
Prototype
int stime(time_t *tp);
Description
Sets system date and time.
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
stime returns a value of 0.
Example
strftime, wcsftime ( see page 1207) Header File
time.h
Category
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
Formats time for output.
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.
The time is formatted according to the current locale's LC_TIME category.
Return Value
On success, strftime returns the number of characters placed into s.
On... more ( see page 1207)
time ( see page 1208) Header File
time.h
Category
Time and Date Routines
Prototype
time_t time(time_t *timer);
Description
Gets time of day.
time gives the current time, in seconds, elapsed since 00:00:00 GMT, January 1,
3 1970, and stores that value in the location pointed to by timer, provided that timer
is not a NULL pointer.
Return Value
time returns the elapsed time in seconds.
Example

1196
3.1 C++ Reference RAD Studio C Runtime Library Reference

_timezone ( see page 1209) 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.
On Win32, the value of _timezone is obtained from the operating system.
tm ( see page 1209) 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) */
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) */
};
Description
A structure defining the time, broken down into increments.
tm is used by the functions asctime, gmtime, localtime, mktime, and strftime.
Example... more ( see page 1209)
_tzname,_wtzname ( see page 1210) 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.
On Win32, the value of _tzname is obtained from the operating system.
_tzset, _wtzset ( see page 1210) Header File
time.h
Category
Time and Date Routines
Prototype
void _tzset(void)
void _wtzset(void)
Description
Sets value of global variables _daylight, _timezone, and _tzname.
_tzset is available on XENIX systems.
_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] 3
where zzz is a three-character string representing the name of the current time
zone. All... more ( see page 1210)

3.1.4.34.1 _strdate, _wstrdate


Header File

time.h

1197
C Runtime Library Reference RAD Studio 3.1 C++ Reference

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
#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

POSIX Win32 ANSI C ANSI C++


strdate +
_wstrdate +

3.1.4.34.2 _strtime, _wstrtime


Header File

time.h

Category

Time and Date Routines

Prototype
3
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.

1198
3.1 C++ Reference RAD Studio C Runtime Library Reference

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
#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

POSIX Win32 ANSI C ANSI C++


_strtime +
_wstrtime +

3.1.4.34.3 asctime
Header File

time.h

Category

Time and Date Routines

Prototype
char *asctime(const struct tm *tblock);
wchar_t *_wasctime(const struct tm *tblock);

Description

asctime converts date and time to ASCII.

_wasctime converts date and time to a wchar_t string.

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:

tm parameterValid value rangeOutput

tm.mon (month)0-110=Jan, 1=Feb, and so on

tm.day (day-of-the-week)0-60=Sun, 1=Mon, and so on

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

POSIX Win32 ANSI C ANSI C++


asctime + + + +
_wasctime +

3.1.4.34.4 clock
Header File

time.h

Category

Time and Date Routines

Prototype
clock_t clock(void);
3
Description

Determines processor time.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.34.5 clock_t
Header File

time.h

Syntax
typedef long clock_t;

Description

Defines the data type returned by the clock function.

Portability

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.34.6 ctime, _wctime


Header File

time.h

Category

Time and Date Routines


3
Prototype
char *ctime(const time_t *time);
wchar_t *_wctime(const time_t *time);

Description

Converts date and time to a string.

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

All the fields have constant width.

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

POSIX Win32 ANSI C ANSI C++


ctime + + + +
_wctime +

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

Time and Date Routines

Prototype
double difftime(time_t time2, time_t time1);

Description

Computes the difference between two times.

difftime calculates the elapsed time in seconds, from time1 to time2.

Return Value

difftime returns the result of its calculation as a double.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.34.9 gmtime
Header File

time.h

Category

Time and Date Routines

Prototype
struct tm *gmtime(const time_t *timer);
3
Description

Converts date and time to Greenwich mean time (GMT).

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

conversion should be applied.

This is the tm structure declaration from the time.h header file:


struct tm {
int tm_sec; /* Seconds */
int tm_min; /* Minutes */
int tm_hour; /* Hour (0 - 23) */
int tm_mday; /* Day of month (1 - 31) */
int tm_mon; /* Month (0 - 11) */
int tm_year; /* Year (calendar year minus 1900) */
int tm_wday; /* Weekday (0 - 6; Sunday is 0) */
int tm_yday; /* Day of year (0 -365) */
int tm_isdst; /* Nonzero if daylight saving time is in effect. */
};

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

POSIX Win32 ANSI C ANSI C++

3 + + + +

3.1.4.34.10 localtime
Header File

time.h

Category

1204
3.1 C++ Reference RAD Studio C Runtime Library Reference

Time and Date Routines

Prototype
struct tm *localtime(const time_t *timer);

Description

Converts date and time to a structure.

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.

This is the tm structure declaration from the time.h header file:


struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};

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

POSIX Win32 ANSI C ANSI C++


+ + + +

3.1.4.34.11 mktime
Header File

time.h

Category

Time and Date Routines

Prototype

time_t mktime(struct tm *t);

Description

Converts time to calendar format.

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 success, mktime returns calendar time as described above.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

1206
3.1 C++ Reference RAD Studio C Runtime Library Reference

3.1.4.34.12 stime
Header File

time.h

Category

Time and Date Routines

Prototype
int stime(time_t *tp);

Description

Sets system date and time.

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

stime returns a value of 0.

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

POSIX Win32 ANSI C ANSI C++


+

3.1.4.34.13 strftime, wcsftime


Header File

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

Formats time for output.

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.

The time is formatted according to the current locale's LC_TIME category.

Return Value

On success, strftime returns the number of characters placed into s.

On error (if the number of characters required is greater than maxsize), strftime returns 0.

More about strftime

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

POSIX Win32 ANSI C ANSI C++


strftime + + + +
wcsftime + + +

3.1.4.34.14 time
Header File

time.h

Category

Time and Date Routines

Prototype
3 time_t time(time_t *timer);

Description

Gets time of day.

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

time returns the elapsed time in seconds.

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

POSIX Win32 ANSI C ANSI C++


+ + + +

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.

On Win32, the value of _timezone is obtained from the operating system.

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

A structure defining the time, broken down into increments.

tm is used by the functions asctime, gmtime, localtime, mktime, and strftime.

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.

On Win32, the value of _tzname is obtained from the operating system.

3.1.4.34.18 _tzset, _wtzset


Header File

time.h

Category

Time and Date Routines

Prototype
void _tzset(void)
void _wtzset(void)

Description

Sets value of global variables _daylight, _timezone, and _tzname.

_tzset is available on XENIX systems.

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

POSIX Win32 ANSI C ANSI C++


_tzset + +
_wtzset +

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

bad_typeid class ( see page 1212) Header File


typeinfo.h
Description
When the operand of typeid is a dereferenced null pointer, the typeid operator
can throw bad_typeid.
type_info class ( see page 1212) Header File
typeinfo.h
Description
Provides information about a type.
Constructor
Only a private constructor is provided. You cannot create type_info objects. By
declaring your objects to be _ _rtti types, or by 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.
Public Member Functions
Operators

3.1.4.35.1 bad_cast class


Header File

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.

3.1.4.35.2 bad_typeid class


Header File

typeinfo.h

Description

When the operand of typeid is a dereferenced null pointer, the typeid operator can throw bad_typeid.

3.1.4.35.3 type_info class


Header File

typeinfo.h

Description

Provides information about a type.

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.

Public Member Functions

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)

3.1.4.36.1 _utime, _wutime


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 */
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

the functions perform identically.

Return Value

On success, _utime returns 0.

On error, it returns -1, and sets the global variable errno to one of the following values:

EACCES Permission denied


EMFILE Too many open files
ENOENT Path or file name not found

Example
/* Copy timestamp from one file to another */
#include <sys\stat.h>
#include <utime.h>
#include <stdio.h>

int main( int argc, char *argv[] )


{
struct stat src_stat;
struct utimbuf times;
if(argc != 3) {
printf( "Usage: copytime <source file> <dest file>\n" );
return 1;
}

if (stat(argv[1],&src_stat) != 0) {
perror("Unable to get status of source file");
return 1;
}

times.modtime = times.actime = src_stat.st_mtime;


if (utime(argv[2],&times) != 0) {
perror("Unable to set time of destination file");
return 1;
}
return 0;
}
Portability

POSIX Win32 ANSI C ANSI C++


_utime + +
_wutime +

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

HIBITx #defines ( see page 1215) Header File


values.h
Description
Bit mask for the high (sign) bit of standard integer types.
MAXxxxx #defines (integer data types) ( see page 1215) Header File
values.h
Description
Maximum values for integer data types
Float and Double Limits ( see page 1216) Header File
values.h
Description
UNIX System V compatible:

3.1.4.37.1 BITSPERBYTE #define


Header File

values.h

Description

Number of bits in a byte.

3.1.4.37.2 HIBITx #defines


Header File

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

3.1.4.37.3 MAXxxxx #defines (integer data types)


Header File

values.h

Description

Maximum values for integer data types


3
Name Meaning
MAXSHORT Largest short
MAXINT Largest int
MAXLONG Largest long

1215
C Runtime Library Reference RAD Studio 3.1 C++ Reference

3.1.4.37.4 Float and Double Limits


Header File

values.h

Description

UNIX System V compatible:

_LENBASE Base to which exponent applies

Limits for double float values

_DEXPLEN Number of bits in exponent


DMAXEXP Maximum exponent allowed
DMAXPOWTWO Largest power of two allowed
DMINEXP Minimum exponent allowed
DSIGNIF Number of significant bits
MAXDOUBLE Largest magnitude double value
MINDOUBLE Smallest magnitude double value

Limits for float values

_FEXPLEN Number of bits in exponent


FMAXEXP Maximum exponent allowed
FMAXPOWTWO Largest power of two allowed
FMINEXP Minimum exponent allowed
FSIGNIF Number of significant bits
MAXFLOAT Largest magnitude float value
MINFLOAT Smallest magnitude float value

1216
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

3.2 Win32 Developer's Guide


This section contains the Win32 Developer's Guide topics for the Delphi Win32 personality in RAD Studio.

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.

3.2.1 Component Writer's Guide


The Component Writer's Guide covers all the information relating to creating VCL components in the Delphi personality.

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

3.2.1.1 Creating a graphic component


Topics
Name Description
Adding Graphic Capabilities ( see page 1219) 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:

1. Determining what to draw. ( see page 1223)


2. Drawing the component image. ( see page 1224)
In addition, for the shape control example, you will add some
properties that enable application developers to customize
the appearance of the shape at design time.
Creating a Graphic Component ( see page 1220) A graphic control is a simple kind of component. Because a purely graphic
control never receives focus, it does not have or need its own window handle.
Users can still manipulate the control with the mouse, but there is no keyboard
interface.
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... more ( see page
1220)
Creating and Registering the Graphic Component ( see page 1220) You create every component in 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)
Declaring the Access Properties ( see page 1221) You can provide access to the owned objects of a component by declaring
properties of the type of the objects. That gives developers a way to access the
objects at design time or runtime. Usually, the read part of the property just
references the class field, but the write part calls a method that enables the
component to react to changes in the owned object.
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.
Declaring the Class Fields ( see page 1222) Each class a component owns must have a class field declared for it in the
component. The class field ensures that the component always has a pointer to
the owned object so that it can destroy the class before destroying itself. In
general, a component initializes owned objects in its constructor and destroys
them in its destructor.
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.
Add fields for a pen and brush to the shape control:
Declaring the Property ( see page 1222) When you declare a property, you usually need to declare a private field to store
the data for the property, then specify methods for reading and writing the
property value. Often, you don't need to use a method to read the value, but can
just point to the stored data instead.
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.
Add the following declarations to TSampleShape:
Declaring the Property Type ( see page 1223) When you declare a property of a user-defined type, you must declare the type
first, before the class that includes the property. The most common sort of
user-defined type for properties is enumerated.
3 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.
Determining What to Draw ( see page 1223) A graphic control can change its appearance to reflect a dynamic condition,
including user input. A graphic control that always looks the same should
probably not be a component at all. If you want a static image, you can import the
image instead of using a control.
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. Similarly, the shape control has a property that determines what kind
of shape it... more ( see page 1223)

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:

• Use the pen and brush selected by the user.


• Use the selected shape.
• Adjust coordinates so that squares and circles use the
same width and height.
Initializing Owned Classes ( see page 1225) If you add classes to your component, the component's constructor must initialize
them so that the user can interact with the objects at runtime. Similarly, the
component's destructor must also destroy the owned objects before destroying
the component itself.
Overriding the Constructor and Destructor ( see page 1226) To change default property values and initialize owned classes for your
component, you must override the inherited constructor and destructor. In both
cases, remember always to call the inherited method in your new constructor or
destructor.
Publishing Inherited Properties (Graphic) ( see page 1227) Once you derive a component type, you can decide which of the properties and
events declared in the protected parts of the ancestor class you want to surface
in the new component. TGraphicControl already publishes all the properties that
enable the component to function as a control, so all you need to publish is the
ability to respond to mouse events and handle drag-and-drop.
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... more ( see page 1227)
Publishing the Pen and Brush ( see page 1228) By default, a canvas has a thin black pen and a solid white brush. To let
developers change the pen and brush, you must provide classes for them to
manipulate at design time, then copy the classes into the canvas during painting.
Classes such as an auxiliary pen or brush are called owned classes because the
component owns them and is responsible for creating and destroying them.
Managing owned classes requires:

1. Declaring the class fields. ( see page 1222)


2. Declaring the access properties. ( see page 1221)
3. Initializing owned classes. ( see page 1225)
4. Setting owned classes' properties. ( see page 1229)
Refining the Shape Drawing ( see page 1228) The standard shape control does one more thing that your sample shape control
does not yet do: it handles squares and circles as well as rectangles and ellipses.
To do that, you need to write code that finds the shortest side and centers the
image.
Here is a refined Paint method that adjusts for squares and ellipses:
Setting Owned Classes' Properties ( see page 1229) As the final step in handling the pen and brush classes, you need to make sure
that changes in the pen and brush cause the shape control to repaint itself. Both
pen and brush classes have OnChange events, so you can create a method in
the shape control and point both OnChange events to it.
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:
Writing the Implementation Method ( see page 1230) When the read or write part of a property definition uses a method instead of
directly accessing the stored property data, you need to implement the method.
Add the implementation of the SetShape method to the implementation part of
the unit:

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:

1. Determining what to draw. ( see page 1223)


2. Drawing the component image. ( see page 1224)
In addition, for the shape control example, you will add some properties that enable application developers to customize the

1219
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

appearance of the shape at design time.

3.2.1.1.2 Creating a Graphic Component


A graphic control is a simple kind of component. Because a purely graphic control never receives focus, it does not have or need
its own window handle. Users can still manipulate the control with the mouse, but there is no keyboard interface.

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:

• Creating and registering the component ( see page 1363).


• Publishing inherited properties ( see page 1227).
• Adding graphic capabilities ( see page 1219).

3.2.1.1.3 Creating and Registering the Graphic Component


You create every component in 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:
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

3.2.1.1.4 Declaring the Access Properties


You can provide access to the owned objects of a component by declaring properties of the type of the objects. That gives
developers a way to access the objects at design time or runtime. Usually, the read part of the property just references the class
field, but the write part calls a method that enables the component to react to changes in the owned object.

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

__property TBrush* Brush = {read=FBrush, write=SetBrush, nodefault};


__property TPen* Pen = {read=FPen, write=SetPen, nodefault};
};
Then, write the SetBrush and SetPen methods in the implementation part of the unit:
procedure TSampleShape.SetBrush(Value: TBrush);
begin
FBrush.Assign(Value); { replace existing brush with parameter }
end;
procedure TSampleShape.SetPen(Value: TPen);
begin
FPen.Assign(Value); { replace existing pen with parameter }
end;
void __fastcall TSampleShape::SetBrush( TBrush* Value)
{
FBrush->Assign(Value);
}
void __fastcall TSampleShape::SetPen( TPen* Value)
{
FPen->Assign(Value);
}
To directly assign the contents of Value to FBrush-
FBrush := Value;
FBrush = Value;
• would overwrite the internal pointer for FBrush, lose memory, and create a number of ownership problems.

3.2.1.1.5 Declaring the Class Fields


Each class a component owns must have a class field declared for it in the component. The class field ensures that the
component always has a pointer to the owned object so that it can destroy the class before destroying itself. In general, a
component initializes owned objects in its constructor and destroys them in its destructor.

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.

Add fields for a pen and brush to the shape control:


type
TSampleShape = class(TGraphicControl)
private { fields are nearly always private }
FPen: TPen; { a field for the pen object }
FBrush: TBrush; { a field for the brush object }
.
.
.
end;
class PACKAGE TSampleShape : public TGraphicControl
{
private: // data members are always private
TPen *FPen; // a data member for the pen object
TBrush *FBrush; // a data member for the brush object
3 .
.
.
};

3.2.1.1.6 Declaring the Property


When you declare a property, you usually need to declare a private field to store the data for the property, then specify methods
for reading and writing the property value. Often, you don't need to use a method to read the value, but can just point to the

1222
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

stored data instead.

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.

Add the following declarations to TSampleShape:


type
TSampleShape = class(TGraphicControl)
private
FShape: TSampleShapeType; { field to hold property value }
procedure SetShape(Value: TSampleShapeType);
published
property Shape: TSampleShapeType read FShape write SetShape;
end;
class PACKAGE TSampleShape : public TGraphicControl
{
private:
TSampleShapeType FShape;
void __fastcall SetShape(TSampleShapeType Value);
__published:
__property TSampleShapeType Shape = {read=FShape, write=SetShape, nodefault};
};
Now all that remains is to add the implementation of SetShape.

3.2.1.1.7 Declaring the Property Type


When you declare a property of a user-defined type, you must declare the type first, before the class that includes the property.
The most common sort of user-defined type for properties is enumerated.

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.

3.2.1.1.8 Determining What to Draw


A graphic control can change its appearance to reflect a dynamic condition, including user input. A graphic control that always
looks the same should probably not be a component at all. If you want a static image, you can import the image instead of using
a control.

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

1. Declaring the property type. ( see page 1223)


2. Declaring the property. ( see page 1222)
3. Writing the implementation method. ( see page 1230)

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).

3.2.1.1.9 Drawing the Component Image


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:

• Use the pen and brush selected by the user.


• Use the selected shape.
• Adjust coordinates so that squares and circles use the same width and height.

Overriding the Paint method requires two steps:


1. Add Paint to the component's declaration.
2. Write the Paint method in the implementation part of the unit.
For the shape control, add the following declaration to the class declaration:
type
TSampleShape = class(TGraphicControl)
.
.
.
protected
procedure Paint; override;
.
.
.
end;
class PACKAGE TSampleShape : public TGraphicControl
{
.
.
.
protected:
virtual void __fastcall Paint();
.
.
.
};
Then write the method in the implementation part of the unit:
procedure TSampleShape.Paint;
begin
with Canvas do
begin
Pen := FPen; { copy the component's pen }
Brush := FBrush; { copy the component's brush }
case FShape of
sstRectangle, sstSquare:
3 Rectangle(0, 0, Width, Height); { draw rectangles and squares }
sstRoundRect, sstRoundSquare:
RoundRect(0, 0, Width, Height, Width div 4, Height div 4); { draw rounded shapes }
sstCircle, sstEllipse:
Ellipse(0, 0, Width, Height); { draw round shapes }
end;
end;
end;
void __fastcall TSampleShape::Paint()
{
int X,Y,W,H,S;

1224
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

Canvas->Pen = FPen; // copy the component's pen


Canvas->Brush = FBrush; // copy the component's brush
W=Width; // use the component width
H=Height; // use the component height
X=Y=0; // save smallest for circles/squares
if( W<H )
S=W;
else
S=H;
switch(FShape)
{
case sstRectangle: // draw rectangles and squares
case sstSquare:
Canvas->Rectangle(X,Y,X+W,Y+H);
break;
case sstRoundRect: // draw rounded rectangles and squares
case sstRoundSquare:
Canvas->RoundRect(X,Y,X+W,Y+H,S/4,S/4);
break;
case sstCircle: // draw circles and ellipses
case sstEllipse:
Canvas->Ellipse(X,Y,X+W,Y+H);
break;
default:
break;
}
}
Paint is called whenever the control needs to update its image. Controls are painted when they first appear or when a window in
front of them goes away. In addition, you can force repainting by calling Invalidate, as the StyleChanged method does.

3.2.1.1.10 Initializing Owned Classes


If you add classes to your component, the component's constructor must initialize them so that the user can interact with the
objects at runtime. Similarly, the component's destructor must also destroy the owned objects before destroying the component
itself.

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
}

3.2.1.1.11 Overriding the Constructor and Destructor


To change default property values and initialize owned classes for your component, you must override the inherited constructor
and destructor. In both cases, remember always to call the inherited method in your new constructor or destructor.

Changing default property values


The default size of a graphic control is fairly small, so you can change the width and height in the constructor. Changing default
property values is explained in more detail in Modifying an existing component ( see page 1365).

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;
}

3.2.1.1.12 Publishing Inherited Properties (Graphic)


Once you derive a component type, you can decide which of the properties and events declared in the protected parts of the
ancestor class you want to surface in the new component. TGraphicControl already publishes all the properties that enable the
component to function as a control, so all you need to publish is the ability to respond to mouse events and handle
drag-and-drop.

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

3.2.1.1.13 Publishing the Pen and Brush


By default, a canvas has a thin black pen and a solid white brush. To let developers change the pen and brush, you must provide
classes for them to manipulate at design time, then copy the classes into the canvas during painting. Classes such as an
auxiliary pen or brush are called owned classes because the component owns them and is responsible for creating and
destroying them.

Managing owned classes requires:

1. Declaring the class fields. ( see page 1222)


2. Declaring the access properties. ( see page 1221)
3. Initializing owned classes. ( see page 1225)
4. Setting owned classes' properties. ( see page 1229)

3.2.1.1.14 Refining the Shape Drawing


The standard shape control does one more thing that your sample shape control does not yet do: it handles squares and circles
as well as rectangles and ellipses. To do that, you need to write code that finds the shortest side and centers the image.

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

W=Width; // use the component width


H=Height; // use the component height
X=Y=0; // save smallest for circles/squares
if( W<H )
S=W;
else
S=H;
switch(FShape) // adjust height, width and position
{
case sstRectangle:
case sstRoundRect:
case sstEllipse:
Y=X=0; // origin is top-left for these shapes
break;
case sstSquare:
case sstRoundSquare:
case sstCircle:
X= (W-S)/2; // center these horizontally
Y= (H-S)/2; // and vertically
break;
default:
break;
}
switch(FShape)
{
case sstSquare: // draw rectangles and squares
W=H=S; // use shortest dimension for width and height
case sstRectangle:
Canvas->Rectangle(X,Y,X+W,Y+H);
break;
case sstRoundSquare: // draw rounded rectangles and squares
W=H=S;
case sstRoundRect:
Canvas->RoundRect(X,Y,X+W,Y+H,S/4,S/4);
break;
case sstCircle: // draw circles and ellipses
W=H=S;
case sstEllipse:
Canvas->Ellipse(X,Y,X+W,Y+H);
break;
default:
break;
}
}

3.2.1.1.15 Setting Owned Classes' Properties


As the final step in handling the pen and brush classes, you need to make sure that changes in the pen and brush cause the
shape control to repaint itself. Both pen and brush classes have OnChange events, so you can create a method in the shape
control and point both OnChange events to it.

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.

3.2.1.1.16 Writing the Implementation Method


When the read or write part of a property definition uses a method instead of directly accessing the stored property data, you
need to implement the method.

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

Invalidate(); // force a repaint with the new shape


}
}

3.2.1.2 Creating events


Topics
Name Description
Creating Events: Overview ( see page 1233) An event is a link between an occurrence in the system (such as a user action or
a change in focus) and a piece of code that responds to that occurrence. The
responding code is an event handler, and is nearly always written by the
application developer. Events let application developers customize the behavior
of components without having to change the classes themselves. This is known
as delegation.
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... more ( see page 1233)
What Are Events? ( see page 1234) An event is a mechanism that links an occurrence to some code. More
specifically, an event is a method pointer that points to a method in a specific
class instance.
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... more ( see page 1234)
Events Are closures (C++) ( see page 1234) Closures are used to implement events. A closure is a special pointer type that
points to a specific method in a specific class instance. As a component writer,
you can treat the closure as a place holder: your code detects that an event
occurs, so you call the method (if any) specified by the user for that event.
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....
more ( see page 1234)
Events Are Method Pointers ( see page 1234) 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...
more ( see page 1234)
Calling the Click-event Handler ( see page 1235) All controls, for example, inherit a dynamic method called Click for handling click
events:
Events Are Properties ( see page 1235) Components use properties to implement their events. Unlike most other
properties, events do not use methods to implement their read and write parts.
Instead, event properties use a private class field of the same type as the
property.
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:
Event Types Are Method-pointer Types ( see page 1235) Because an event is a pointer to an event handler, the type of the event property
must be a method-pointer type. Similarly, any code to be used as an event
handler must be an appropriately typed method of a class.
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 3
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... more ( see page 1235)

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:

• Identifying standard events ( see page 1237)


• Making events visible ( see page 1238)
• Changing the standard event handling ( see page 1238)
Identifying Standard Events ( see page 1237) There are two categories of standard events: those defined for all controls and
those defined only for the standard windowed controls.
Making Events Visible ( see page 1238) The declarations of the standard events in TControl and TWinControl are
protected, as are the methods that correspond to them. If you are inheriting from
one of these abstract classes and want to make their events accessible at
runtime or design time, you need to redeclare the events as either public or
published.
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
3 declaring it as public or published.
Changing the Standard Event Handling ( see page 1238) If you want to change the way your component responds to a certain kind of
event, you might be tempted to write some code and assign it to the event. As an
application developer, that is exactly what you would do. But when you are
creating a component, you must keep the event available for developers who use
the component.
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,... more ( see page 1238)

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:

• Triggering the event ( see page 1239)


• Defining the handler type ( see page 1239)
• Declaring the event ( see page 1240)
• Calling the event ( see page 1240)
Triggering the Event ( see page 1239) You need to know what triggers the event. For some events, the answer is
obvious. For example, a mouse-down event occurs when the user presses the
left button on the mouse and Windows sends a WM_LBUTTONDOWN message
to the application. Upon receiving that message, a component calls its
MouseDown method, which in turn calls any code the user has attached to the
OnMouseDown event.
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...
more ( see page 1239)
Two Kinds of Events ( see page 1239) There are two kinds of occurrence you might need to provide events for: user
interactions and state changes. User-interaction events are nearly always
triggered by a message from Windows, indicating that the user did something
your component may need to respond to. State-change events may also be
related to messages from Windows (focus changes or enabling, for example), but
they can also occur through changes in properties or other code.
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.
Defining the Handler Type ( see page 1239) Once you determine when the event occurs, you must define how you want the
event handled. This means determining the type of the event handler. In most
cases, handlers for events you define yourself are either simple notifications or
event-specific types. It is also possible to get information back from the handler.
Declaring the Event ( see page 1240) Once you have determined the type of your event handler, you are ready to
declare the method pointer and the property for the event. Be sure to give the
event a meaningful and descriptive name so that users can understand what the
event does. Try to be consistent with names of similar properties in other
components.
Calling the Event ( see page 1240) You should centralize calls to an event. That is, create a virtual method in your
component that calls the application's event handler (if it assigns one) and
provides any default handling.
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.
There are two other considerations when calling the event:

• Empty handlers must be valid. ( see page 1240)


• Users can override default handling. ( see page 1240)
Empty Handlers Must Be Valid ( see page 1240) You should never create a situation in which an empty event handler causes an
error, nor should the proper functioning of your component depend on a
particular response from the application's event-handling code.
Users Can Override Default Handling ( see page 1240) For some kinds of events, developers may want to replace the default handling or
even suppress all responses. To allow this, you need to pass an argument by
reference to the handler and check for a certain value when the handler returns.
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. 3

3.2.1.2.1 Creating Events: Overview


An event is a link between an occurrence in the system (such as a user action or a change in focus) and a piece of code that
responds to that occurrence. The responding code is an event handler, and is nearly always written by the application developer.
Events let application developers customize the behavior of components without having to change the classes themselves. This
is known as delegation.

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:

• What are events? ( see page 1234)


• Implementing the standard events ( see page 1237)
• Defining your own events ( see page 1238)
Events are implemented as properties, so you should already be familiar with the material in Creating properties ( see page
1249) before you attempt to create or change a component's events.

3.2.1.2.2 What Are Events?


An event is a mechanism that links an occurrence to some code. More specifically, an event is a method pointer that points to a
method in a specific class instance.

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.

To write an event, you need to understand the following:

• Events are method pointers ( see page 1234).


• Events are properties ( see page 1235).
• Event types are method-pointer types ( see page 1235).
• Event-handler types are procedures ( see page 1236).
• Event handlers are optional ( see page 1237).

3.2.1.2.3 Events Are closures (C++)


Closures are used to implement events. A closure is a special pointer type that points to a specific method in a specific class
instance. As a component writer, you can treat the closure as a place holder: your code detects that an event occurs, so you call
the method (if any) specified by the user for that event.

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

3.2.1.2.5 Calling the Click-event Handler


All controls, for example, inherit a dynamic method called Click for handling click events:
procedure Click; dynamic;
virtual void __fastcall Click(void);
The implementation of Click calls the user's click-event handler, if one exists. If the user has assigned a handler to a control's
OnClick event, clicking the control results in that method being called. If no handler is assigned, nothing happens.

3.2.1.2.6 Events Are Properties


Components use properties to implement their events. Unlike most other properties, events do not use methods to implement
their read and write parts. Instead, event properties use a private class field of the same type as the property.

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.

3.2.1.2.7 Event Types Are Method-pointer Types


Because an event is a pointer to an event handler, the type of the event property must be a method-pointer type. Similarly, any 3
code to be used as an event handler must be an appropriately typed method of a class.

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

3.2.1.2.8 Event Handler Types Are Procedures


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 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.

3.2.1.2.9 Event Handlers Have A Return Type of void (C++)


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 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.

3.2.1.2.11 Event Handlers Are Optional


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 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.

3.2.1.2.12 Implementing the Standard Events


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:

• Identifying standard events ( see page 1237)


• Making events visible ( see page 1238)
• Changing the standard event handling ( see page 1238)

3.2.1.2.13 Identifying Standard Events


There are two categories of standard events: those defined for all controls and those defined only for the standard windowed
controls.

Standard events for all controls


The most basic events are defined in the class TControl. All controls, whether windowed, graphical, or custom, inherit these
events. The following events are available in all 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.

3.2.1.2.14 Making Events Visible


The declarations of the standard events in TControl and TWinControl are protected, as are the methods that correspond to them.
If you are inheriting from one of these abstract classes and want to make their events accessible at runtime or design time, you
need to redeclare the events as either public or published.

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.

3.2.1.2.15 Changing the Standard Event Handling


If you want to change the way your component responds to a certain kind of event, you might be tempted to write some code
and assign it to the event. As an application developer, that is exactly what you would do. But when you are creating a
component, you must keep the event available for developers who use the component.

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:

• Triggering the event ( see page 1239)

1238
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

• Defining the handler type ( see page 1239)


• Declaring the event ( see page 1240)
• Calling the event ( see page 1240)

3.2.1.2.17 Triggering the Event


You need to know what triggers the event. For some events, the answer is obvious. For example, a mouse-down event occurs
when the user presses the left button on the mouse and Windows sends a WM_LBUTTONDOWN message to the application.
Upon receiving that message, a component calls its MouseDown method, which in turn calls any code the user has attached to
the OnMouseDown event.

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.

3.2.1.2.18 Two Kinds of Events


There are two kinds of occurrence you might need to provide events for: user interactions and state changes. User-interaction
events are nearly always triggered by a message from Windows, indicating that the user did something your component may
need to respond to. State-change events may also be related to messages from Windows (focus changes or enabling, for
example), but they can also occur through changes in properties or other code.

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.

3.2.1.2.19 Defining the Handler Type


Once you determine when the event occurs, you must define how you want the event handled. This means determining the type
of the event handler. In most cases, handlers for events you define yourself are either simple notifications or event-specific
types. It is also possible to get information back from the handler.

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.

Returning information from the handler


Because all event handlers are procedures, the only way to pass information back from a handler is through a var parameter.
Your components can use such information to determine how or whether to process an event after the user's handler executes.

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.

3.2.1.2.20 Declaring the Event


Once you have determined the type of your event handler, you are ready to declare the method pointer and the property for the
event. Be sure to give the event a meaningful and descriptive name so that users can understand what the event does. Try to be
consistent with names of similar properties in other components.

Event names start with "On"


The names of most events in Delphi begin with "On." This is just a convention; the compiler does not enforce it. The Object
Inspector determines that a property is an event by looking at the type of the property: all method-pointer properties are assumed
to be events and appear on the Events page.

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."

3.2.1.2.21 Calling the Event


You should centralize calls to an event. That is, create a virtual method in your component that calls the application's event
handler (if it assigns one) and provides any default handling.

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.

There are two other considerations when calling the event:

• Empty handlers must be valid. ( see page 1240)


• Users can override default handling. ( see page 1240)

3.2.1.2.22 Empty Handlers Must Be Valid


You should never create a situation in which an empty event handler causes an error, nor should the proper functioning of your
component depend on a particular response from the application's event-handling code.

3.2.1.2.23 Users Can Override Default Handling


For some kinds of events, developers may want to replace the default handling or even suppress all responses. To allow this,
you need to pass an argument by reference to the handler and check for a certain value when the handler returns.

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

3.2.1.3 Creating methods


Topics
Name Description
Abstract Methods ( see page 1242) Sometimes a method is declared as abstract in a Delphi component. In the
component library, abstract methods usually occur in classes whose names
begin with "custom," such as TCustomGrid. Such classes are themselves
abstract, in the sense that they are intended only for deriving descendant classes.
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... more ( see page 1242)
Avoiding Interdependencies ( see page 1242) At all times when writing components, minimize the preconditions imposed on the
developer. To the greatest extent possible, developers should be able to do
anything they want to a component, whenever they want to do it. There will be
times when you cannot accommodate that, but your goal should be to come as
close as possible.
This list gives you an idea of the kinds of dependencies to avoid:

• Methods that the user must call to use the component


• Methods that must execute in a particular order
• Methods that put the component into a state or mode
where certain events... more ( see page 1242)
Creating Methods: Overview ( see page 1243) Component methods are procedures and functions built into the structure of a
class. Although there are essentially no restrictions on what you can do with the
methods of a component, Delphi does use some standards you should follow.
These guidelines include:

• Avoiding dependencies ( see page 1242)


• Naming methods ( see page 1244)
• Protecting methods ( see page 1245)
• Making methods virtual ( see page 1245)
• Declaring methods ( see page 1243)
In general, components should not contain many methods
and you should minimize the number of methods that an
application needs to call. The features you might be
inclined to implement as methods are often better
encapsulated into properties. Properties provide an
interface that suits the Delphi and are... more ( see page
1243)
Declaring Methods ( see page 1243) Declaring a method in a component is the same as declaring any class method.
To declare a new method in a component, do the following:

• Add the declaration to the component's object-type


declaration.
• Implement the method in the implementation part of the 3
component's unit.
Example of Declaring Methods ( see page 1243) The following code shows a component that defines two new methods, one
protected method and one public virtual method.

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.

3.2.1.3.1 Abstract Methods


Sometimes a method is declared as abstract in a Delphi component. In the component library, abstract methods usually occur in
classes whose names begin with "custom," such as TCustomGrid. Such classes are themselves abstract, in the sense that they
are intended only for deriving descendant classes.

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.

3.2.1.3.2 Avoiding Interdependencies


3 At all times when writing components, minimize the preconditions imposed on the developer. To the greatest extent possible,
developers should be able to do anything they want to a component, whenever they want to do it. There will be times when you
cannot accommodate that, but your goal should be to come as close as possible.

This list gives you an idea of the kinds of dependencies to avoid:

• Methods that the user must call to use the component


• Methods that must execute in a particular order
• Methods that put the component into a state or mode where certain events or methods could be invalid

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.

3.2.1.3.3 Creating Methods: Overview


Component methods are procedures and functions built into the structure of a class. Although there are essentially no
restrictions on what you can do with the methods of a component, Delphi does use some standards you should follow. These
guidelines include:

• Avoiding dependencies ( see page 1242)


• Naming methods ( see page 1244)
• Protecting methods ( see page 1245)
• Making methods virtual ( see page 1245)
• Declaring methods ( see page 1243)
In general, components should not contain many methods and you should minimize the number of methods that an application
needs to call. The features you might be inclined to implement as methods are often better encapsulated into properties.
Properties provide an interface that suits the Delphi and are accessible at design time.

3.2.1.3.4 Declaring Methods


Declaring a method in a component is the same as declaring any class method.

To declare a new method in a component, do the following:

• Add the declaration to the component's object-type declaration.


• Implement the method in the implementation part of the component's unit.

3.2.1.3.5 Example of Declaring Methods


The following code shows a component that defines two new methods, one protected method and one public virtual method.

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;

3.2.1.3.6 Methods That Should Be Protected


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 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.

3.2.1.3.7 Methods That Should Be Public


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
3 respond to the user.

Note: Constructors and destructors should always be public.

3.2.1.3.8 Naming Methods


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

1244
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

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 your components.

Here are some suggestions for making clear method names:

• 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.

3.2.1.3.9 Protecting Methods


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.

3.2.1.3.10 Making Methods Virtual


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.

3.2.1.4 Creating properties


Topics
Name Description
Creating Properties: Overview ( see page 1249) Properties are the most visible parts of components. The application developer
can see and manipulate them at design time and get immediate feedback as the
components react in the Form Designer. Well-designed properties make your
components easier for others to use and easier for you to maintain.
To make the best use of properties in your components, you should understand
the following:

• Why create properties? ( see page 1249) 3


• Types of properties ( see page 1250)
• Publishing inherited properties ( see page 1250)
• Defining properties ( see page 1251)
• Creating array properties ( see page 1253)
• Storing and loading properties ( see page 1254)

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

• 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...
more ( see page 1249)
Types of Properties ( see page 1250) A property can be of any type. Different types are displayed differently in the
Object Inspector, which validates property assignments as they are made at
design time.
How properties appear in the Object Inspector
Publishing Inherited Properties ( see page 1250) All components inherit properties from their ancestor classes. When you derive a
new component from an existing one, your new component inherits all the
properties of its immediate ancestor. If you derive from one of the abstract
classes, many of the inherited properties are either protected or public, but not
published.
To make a protected or public property available at design time in the Object
Inspector, you must redeclare the property as published. Redeclaring means
adding a declaration for the inherited property to the declaration of the
descendant class.
Defining Properties ( see page 1251) This section shows how to declare new properties and explains some of the
conventions followed in the standard components. Topics include:

• Property declarations ( see page 1251)


• Internal data storage ( see page 1251)
• Direct access ( see page 1251)
• Access methods ( see page 1252)
• Default property values ( see page 1253)
Property Declarations ( see page 1251) A property is declared in the declaration of its component class. To declare a
property, you specify three things:

• The name of the property.


• The type of the property.
• The methods used to read and write the value of the
property. If no write method is declared, the property is
read-only.
Properties declared in a published section of the
component's class declaration are editable in the Object
Inspector at design time. The value of a published
property is saved with the component in the form file.
Properties declared in a public section are available at
runtime and can be read... more ( see page 1251)

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:

• Property data is stored in class fields.


• The fields used to store property data are private and
should be accessed only from within the component itself.
Derived components should use the inherited property;
they do not need direct access to the property's internal
data storage.
• Identifiers for these fields consist of the letter F followed
by the name of the property. For example, the raw data for
the Width property defined in TControl is stored in a field
called... more ( see page 1251)
Direct Access ( see page 1251) The simplest way to make property data available is direct access. That is, the
read and write parts of the property declaration specify that assigning or reading
the property value goes directly to the internal-storage field without calling an
access method. Direct access is useful when you want to make a property
available in the Object Inspector but changes to its value trigger no immediate
processing.
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... more ( see page 1251)
Access Methods (properties) ( see page 1252) You can specify an access method instead of a field in the read and write parts
of a property declaration. Access methods should be protected, and are usually
declared as virtual; this allows descendant components to override the
property's implementation.
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 Read Method ( see page 1252) The read method for a property is a function that takes no parameters (except as
noted below) and returns a value of the same type as the property. By
convention, the function's name is Get followed by the name of the property. For
example, the read method for a property called Count would be GetCount. The
read method manipulates the internal storage data as needed to produce the
value of the property in the appropriate type.
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... more ( see page 1252)
The Write Method ( see page 1252) The write method for a property is a procedure that takes a single parameter
(except as noted below) of the same type as the property. The parameter can be
passed by reference or by value, and can have any name you choose. By
convention, the write method's name is Set followed by the name of the property.
For example, the write method for a property called Count would be SetCount.
The value passed in the parameter becomes the new value of the property; the
write method must perform any manipulation needed to put the appropriate data
in the property's... more ( see page 1252)
Default Property Values ( see page 1253) When you declare a property, you can specify a default value for it. The VCL
uses the default value to determine whether to store the property in a form file. If
you do not specify a default value for a property, the VCL always stores the
property.
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,
Specifying No Default Value ( see page 1253) When redeclaring a property, you can specify that the property has no default
value, even if the inherited property specified one.
To designate a property as having no default value, append the nodefault
directive to the property's declaration. For example,
3

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

• 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... more ( see page
1253)
Creating Properties for Interfaces ( see page 1253) You can use an interface as the value of a published property, much as you can
use an object. However, the mechanism by which your component receives
notifications from the implementation of that interface differs. In Creating
properties for subcomponents ( see page 1254), the property setter called the
FreeNotification method of the component that was assigned as the property
value. This allowed the component to update itself when the component that was
the value of the property was freed. When the value of the property is an
interface, however, you don't have access to the component that implements that
interface. As a... more ( see page 1253)
Creating Properties for Subcomponents ( see page 1254) By default, when a property's value is another component, you assign a value to
that property by adding an instance of the other component to the form or data
module and then assigning that component as the value of the property.
However, it is also possible for your component to create its own instance of the
object that implements the property value. Such a dedicated component is called
a subcomponent.
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... more ( see page 1254)
Storing and Loading Properties ( see page 1254) Delphi stores forms and their components in form (.dfm in VCL applications )
files. A form file stores the properties of a form and its components. When Delphi
developers add the components you write to their forms, your components must
have the ability to 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... more ( see page
1254)
Using the Store-and-load Mechanism ( see page 1255) The description of a form consists of a list of the form's properties, along with
similar descriptions of each component on the form. Each component, including
the form itself, is responsible for storing and loading its own description.
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... more ( see page 1255)
Specifying Default Values ( see page 1255) Delphi components save their property values only if those values differ from the
defaults. If you do not specify otherwise, Delphi assumes a property has no
default value, meaning the component always stores the property, whatever its
value.
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.
Determining What to Store ( see page 1255) You can control whether Delphi stores each of your components' properties. By
default, all properties in the published part of the class declaration are stored.
You can choose not to store a given property at all, or you can designate a
function that determines dynamically whether to store the property.
3
To control whether Delphi stores a property, add the stored directive to the
property declaration, followed by True, False, or the name of a Boolean function.

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:

• Create a method of type TWriterProc to store your


property value and a method of type TReaderProc to load
your property value. This approach lets you take
advantage of Delphi's built-in capabilities for saving and
loading simple types. If your property value is built out of
types that Delphi knows how to save and load, use this
approach.
• Create two methods of type TStreamProc, one to store
and one to load... more ( see page 1256)
Overriding the DefineProperties Method ( see page 1257) Once you have created methods to store and load your property value, you can
override the component's DefineProperties method. Delphi calls this method
when it loads or stores the component. In the DefineProperties method, you must
call the DefineProperty method or the DefineBinaryProperty method of the
current filer, passing it the method to use for loading or saving your property
value. If your load and store methods are of type TWriterProc and type
TReaderProc, then you call the filer's DefineProperty method. If you created
methods of type TStreamProc, call DefineBinaryProperty instead.
No matter which method you use to... more ( see page 1257)

3.2.1.4.1 Creating Properties: Overview


Properties are the most visible parts of components. The application developer can see and manipulate them at design time and
get immediate feedback as the components react in the Form Designer. Well-designed properties make your components easier
for others to use and easier for you to maintain.

To make the best use of properties in your components, you should understand the following:

• Why create properties? ( see page 1249)


• Types of properties ( see page 1250)
• Publishing inherited properties ( see page 1250)
3
• Defining properties ( see page 1251)
• Creating array properties ( see page 1253)
• Storing and loading properties ( see page 1254)

3.2.1.4.2 Why Create Properties?


From the application developer's standpoint, properties look like variables. Developers can set or read the values of properties

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.)

Properties provide more power than simple fields because

• 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.

3.2.1.4.3 Types of Properties


A property can be of any type. Different types are displayed differently in the Object Inspector, which validates property
assignments as they are made at design time.

How properties appear in the Object Inspector

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

3.2.1.4.4 Publishing Inherited Properties


All components inherit properties from their ancestor classes. When you derive a new component from an existing one, your new
component inherits all the properties of its immediate ancestor. If you derive from one of the abstract classes, many of the
inherited properties are either protected or public, but not published.

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.

3.2.1.4.5 Defining Properties


This section shows how to declare new properties and explains some of the conventions followed in the standard components.
Topics include:

• Property declarations ( see page 1251)


• Internal data storage ( see page 1251)
• Direct access ( see page 1251)
• Access methods ( see page 1252)
• Default property values ( see page 1253)

3.2.1.4.6 Property Declarations


A property is declared in the declaration of its component class. To declare a property, you specify three things:

• The name of the property.


• The type of the property.
• The methods used to read and write the value of the property. If no write method is declared, the property is read-only.
Properties declared in a published section of the component's class declaration are editable in the Object Inspector at design
time. The value of a published property is saved with the component in the form file. Properties declared in a public section
are available at runtime and can be read or set in program code.

3.2.1.4.7 Internal Data Storage


There are no restrictions on how you store the data for a property. In general, however, Delphi components follow these
conventions:

• Property data is stored in class fields.


• The fields used to store property data are private and should be accessed only from within the component itself. Derived
components should use the inherited property; they do not need direct access to the property's internal data storage.
• Identifiers for these fields consist of the letter F followed by the name of the property. For example, the raw data for the Width
property defined in TControl is stored in a field called FWidth.
The principle that underlies these conventions is that only the implementation methods for a property should access the data
behind it. If a method or another property needs to change that data, it should do so through the property, not by direct access
to the stored data. This ensures that the implementation of an inherited property can change without invalidating derived
components.

3.2.1.4.8 Direct Access


The simplest way to make property data available is direct access. That is, the read and write parts of the property declaration 3
specify that assigning or reading the property value goes directly to the internal-storage field without calling an access method.
Direct access is useful when you want to make a property available in the Object Inspector but changes to its value trigger no
immediate processing.

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

3.2.1.4.9 Access Methods (properties)


You can specify an access method instead of a field in the read and write parts of a property declaration. Access methods
should be protected, and are usually declared as virtual; this allows descendant components to override the property's
implementation.

Avoid making access methods public. Keeping them protected ensures that application developers do not inadvertently modify a
property by calling one of these methods.

3.2.1.4.10 The Read Method


The read method for a property is a function that takes no parameters (except as noted below) and returns a value of the same
type as the property. By convention, the function's name is Get followed by the name of the property. For example, the read
method for a property called Count would be GetCount. The read method manipulates the internal storage data as needed to
produce the value of the property in the appropriate type.

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.

3.2.1.4.11 The Write Method


The write method for a property is a procedure that takes a single parameter (except as noted below) of the same type as the
property. The parameter can be passed by reference or by value, and can have any name you choose. By convention, the write
method's name is Set followed by the name of the property. For example, the write method for a property called Count would be
SetCount. The value passed in the parameter becomes the new value of the property; the write method must perform any
manipulation needed to put the appropriate data in the property's internal storage.

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.)

If you do not declare a write method, the property is read-only.

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

3.2.1.4.12 Default Property Values


When you declare a property, you can specify a default value for it. The VCL uses the default value to determine whether to
store the property in a form file. If you do not specify a default value for a property, the VCL always stores the property.

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.

3.2.1.4.13 Specifying No Default Value


When redeclaring a property, you can specify that the property has no default value, even if the inherited property specified one.

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.

3.2.1.4.14 Creating Array Properties


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

• 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.

3.2.1.4.15 Creating Properties for Interfaces


You can use an interface as the value of a published property, much as you can use an object. However, the mechanism by 3
which your component receives notifications from the implementation of that interface differs. In Creating properties for
subcomponents ( see page 1254), the property setter called the FreeNotification method of the component that was assigned
as the property value. This allowed the component to update itself when the component that was the value of the property was
freed. When the value of the property is an interface, however, you don't have access to the component that implements that
interface. As a result, you can't call its FreeNotification method.

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.

3.2.1.4.16 Creating Properties for Subcomponents


By default, when a property's value is another component, you assign a value to that property by adding an instance of the other
component to the form or data module and then assigning that component as the value of the property. However, it is also
possible for your component to create its own instance of the object that implements the property value. Such a dedicated
component is called a subcomponent.

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.

3.2.1.4.17 Storing and Loading Properties


Delphi stores forms and their components in form (.dfm in VCL applications ) files. A form file stores the properties of a form and
its components. When Delphi developers add the components you write to their forms, your components must have the ability to

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.

These are the aspects of property storage you need to understand:

• Using the store-and-load mechanism ( see page 1255)


• Specifying default values ( see page 1255)
• Determining what to store ( see page 1255)
• Initializing after loading ( see page 1256)
• Storing and loading unpublished properties ( see page 1256)

3.2.1.4.18 Using the Store-and-load Mechanism


The description of a form consists of a list of the form's properties, along with similar descriptions of each component on the
form. Each component, including the form itself, is responsible for storing and loading its own description.

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.

3.2.1.4.19 Specifying Default Values


Delphi components save their property values only if those values differ from the defaults. If you do not specify otherwise, Delphi
assumes a property has no default value, meaning the component always stores the property, whatever its value.

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

3.2.1.4.20 Determining What to Store


You can control whether Delphi stores each of your components' properties. By default, all properties in the published part of the
class declaration are stored. You can choose not to store a given property at all, or you can designate a function that determines
dynamically whether to store the property.

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

name of a Boolean function.

3.2.1.4.21 Initializing After Loading


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 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;

3.2.1.4.22 Storing and Loading Unpublished Properties


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 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.

3.2.1.4.23 Creating Methods to Store and Load Property Values


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:
3 • Create a method of type TWriterProc to store your property value and a method of type TReaderProc to load your property
value. This approach lets you take advantage of Delphi's built-in capabilities for saving and loading simple types. If your
property value is built out of types that Delphi knows how to save and load, use this approach.
• Create two methods of type TStreamProc, one to store and one to load your property's value. TStreamProc takes a stream as
an argument, and you can use the stream's methods to write and read your property values.
For example, consider a property that represents a component that is created at runtime. Delphi knows how to write this value,
but does not do so automatically because the component is not created in the form designer. Because the streaming system
can already load and save components, you can use the first approach. The following methods load and store the dynamically

1256
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

created component that is the value of a property named MyCompProperty:


procedure TSampleComponent.LoadCompProperty(Reader: TReader);
begin
if Reader.ReadBoolean then
MyCompProperty := Reader.ReadComponent(nil);
end;
procedure TSampleComponent.StoreCompProperty(Writer: TWriter);
begin
Writer.WriteBoolean(MyCompProperty <> nil);
if MyCompProperty <> nil then
Writer.WriteComponent(MyCompProperty);
end;
void __fastcall TSampleComponent::LoadCompProperty(TReader *Reader)
{
if (Reader->ReadBoolean())
MyCompProperty = Reader->ReadComponent(NULL);
}
void __fastcall TSampleComponent::StoreCompProperty(TWriter *Writer)
{
if (MyCompProperty)
{
Writer->WriteBoolean(true);
Writer->WriteComponent(MyCompProperty);
}
else
Writer->WriteBoolean(false);
}

3.2.1.4.24 Overriding the DefineProperties Method


Once you have created methods to store and load your property value, you can override the component's DefineProperties
method. Delphi calls this method when it loads or stores the component. In the DefineProperties method, you must call the
DefineProperty method or the DefineBinaryProperty method of the current filer, passing it the method to use for loading or saving
your property value. If your load and store methods are of type TWriterProc and type TReaderProc, then you call the filer's
DefineProperty method. If you created methods of type TStreamProc, call DefineBinaryProperty instead.

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;

3.2.1.5 Customizing a grid


Topics
Name Description
Accessing the Day, Month, and Year ( see page 1260) An encoded numeric date is fine for applications, but humans prefer to work with
days, months, and years. You can provide alternate access to those elements of
the stored, encoded date by creating properties.
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... more ( see page
1260)
Changing Initial Values ( see page 1262) A calendar is essentially a grid with a fixed number of rows and columns,
although not all the rows always contain dates. For this reason, you have not
published the grid properties ColCount and RowCount, because it is highly
unlikely that users of the calendar will want to display anything other than seven
days per week. You still must set the initial values of those properties so that the
week always has seven days, however.
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... more ( see page 1262)
Creating and registering the component (Grid) ( see page 1263) 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. Creating a new
component. ( see page 1317)

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:

• Creating and registering the component ( see page


1263)
• Publishing inherited properties ( see page 1271)
• Changing initial values ( see page 1262)
• Resizing the cells ( see page 1272)
• Filling in the cells ( see page 1265)
• Navigating months and years ( see page 1269)
• Navigating days ( see page 1269)
In VCL applications, the resulting component is similar to the
TCalendar component on the Samples category of the
Tool palette. See Specifying the palette page ( see page
1356).
Excluding Blank Cells ( see page 1265) As the calendar is written, the user can select a blank cell, but the date does not
change. It makes sense, then, to disallow selection of the blank cells.
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:
Filling in the Cells ( see page 1265) A grid control fills in its contents cell-by-cell. In the case of the calendar, that
means calculating which date, if any, belongs in each cell. The default drawing
for grid cells takes place in a virtual method called DrawCell.
To fill in the contents of grid cells, override the DrawCell method.
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:
Generating the Day Numbers ( see page 1266) Putting numbers into the calendar involves several considerations. The number
of days in the month depends on which month it is, and whether the given year is
a leap year. In addition, months start on different days of the week, dependent on
the month and year. Use the IsLeapYear function to determine whether the year
is a leap year. Use the MonthDays array in the SysUtils unit to get the number of
days in the month.
Once you have the information on leap years and days per month, you can
calculate where in the grid the individual dates go.... more ( see page 1266)
Moving the Selection ( see page 1268) The inherited behavior of a grid handles moving the selection in response to
either arrow keys or clicks, but if you want to change the selected day, you need
to modify that default behavior.
To handle movements within the calendar, override the Click method of the grid.
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... more ( see page 1268)
Navigating Days ( see page 1269) Within a given month, there are two obvious ways to navigate among the days.
The first is to use the arrow keys, and the other is to respond to clicks of the
mouse. The standard grid component handles both as if they were clicks. That is,
an arrow movement is treated like a click on an adjacent cell. 3
The process of navigating days consists of

• Moving the selection ( see page 1268)


• Providing an OnChange event ( see page 1270)
• Excluding blank cells ( see page 1265)

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)

3.2.1.5.1 Accessing the Day, Month, and Year


An encoded numeric date is fine for applications, but humans prefer to work with days, months, and years. You can provide
alternate access to those elements of the stored, encoded date by creating properties.

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

property Year: Integer index 1 read GetDateElement write SetDateElement;


.
.
.
class PACKAGE TSampleCalendar : public TCustomGrid
{
.
.
.
public:
__property int Day = {read=GetDateElement, write=SetDateElement, index=3,
nodefault};
__property int Month = {read=GetDateElement, write=SetDateElement, index=2,
nodefault};
__property int Year = {read=GetDateElement, write=SetDateElement, index=1,
nodefault};
};
2. Declare and write the implementation methods, setting different elements for each index value:
type
TSampleCalendar = class(TCustomGrid)
private
function GetDateElement(Index: Integer): Integer; { note the Index parameter }
procedure SetDateElement(Index: Integer; Value: Integer);
.
.
.
function TSampleCalendar.GetDateElement(Index: Integer): Integer;
var
AYear, AMonth, ADay: Word;
begin
DecodeDate(FDate, AYear, AMonth, ADay); { break encoded date into elements }
case Index of
1: Result := AYear;
2: Result := AMonth;
3: Result := ADay;
else Result := -1;
end;
end;
procedure TSampleCalendar.SetDateElement(Index: Integer; Value: Integer);
var
AYear, AMonth, ADay: Word;
begin
if Value > 0 then { all elements must be positive }
begin
DecodeDate(FDate, AYear, AMonth, ADay); { get current date elements }
case Index of { set new element depending on Index }
1: AYear := Value;
2: AMonth := Value;
3: ADay := Value;
else Exit;
end;
FDate := EncodeDate(AYear, AMonth, ADay); { encode the modified date }
Refresh; { update the visible calendar }
end;
end; 3
// header file
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
int __fastcall GetDateElement(int Index); // note the Index parameter
void __fastcall SetDateElement(int Index, int Value);
.
.
.
};

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.

3.2.1.5.2 Changing Initial Values


A calendar is essentially a grid with a fixed number of rows and columns, although not all the rows always contain dates. For this
reason, you have not published the grid properties ColCount and RowCount, because it is highly unlikely that users of the
calendar will want to display anything other than seven days per week. You still must set the initial values of those properties so
that the week always has seven days, however.

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

inherited Create(AOwner); { call inherited constructor }


ColCount := 7; { always seven days/week }
RowCount := 7; { always six weeks plus the headings }
FixedCols := 0; { no row labels }
FixedRows := 1; { one row for day names }
ScrollBars := ssNone; { no need to scroll }
Options := Options - [goRangeSelect] + [goDrawFocusSelected]; {disable range selection}
end;
//header file
class PACKAGE TSampleCalendar : public TCustomGrid
{
protected:
virtual void __fastcall DrawCell(int ACol, int ARow, const Windows::TRect &Rect,
TGridDrawState AState);
.
.
.
public:
__fastcall TSampleCalendar(TComponent *Owner); // the added constructor
.
.
.
};
//implementation file
__fastcall TSampleCalendar::TSampleCalendar(TComponent *Owner) : TCustomGrid(Owner)
{
ColCount = 7;
RowCount = 7;
FixedCols = 0;
FixedRows = 1;
ScrollBars = ssNone;
Options = (Options >> goRangeSelect) << goDrawFocusSelected;
}
void __fastcall TSampleCalendar::DrawCell(int ACol, int ARow, const Windows::TRect
&ARect, TGridDrawState AState)
{
}
The calendar now has seven columns and seven rows, with the top row fixed, or nonscrolling.

3.2.1.5.3 Creating and registering the component (Grid)


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. Creating a new component. ( see page 1317)

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)

3.2.1.5.4 Customizing a Grid: Overview


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
3
component, TCustomGrid:

• Creating and registering the component ( see page 1263)


• Publishing inherited properties ( see page 1271)
• Changing initial values ( see page 1262)
• Resizing the cells ( see page 1272)
• Filling in the cells ( see page 1265)

1264
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

• Navigating months and years ( see page 1269)


• Navigating days ( see page 1269)
In VCL applications, the resulting component is similar to the TCalendar component on the Samples category of the Tool palette.
See Specifying the palette page ( see page 1356).

3.2.1.5.5 Excluding Blank Cells


As the calendar is written, the user can select a blank cell, but the date does not change. It makes sense, then, to disallow
selection of the blank cells.

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.

3.2.1.5.6 Filling in the Cells


A grid control fills in its contents cell-by-cell. In the case of the calendar, that means calculating which date, if any, belongs in
each cell. The default drawing for grid cells takes place in a virtual method called DrawCell.

To fill in the contents of grid cells, override the DrawCell method.

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);
}

3.2.1.5.7 Generating the Day Numbers


Putting numbers into the calendar involves several considerations. The number of days in the month depends on which month it
is, and whether the given year is a leap year. In addition, months start on different days of the week, dependent on the month
and year. Use the IsLeapYear function to determine whether the year is a leap year. Use the MonthDays array in the SysUtils
unit to get the number of days in the month.

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.

To fill in the days in the proper cells, you do the following:


1. Add a month-offset field to the object and a method that updates the field value:
type
TSampleCalendar = class(TCustomGrid)
private
FMonthOffset: Integer; { storage for the offset }
.
.
.
protected
procedure UpdateCalendar; virtual; { property for offset access }
end;
.
.
.
procedure TSampleCalendar.UpdateCalendar;
var
AYear, AMonth, ADay: Word;
FirstDate: TDateTime; { date of the first day of the month }
begin
if FDate <> 0 then { only calculate offset if date is valid }
begin
DecodeDate(FDate, AYear, AMonth, ADay); { get elements of date }
FirstDate := EncodeDate(AYear, AMonth, 1); { date of the first }
FMonthOffset := 2 - DayOfWeek(FirstDate); { generate the offset into the grid }
end;
3 Refresh; { always repaint the control }
end;
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
int FMonthOffset; // storage for the offset
.
.
.
protected:
virtual void __fastcall UpdateCalendar(void);

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

if (Result < 1) or (Result > MonthDays[IsLeapYear(Year), Month]) then


Result := -1; { return -1 if invalid }
end;
int __fastcall TSampleCalendar::DayNum(int ACol, int ARow)
{
int result = FMonthOffset + ACol + (ARow - 1) * 7; // calculate day for this cell
if ((result < 1)||(result > MonthDays[IsLeapYear(Year)][Month]))
result = -1; // return -1 if invalid
return result;
}
Remember to add the declaration of DayNum to the component's type declaration.

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.

3.2.1.5.8 Moving the Selection


The inherited behavior of a grid handles moving the selection in response to either arrow keys or clicks, but if you want to
change the selected day, you need to modify that default behavior.
3
To handle movements within the calendar, override the Click method of the grid.

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
}

3.2.1.5.9 Navigating Days


Within a given month, there are two obvious ways to navigate among the days. The first is to use the arrow keys, and the other is
to respond to clicks of the mouse. The standard grid component handles both as if they were clicks. That is, an arrow movement
is treated like a click on an adjacent cell.

The process of navigating days consists of

• Moving the selection ( see page 1268)


• Providing an OnChange event ( see page 1270)
• Excluding blank cells ( see page 1265)

3.2.1.5.10 Navigating Months and Years


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 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.

3.2.1.5.11 Providing an OnChange Event


Now that users of the calendar can change the date within the calendar, it makes sense to allow applications to respond to those
changes.

Add an OnChange event to TSampleCalendar.


1. Declare the event, a field to store the event, and a dynamic method to call the event:
type
TSampleCalendar = class(TCustomGrid)
private
FOnChange: TNotifyEvent;
protected
procedure Change; dynamic;
.
.
.
published
property OnChange: TNotifyEvent read FOnChange write FOnChange;
.
.
.
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
TNotifyEvent FOnChange;
.
.
.
protected:
virtual void __fastcall Change();
__published:
__property TNotifyEvent OnChange = {read=FOnChange, write=FOnChange};
.
.
.
}
3 2. Write the Change method:
procedure TSampleCalendar.Change;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
void __fastcall TSampleCalendar::Change()
{
if(FOnChange != NULL) FOnChange(this);
}

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.

3.2.1.5.12 Publishing Inherited Properties (Grid)


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:
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.

3.2.1.5.13 Resizing the Cells


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, 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

3.2.1.5.14 Selecting the Current Day


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:
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.

3.2.1.5.15 Storing the Internal Date


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.

Adding the internal date to the calendar requires three steps:


1. Declare a private field to hold the date:
type
TSampleCalendar = class(TCustomGrid)
private
FDate: TDateTime;
.
.
3 .
class PACKAGE TSampleCalendar : public TCustomGrid
{
public:
__property TDateTime CalendarDate = {read=FDate, write=SetCalendarDate, nodefault};
.
.
.
};
class PACKAGE TSampleCalendar : public TCustomGrid

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

Tracking the date in the calendar consists of the processes:

• Storing the internal date ( see page 1274)


• Accessing the day ( see page 1260)
• Generating the day numbers ( see page 1266)
• Selecting the current day ( see page 1274)

3.2.1.6 Extending the IDE


Topics
Name Description
Adding an Action to the Action List ( see page 1278) The image index obtained in Adding an image to the image list ( see page
1279) is used to create an action, as shown below. The wizard uses the
OnExecute and OnUpdate events. A common scenario is for a wizard to use the
OnUpdate event to enable or disable the action. Be sure the OnUpdate event
returns quickly, or the user will notice that the IDE becomes sluggish after loading
your wizard. The action's OnExecute event is similar to the wizard's Execute
method. If you are using a menu item to invoke a form or project wizard, you
might even want to have OnExecute... more ( see page 1278)
Adding an Image to the Image List ( see page 1279) Suppose you want to add a menu item to invoke your wizard. You also want to
enable the user to add a toolbar button that invokes the wizard. The first step is
to add an image to the IDE's image list. The index of your image can then be
used for the action, which in turn is used by the menu item and toolbar button.
Create a resource file that contains a 16 by 16 bitmap resource. Add the
following code to your wizard's constructor:
Creating Forms and Projects ( see page 1279) Delphi comes with a number of form and project wizards already installed, and
you can write your own. The Object Repository lets you create static templates
that can be used in a project, but a wizard offers much more power because it is
dynamic. The wizard can prompt the user and create different kinds of files
depending on the user's responses.
A form or project wizard typically creates one or more new files. Instead of real
files, however, it is best to create unnamed, unsaved modules. When the user
saves them, the IDE prompts the user for a file name.... more ( see page 1279)
Debugging a Wizard ( see page 1284) The Tools API provides you with a lot of flexibility in how your wizard interacts
with the IDE. With the flexibility comes responsibility, however. It is easy to wind
up with dangling pointers or other access violations.
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... more ( see page 1284)
Deleting Toolbar Buttons ( see page 1284) There is no convenient function for removing a button from a toolbar; you must
send the CM_CONTROLCHANGE message, where the first parameter is the
control to change, and the second parameter is zero to remove it or non-zero to
add it to the toolbar. After removing the toolbar buttons, the destructor deletes
the action and menu item. Deleting these items automatically removes them from
the IDE's ActionList and MainMenu.
Extending the IDE ( see page 1285) You can extend and customize the IDE with your own menu items, tool bar
buttons, dynamic form-creation wizards, and more, using the Open Tools API
(often shortened to just Tools API). The Tools API is a suite of over 100
interfaces that interact with and control the IDE, including the main menu, the tool
bars, the main action list and image list, the source editor's internal buffers,
keyboard macros and bindings, forms and their components in the form editor,
the debugger and the process being debugged, code completion, the message
view, and the To-Do list.
3 Using the Tools API is... more ( see page 1285)
Implementing the Wizard Interfaces ( see page 1286) Every wizard class must implement at least IOTAWizard, which requires
implementing its ancestors, too: IOTANotifier and IInterface. Form and project
wizards must implement all their ancestor interfaces, namely,
IOTARepositoryWizard, IOTAWizard, IOTANotifier, and IInterface.
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... more
( see page 1286)

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

3.2.1.6.1 Adding an Action to the Action List


The image index obtained in Adding an image to the image list ( see page 1279) is used to create an action, as shown below.
The wizard uses the OnExecute and OnUpdate events. A common scenario is for a wizard to use the OnUpdate event to enable
or disable the action. Be sure the OnUpdate event returns quickly, or the user will notice that the IDE becomes sluggish after
loading your wizard. The action's OnExecute event is similar to the wizard's Execute method. If you are using a menu item to
invoke a form or project wizard, you might even want to have OnExecute call Execute directly.
NewAction := TAction.Create(nil);
NewAction.ActionList := Services.ActionList;
NewAction.Caption := GetMenuText();
NewAction.Hint := 'Display a silly dialog box';
NewAction.ImageIndex := ImageIndex;
NewAction.OnUpdate := action_update;
NewAction.OnExecute := action_execute;
action = new TAction(0);
action->ActionList = services->ActionList;
action->Caption = GetMenuText();
action->Hint = "Display a silly dialog box";
action->ImageIndex = image;
action->OnUpdate = action_update;
action->OnExecute = action_execute;
The menu item sets its Action property to the newly created action. The tricky part of creating the menu item is knowing where to
insert it. The example below looks for theView menu, and inserts the new menu item as the first item in the View menu. (In
general, relying on absolute position is not a good idea: you never know when another wizard might insert itself in the menu.
Future versions of Delphi are likely to reorder the menu, too. A better approach is to search the menu for a menu item with a
specific name. The simplistic approach follows for the sake of clarity.)
for I := 0 to Services.MainMenu.Items.Count - 1 do
begin
with Services.MainMenu.Items[I] do
begin
if CompareText(Name, 'ViewsMenu') = 0 then
begin
NewItem := TMenuItem.Create(nil);
NewItem.Action := NewAction;
Insert(0, NewItem);
end;
end;
end;
for (int i = 0; i < services->MainMenu->Items->Count; ++i)
{
TMenuItem* item = services->MainMenu->Items->Items[i];
if (CompareText(item->Name, "ViewsMenu") == 0)
{
menu_item = new TMenuItem(0);
3 menu_item->Action = action;
item->Insert(0, menu_item);
}
}
By adding the action to the IDE's action list, the user can see the action when customizing the toolbars. The user can select the
action and add it as a button to any toolbar. This causes a problem when your wizard is unloaded: all the tool buttons end up
with dangling pointers to the non-existent action and OnClick event handler. To prevent access violations, your wizard must find
all tool buttons that refer to its action, and remove those buttons.

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)

Deleting Toolbar Buttons ( see page 1284)

3.2.1.6.2 Adding an Image to the Image List


Suppose you want to add a menu item to invoke your wizard. You also want to enable the user to add a toolbar button that
invokes the wizard. The first step is to add an image to the IDE's image list. The index of your image can then be used for the
action, which in turn is used by the menu item and toolbar button. Create a resource file that contains a 16 by 16 bitmap
resource. Add the following code to your wizard's constructor:
constructor MyWizard.Create;
var
Services: INTAServices;
Bmp: TBitmap;
ImageIndex: Integer;
begin
inherited;
Supports(BorlandIDEServices, INTAServices, Services);
{ Add an image to the image list. }
Bmp := TBitmap.Create;
Bmp.LoadFromResourceName(HInstance, 'Bitmap1');
ImageIndex := Services.AddMasked(Bmp, Bmp.TransparentColor,
'Tempest Software.intro wizard image');
Bmp.Free;
end;
_di_INTAServices services;
BorlandIDEServices->Supports(services);
// Add an image to the image list.
Graphics::TBitmap* bitmap(new Graphics::TBitmap());
bitmap->LoadFromResourceName(reinterpret_cast<unsigned>(HInstance), "Bitmap1");
int image = services->AddMasked(bitmap, bitmap->TransparentColor,
"Tempest Software.intro wizard image");
delete bitmap;
Be sure to load the resource by the name or ID you specify in the resource file. You must choose a color that will be interpreted
as the background color for the image. If you don't want a background color, choose a color that does not exist in the bitmap.

See Also
Adding an Action to the Action List ( see page 1278)

Deleting Toolbar Buttons ( see page 1284)

3.2.1.6.3 Creating Forms and Projects


Delphi comes with a number of form and project wizards already installed, and you can write your own. The Object Repository
lets you create static templates that can be used in a project, but a wizard offers much more power because it is dynamic. The
wizard can prompt the user and create different kinds of files depending on the user's responses.
3
A form or project wizard typically creates one or more new files. Instead of real files, however, it is best to create unnamed,
unsaved modules. When the user saves them, the IDE prompts the user for a file name. A wizard uses a creator object to create
such modules.

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

const AnsiString ModuleIdent, const AnsiString FormIdent,


const AnsiString AncestorIdent);
virtual _di_IOTAFile __fastcall NewIntfSource(
const AnsiString ModuleIdent, const AnsiString FormIdent,
const AnsiString AncestorIdent);
virtual void __fastcall FormCreated(
const _di_IOTAFormEditor FormEditor);
// IOTACreator
virtual AnsiString __fastcall GetCreatorType();
virtual bool __fastcall GetExisting();
virtual AnsiString __fastcall GetFileSystem();
virtual _di_IOTAModule __fastcall GetOwner();
virtual bool __fastcall GetUnnamed();
protected:
// IInterface
virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
private:
long ref_count;
const AnsiString creator_type;
};
Most of the members of TCreator return zero, nil, or empty strings. The boolean methods return true, except GetExisting, which
returns false. The most interesting method is GetOwner, which returns a pointer to the current project module, or nil if there is no
project. There is no simple way to discover the current project or the current project group. Instead, GetOwner must iterate over
all open modules. If a project group is found, it must be the only project group open, so GetOwner returns its current project.
Otherwise, the function returns the first project module it finds, or nil if no projects are open.
function TCreator.GetOwner: IOTAModule;
var
I: Integer;
Svc: IOTAModuleServices;
Module: IOTAModule;
Project: IOTAProject;
Group: IOTAProjectGroup;
begin
{ Return the current project. }
Supports(BorlandIDEServices, IOTAModuleServices, Svc);
Result := nil;
for I := 0 to Svc.ModuleCount - 1 do
begin
Module := Svc.Modules[I];
if Supports(Module, IOTAProject, Project) then
begin
{ Remember the first project module}
if Result = nil then
Result := Project;
end
else if Supports(Module, IOTAProjectGroup, Group) then
begin
{ Found the project group, so return its active project}
Result := Group.ActiveProject;
Exit;
end;
end; 3
end;
_di_IOTAModule __fastcall Creator::GetOwner()
{
// Return the current project.
_di_IOTAProject result = 0;
_di_IOTAModuleServices svc = interface_cast<IOTAModuleServices>(BorlandIDEServices);
for (int i = 0; i < svc->ModuleCount; ++i)
begin
_di_IOTAModule module = svc->Modules[i];

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)

3.2.1.6.4 Debugging a Wizard


The Tools API provides you with a lot of flexibility in how your wizard interacts with the IDE. With the flexibility comes
responsibility, however. It is easy to wind up with dangling pointers or other access violations.

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)

3.2.1.6.5 Deleting Toolbar Buttons


There is no convenient function for removing a button from a toolbar; you must send the CM_CONTROLCHANGE message,
where the first parameter is the control to change, and the second parameter is zero to remove it or non-zero to add it to the
toolbar. After removing the toolbar buttons, the destructor deletes the action and menu item. Deleting these items automatically
removes them from the IDE's ActionList and MainMenu.
procedure remove_action (Action: TAction; ToolBar: TToolBar);
var
I: Integer;
Btn: TToolButton;
begin
for I := ToolBar.ButtonCount - 1 downto 0 do
begin
Btn := ToolBar.Buttons[I];
if Btn.Action = Action then
begin
{ Remove "Btn" from "ToolBar" }
ToolBar.Perform(CM_CONTROLCHANGE, WPARAM(Btn), 0);
Btn.Free;
3 end;
end;
end;
destructor MyWizard.Destroy;
var
Services: INTAServices;
Btn: TToolButton;
begin
Supports(BorlandIDEServices, INTAServices, Services);
{ Check all the toolbars, and remove any buttons that use this action. }
remove_action(NewAction, Services.ToolBar[sCustomToolBar]);

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)

Adding an Action to the Action List ( see page 1278)

3.2.1.6.6 Extending the IDE


You can extend and customize the IDE with your own menu items, tool bar buttons, dynamic form-creation wizards, and more,
using the Open Tools API (often shortened to just Tools API). The Tools API is a suite of over 100 interfaces that interact with
and control the IDE, including the main menu, the tool bars, the main action list and image list, the source editor's internal
buffers, keyboard macros and bindings, forms and their components in the form editor, the debugger and the process being
debugged, code completion, the message view, and the To-Do list.

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

• Overview of the Tools API ( see page 1294)


• Writing a wizard class ( see page 1297)
• Obtaining Tools API services ( see page 1293)
• Working with files and editors ( see page 1297)
• Creating forms and projects ( see page 1279)
• Notifying a wizard of IDE events ( see page 1289)
See Also
Making Components Available at Design Time: Overview ( see page 1350)

3.2.1.6.7 Implementing the Wizard Interfaces


Every wizard class must implement at least IOTAWizard, which requires implementing its ancestors, too: IOTANotifier and
IInterface. Form and project wizards must implement all their ancestor interfaces, namely, IOTARepositoryWizard, IOTAWizard,
IOTANotifier, and IInterface.

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.

You can write a class similar to TNotifierObject in C++.


class PACKAGE NotifierObject : public IOTANotifier {
public:
__fastcall NotifierObject() : ref_count(0) {}
virtual __fastcall ~NotifierObject();
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();
private:
long ref_count;
};
// implementation
ULONG __stdcall NotifierObject::AddRef()
{
return InterlockedIncrement(&ref_count);
}
ULONG __stdcall NotifierObject::Release()
{
ULONG result = InterlockedDecrement(&ref_count);
if (ref_count == 0)
delete this;
return result;
}
HRESULT __stdcall NotifierObject::QueryInterface(const GUID& iid, void** obj)
{
if (iid == __uuidof(IInterface)) {
*obj = static_cast<IInterface*>(this);
static_cast<IInterface*>(*obj)->AddRef();
return S_OK;
}
if (iid == __uuidof(IOTANotifier)) {
*obj = static_cast<IOTANotifier*>(this);
static_cast<IOTANotifier*>(*obj)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
Although wizards inherit from IOTANotifier, and must therefore implement all of its functions, the IDE does not usually make use
of those functions, so your implementations can be empty (as they are in TNotifierObject). Thus, when you write your wizard
class, you need only declare and implement those interface methods introduced by the wizard interfaces, accepting the
TNotifierObject implementation of IOTANotifier.
// C++ empty implementations
3
void __fastcall NotifierObject::AfterSave() {}
void __fastcall NotifierObject::BeforeSave() {}
void __fastcall NotifierObject::Destroyed() {}
void __fastcall NotifierObject::Modified() {}
See Also
Installing the Wizard Package ( see page 1288)

1287
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

3.2.1.6.8 Installing the Wizard Package


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:
procedure Register;
begin
RegisterPackageWizard(MyWizard.Create);
RegisterPackageWizard(MyOtherWizard.Create);
end;
namespace Example {
void __fastcall PACKAGE Register()
{
RegisterPackageWizard(new MyWizard());
RegisterPackageWizard(new MyOtherWizard());
}
}
You can also register property editors, components, and so on, as part of the same package.

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)

3.2.1.6.9 Interface Version Numbers


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 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)

3.2.1.6.10 Notifying a Wizard of IDE Events


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 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

TModuleIdentifier = class(TNotifierObject, IOTAModuleNotifier)


public
constructor Create(const Module: IOTAModule);
destructor Destroy; override;
function CheckOverwrite: Boolean;
procedure ModuleRenamed(const NewName: string);
procedure Destroyed;
private
FModule: IOTAModule;
FName: string;
FIndex: Integer;
end;
class ModuleNotifier : public NotifierObject, public IOTAModuleNotifier
{
typedef NotifierObject inherited;
public:
__fastcall ModuleNotifier(const _di_IOTAModule module);
__fastcall ~ModuleNotifier();
// IOTAModuleNotifier
virtual bool __fastcall CheckOverwrite();
virtual void __fastcall ModuleRenamed(const AnsiString NewName);
// IOTANotifier
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();
private:
_di_IOTAModule module;
AnsiString name; // Remember the module's old name.
int index; // Notifier index.
};
One way to write a notifier is to have it register itself automatically in its constructor. The destructor unregisters the notifier. In the
case of a module notifier, the IDE calls the Destroyed method when the user closes the file. In that case, the notifier must
unregister itself and release its reference to the module interface. The IDE releases its reference to the notifier, which reduces its
reference count to zero and frees the object. Therefore, you need to write the destructor defensively: the notifier might already be
unregistered.
constructor TModuleNotifier.Create( const Module: IOTAModule);
begin
FIndex := -1;
FModule := Module;
{ Register this notifier. }
FIndex := Module.AddNotifier(self);
{ Remember the module's old name. }
FName := ChangeFileExt(ExtractFileName(Module.FileName), '');
end;
destructor TModuleNotifier.Destroy;
begin
{ Unregister the notifier if that hasn't happened already. }
3 if Findex >= 0 then
FModule.RemoveNotifier(FIndex);
end;
procedure TModuleNotifier.Destroyed;
begin
{ The module interface is being destroyed, so clean up the notifier. }
if Findex >= 0 then
begin
{ Unregister the notifier. }
FModule.RemoveNotifier(FIndex);
FIndex := -1;

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)

Using Module Interfaces ( see page 1296)

3.2.1.6.11 Obtaining Tools API Services


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 3


Interface Description
INTAServices Provides access to native IDE objects: main menu, action list, image list, and tool bars.
IOTAActionServices Performs basic file actions: open, close, save, and reload a file.
IOTACodeCompletionServices Provides access to code completion, allowing a wizard to install a custom code completion
manager.

1293
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

IOTADebuggerServices Provides access to debugger.


IOTAEditorServices Provides access to source code editor and its internal buffers.
IOTAKeyBindingServices Permits a wizard to register custom keyboard bindings.
IOTAKeyboardServices Provides access to keyboard macros and bindings.
IOTAKeyboardDiagnostics Toggle debugging of keystrokes.
IOTAMessageServices Provides access to message view.
IOTAModuleServices Provides access to open files.
IOTAPackageServices Queries the names of all installed packages and their components.
IOTAServices Miscellaneous services.
IOTAToDoServices Provides access to the To-Do list, allowing a wizard to install a custom To-Do manager.
IOTAToolsFilter Registers tools filter notifiers.
IOTAWizardServices Registers and unregisters wizards.

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:

• Using native IDE objects ( see page 1297)


• Debugging a wizard ( see page 1284)
• Interface version numbers ( see page 1288)
See Also
Working with Files and Editors ( see page 1297)

Creating Forms and Projects ( see page 1279)

Notifying a Wizard of IDE Events ( see page 1289)

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.

3.2.1.6.13 Using Editor Interfaces


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:
{ Return the form editor for a module, or nil if the unit has no form. }
function GetFormEditor(Module: IOTAModule): IOTAFormEditor;
var
I: Integer;
Editor: IOTAEditor; 3
begin
for I := 0 to Module.ModuleFileCount - 1 do
begin
Editor := Module.ModuleFileEditors[I];
if Supports(Editor, IOTAFormEditor, Result) then
Exit;
end;
Result := nil;
end;

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)

3.2.1.6.14 Using Module Interfaces


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:
{ 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)

3.2.1.6.15 Using Native IDE Objects


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 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 illustrate how to perform these tasks:

• Adding an image to the image list ( see page 1279)


• Adding an action to the action list ( see page 1278)
• Deleting toolbar buttons ( see page 1284)

3.2.1.6.16 Working with Files and Editors


It is important to understand how the Tools API works with files. The main 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 topics provide information about the module and editor interfaces:

• Using module interfaces ( see page 1296)


• Using editor interfaces ( see page 1295)
See Also
Obtaining Tools API Services ( see page 1293)

Creating Forms and Projects ( see page 1279)

Notifying a Wizard of IDE Events ( see page 1289)


3

3.2.1.6.17 Writing a Wizard Class


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

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)

3.2.1.7 Handling messages


Topics
Name Description
Broadcasting a Message to All Controls in a Form ( see page 1301) When your component changes global settings that affect all of the controls in a
form or other container, you may want to send a message to those controls so
that they can update themselves appropriately. Not every control may need to
respond to the notification, but by broadcasting the message, you can inform all
controls that know how to respond and allow the other controls to ignore the
message.
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... more ( see page 1301)
Calling a Control's Message Handler Directly ( see page 1302) Sometimes there is only a single control that needs to respond to your message.
If you know the control that should receive your message, the simplest and most
straightforward way to send the message is to call the control's Perform method.
There are two main reasons why you call a control's Perform method:

3 • 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... more ( see page 1302)

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:

• Broadcasting a message to all controls in a form. ( see


page 1301)
• Calling a control's message handler directly. ( see page
1302)
• Sending a message using the Windows message queue.
( see page 1303)... more ( see page 1303)
Changing Message Handling ( see page 1304) Before changing the message handling of your components, make sure that is
what you really want to do. The VCL translates most Windows messages into
events that both the component writer and the component user can handle.
Rather than changing the message-handling behavior, you should probably
change the event-handling behavior.
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.
Creating New Message Handlers ( see page 1304) Because the VCL provides handlers for most common messages, the time you
will most likely need to create new message handlers is when you define your
own messages. Working with user-defined messages has three aspects:

• Defining your own messages. ( see page 1306)


• Declaring a new message-handling method. ( see page
1305)
• Sending messages. ( see page 1303)
Declaring a Message Identifier ( see page 1304) A message identifier is an integer-sized constant. Windows reserves the 3
messages below 1,024 for its own use, so when you declare your own messages
you should start above that level.
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... more ( see page
1304)
Example: User-defined Messages ( see page 1304) The following code shows two user-defined 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:

• 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.
Example: Message Handler ( see page 1306) Here is the declaration of a message handler for a user-defined message called
CM_CHANGECOLOR.
Defining Your Own Messages ( see page 1306) A number of the standard components define messages for internal use. The
most common reasons for defining messages are broadcasting information not
covered by standard messages and notification of state changes. You can define
your own messages in the VCL.
Defining a message is a two-step process. The steps are:

1. Declaring a message identifier. ( see page 1304)


2. Declaring a message-record type. ( see page 1305)
Dispatching Messages ( see page 1306) When an application creates a window, it registers a window procedure with the
Windows kernel. The window procedure is the routine that handles messages for
the window. Traditionally, the window procedure contains a huge case statement
with entries for each message the window has to handle. Keep in mind that
"window" in this sense means just about anything on the screen: each window,
each control, and so on. Every time you create a new type of window, you have
to create a complete window procedure.
The VCL simplifies message dispatching in several ways:

• Each component inherits a complete


message-dispatching system.... more ( see page 1306)
Example: Overriding a Message Handler ( see page 1307) For example, to override a component's handling of the WM_PAINT message,
you redeclare the WMPaint method:
Overriding the Handler Method ( see page 1307) To change the way a component handles a particular message, you override the
message-handling method for that message. If the component does not already
handle the particular message, you need to declare a new message-handling
method.
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.
Note that the name of the method and the type of the single var parameter do
not have to match the overridden method. Only... more ( see page 1307)
Handling Messages and System Notifications: Overview ( see page 1308) Components often need to respond to notifications from the underlying operating
system. The operating system informs the application of occurrences such as
what the user does with the mouse and keyboard. Some controls also generate
notifications, such as the results from user actions such as selecting an item in a
list box. The component library handles most of the common notifications
already. It is possible, however, that you will need to write your own code for
handling such notifications.
3 For VCL applications, notifications arrive in the form of messages. These
messages can come from any source, including Windows, VCL... more ( see
page 1308)
Trapping Messages ( see page 1308) Under some circumstances, you might want your components to ignore
messages. That is, you want to keep the component from dispatching the
message to its handler. To trap a message, you override the virtual method
WndProc.
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:

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:

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... more
( see page 1309)
Using Message Parameters ( see page 1309) Once inside a message-handling method, your component has access to all the
parameters of the message structure. Because the parameter passed to the
message handler is a var parameter, the handler can change the values of the
parameters if necessary. The only parameter that changes frequently is the
Result field for the message: the value returned by the SendMessage call that
sends the message.
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... more ( see page 1309)
What's in a Windows Message? ( see page 1309) A Windows message is a data record that contains several fields. The most
important of these is an integer-size value that identifies the message. Windows
defines many messages, and the Messages unit declares identifiers for all of
them. Other useful information in a message comes in two parameter fields and a
result field.
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... more ( see page 1309)

3.2.1.7.1 Broadcasting a Message to All Controls in a Form


When your component changes global settings that affect all of the controls in a form or other container, you may want to send a
message to those controls so that they can update themselves appropriately. Not every control may need to respond to the
notification, but by broadcasting the message, you can inform all controls that know how to respond and allow the other controls
to ignore the message.

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

It can be the active form:


Screen.ActiveForm.Broadcast(Msg);
Screen->ActiveForm->Broadcast(Msg);
It can even be all the forms in your application:
for I:= 0 to Screen.FormCount - 1 do
Screen.Forms[I].Broadcast(Msg);
for (int i = 0; i < Screen->FormCount; i++)
Screen->Forms[i]->Broadcast(Msg);
See Also
Sending a Message That Does Not Execute Immediately ( see page 1303)

Sending a Message Using the Windows Message Queue ( see page 1303)

3.2.1.7.2 Calling a Control's Message Handler Directly


Sometimes there is only a single control that needs to respond to your message. If you know the control that should receive your
message, the simplest and most straightforward way to send the message is to call the control's Perform method.

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)

Broadcasting a Message to All Controls in a Form ( see page 1301)

Sending a Message Using the Windows Message Queue ( see page 1303)

3.2.1.7.3 Responding to System Events


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
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:

• Commonly used events


• Overriding the EventFilter method
• Generating Qt events

3.2.1.7.4 Sending a Message That Does Not Execute Immediately


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 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)

3.2.1.7.5 Sending a Message Using the Windows Message Queue


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, 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)

Broadcasting a Message to All Controls in a Form ( see page 1301)

3.2.1.7.6 Sending Messages


Typically, an application sends message to send notifications of state changes or to broadcast information. Your component can

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:

• Broadcasting a message to all controls in a form. ( see page 1301)


• Calling a control's message handler directly. ( see page 1302)
• Sending a message using the Windows message queue. ( see page 1303)
• Sending a message that does not execute immediately. ( see page 1303)

3.2.1.7.7 Changing Message Handling


Before changing the message handling of your components, make sure that is what you really want to do. The VCL translates
most Windows messages into events that both the component writer and the component user can handle. Rather than changing
the message-handling behavior, you should probably change the event-handling behavior.

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.

3.2.1.7.8 Creating New Message Handlers


Because the VCL provides handlers for most common messages, the time you will most likely need to create new message
handlers is when you define your own messages. Working with user-defined messages has three aspects:

• Defining your own messages. ( see page 1306)


• Declaring a new message-handling method. ( see page 1305)
• Sending messages. ( see page 1303)

3.2.1.7.9 Declaring a Message Identifier


A message identifier is an integer-sized constant. Windows reserves the messages below 1,024 for its own use, so when you
declare your own messages you should start above that level.

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.

3.2.1.7.10 Example: User-defined Messages


3 The following code shows two user-defined messages.
const
MY_MYFIRSTMESSAGE = WM_APP + 400;
MY_MYSECONDMESSAGE = WM_APP + 401;
#define MY_MYFIRSTMESSAGE (WM_APP + 400)
#define MY_MYSECONDMESSAGE (WM_APP + 401)

1304
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

3.2.1.7.11 Example: Message Structure


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.
type
TWMMouse = record
Msg: TMsgParam; ( first is the message ID )
Keys: Word; ( this is the wParam )
case Integer of ( two ways to look at the lParam )
0: {
XPos: Integer; ( either as x- and y-coordinates...)
YPos: Integer);
1: {
Pos: TPoint; ( ... or as a single point )
Result: Longint); ( and finally, the result field )
end;
struct TWMKey
{
Cardinal Msg; // first parameter is the message ID
Word CharCode; // this is the first wParam
Word Unused;
Longint KeyData; // this is the lParam
Longint Result; // this is the result data member
};

3.2.1.7.12 Declaring a Message-structure Type


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.

To declare a message-record type, follow these conventions:


1. Name the record type after the message, preceded by a T.
2. Call the first field in the record Msg, of type TMsgParam.
3. Define the next two bytes to correspond to the Word parameter, and the next two bytes as unused. Or Define the next four
bytes to correspond to the Longint parameter.
4. Add a final field called Result, of type Longint.

3.2.1.7.13 Declaring a New Message-handling Method


There are two sets of circumstances that require you to declare new message-handling methods:

• 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

6. Call the inherited message handler.

3.2.1.7.14 Example: Message Handler


Here is the declaration of a message handler for a user-defined message called CM_CHANGECOLOR.
const
CM_CHANGECOLOR = WM_APP + 400;
type
TMyComponent = class(TControl)
.
.
.
protected
procedure CMChangeColor(var Message: TMessage); message CM_CHANGECOLOR;
end;
procedure TMyComponent.CMChangeColor(var Message: TMessage);
begin
Color := Message.lParam;
inherited;
end;
#define CM_CHANGECOLOR (WM_APP + 400)
class TMyControl : public TControl
{
protected:
void __fastcall CMChangeColor(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_CHANGECOLOR, TMessage, CMChangeColor)
END_MESSAGE_MAP(TControl)
};
void __fastcall TMyControl::CMChangeColor(TMessage &Message)
{
Color = Message.LParam; // set color from long parameter
TControl::CMChangeColor(Message); // call the inherited message handler
}

3.2.1.7.15 Defining Your Own Messages


A number of the standard components define messages for internal use. The most common reasons for defining messages are
broadcasting information not covered by standard messages and notification of state changes. You can define your own
messages in the VCL.

Defining a message is a two-step process. The steps are:

1. Declaring a message identifier. ( see page 1304)


2. Declaring a message-record type. ( see page 1305)

3.2.1.7.16 Dispatching Messages


When an application creates a window, it registers a window procedure with the Windows kernel. The window procedure is the
3 routine that handles messages for the window. Traditionally, the window procedure contains a huge case statement with entries
for each message the window has to handle. Keep in mind that "window" in this sense means just about anything on the screen:
each window, each control, and so on. Every time you create a new type of window, you have to create a complete window
procedure.

The VCL simplifies message dispatching in several ways:

• Each component inherits a complete message-dispatching system.


• The dispatch system has default handling. You define handlers only for messages you need to respond to specially.

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.

3.2.1.7.17 Example: Overriding a Message Handler


For example, to override a component's handling of the WM_PAINT message, you redeclare the WMPaint method:
type
TMyComponent = class(...)
.
.
.
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
end;
class PACKAGE TMyComponent : public TComponent
{
protected:
void __fastcall WMPaint(TWMPaint* Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_PAINT, TWMPaint, WMPaint)
END_MESSAGE_MAP(TComponent)
};

3.2.1.7.18 Overriding the Handler Method


To change the way a component handles a particular message, you override the message-handling method for that message. If
the component does not already handle the particular message, you need to declare a new message-handling method.

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

3.2.1.7.19 Handling Messages and System Notifications: Overview


Components often need to respond to notifications from the underlying operating system. The operating system informs the
application of occurrences such as what the user does with the mouse and keyboard. Some controls also generate notifications,
such as the results from user actions such as selecting an item in a list box. The component library handles most of the common
notifications already. It is possible, however, that you will need to write your own code for handling such notifications.

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:

• Understanding the message-handling system. ( see page 1309)


• Changing message handling. ( see page 1304)
• Creating new message handlers. ( see page 1304)

3.2.1.7.20 Trapping Messages


Under some circumstances, you might want your components to ignore messages. That is, you want to keep the component
from dispatching the message to its handler. To trap a message, you override the virtual method WndProc.

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.

3.2.1.7.21 The WndProc Method


Note: This information is applicable when writing VCL components only.

Here is part of the WndProc method for TControl, for example:

3 procedure TControl.WndProc(var Message: TMessage);


begin
.
.
.
if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
if Dragging then { handle dragging specially }
DragMouseMsg(TWMMouse(Message))
else
. { handle others normally }
.

1308
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

.
end;
. { otherwise process normally }
.
.
end;

3.2.1.7.22 Understanding the message-handling system


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:

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.

3.2.1.7.23 Using Message Parameters


Once inside a message-handling method, your component has access to all the parameters of the message structure. Because
the parameter passed to the message handler is a var parameter, the handler can change the values of the parameters if
necessary. The only parameter that changes frequently is the Result field for the message: the value returned by the
SendMessage call that sends the message.

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.

3.2.1.7.24 What's in a Windows Message?


A Windows message is a data record that contains several fields. The most important of these is an integer-size value that
identifies the message. Windows defines many messages, and the Messages unit declares identifiers for all of them. Other
useful information in a message comes in two parameter fields and a result field.

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 );
.
.
.
}

3.2.1.8 Introduction to component creation


Topics
Name Description
Overview of Component Creation ( see page 1313) This set of topics provides an overview of component design and the process of
writing components for Delphi applications. The material here assumes that you
are familiar with Delphi and its standard components.
The main topics discussed are

• Class library ( see page 1314)


• Components and classes ( see page 1315)
• Creating components ( see page 1315)
• What goes into a component? ( see page 1323)
• Creating a new component ( see page 1317)
• Testing uninstalled components ( see page 1324)
• Testing installed components ( see page 1324)
For information on installing new components, see Installing
component packages ( see page 2217).
Class library ( see page 1314) Delphi's components reside in the Visual Component Library (VCL) . The
following figure shows the relationship of selected classes that make up the VCL
hierarchy. For a more detailed discussion of class hierarchies and the inheritance
relationships among classes, see Object-oriented programming for component
writers ( see page 1369)
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...
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,

• 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.
Creating Components ( see page 1315) A component can be almost any program element that you want to manipulate at
design time. Creating a component means deriving a new class from an existing
one. You can derive a new component in several ways:

• Modifying existing controls ( see page 1316)


• Creating windowed controls ( see page 1316)
• Creating graphic controls ( see page 1318)
• Subclassing Windows controls ( see page 1321)
• Creating nonvisual components ( see page 1318)
The following table summarizes the different kinds of
components and the classes you use as starting points for
each.
Component creation starting points
Modifying Existing Controls ( see page 1316) The simplest way to create a component is to customize an existing one. You
can derive a new component from any of the components provided in the
component library.
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)...
more ( see page 1316)
Creating Original Controls ( see page 1316) Windowed controls in the component library are objects that appear at runtime
and that the user can interact with. Each windowed control has a window handle,
accessed through its Handle property, that lets the operating system identify and
operate on the control. If using VCL controls, the handle allows the control to
receive input focus and can be passed to Windows API functions. Each
widget-based control has a handle, accessed through its Handle property, that
identifies the underlying widget.-->
All windowed controls descend from the TWinControlclass. These include most
standard windowed controls, such as pushbuttons, list boxes, and edit... more (
see page 1316)
Creating a New Component ( see page 1317) This topic describes how to create and setup a component.
Creating a Unit File ( see page 1317) A unit is a separately compiled module of Delphi code. Delphi uses units for
several purposes. Every form has its own unit, and most components (or groups
of related components) have their own units as well.
When you create a component, you either create a new unit for the component or
add the new component to an existing unit. 3
Declaring A New Constructor (C++) ( see page 1318) Each new component must have a constructor that overrides the constructor of
the class from which it was derived. When you write the constructor for your new
component, it must always call the inherited constructor.
Within the class declaration, declare a virtual constructor in the public section of
the class.
For example,

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:

• The class from which the component is derived.


• The class name for the new component.
• The Tool palette category where you want it to appear.
• The name of the unit in which the component is created.
• The search path where the unit is found.
• The name of the package in which you want to place the
component.
The Component wizard performs the same tasks you would
when creating a component manually:
• Creating a unit.
• Deriving the component.
• Registering the... more ( see page 1321)
What Goes into a Component? ( see page 1323) To make your components reliable parts of the Delphi environment, you need to
follow certain conventions in their design. This section discusses the following
topics:

• Removing dependencies ( see page 1321)


• Setting properties ( see page 1319)
• Encapsulating graphics ( see page 1319)
• Registering components ( see page 1321)
Making Source Files Available ( see page 1323) Component writers should make all source files used by a component should be
located in the same directory. These files 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... more ( see page 1323)
Testing Installed Components ( see page 1324) You can test the design-time behavior of a component after you install it on the
Tool palette. This is particularly useful for debugging newly created components,
but the same technique works with any component, whether or not it is on the
Tool palette. For information on testing components that have not yet been
installed, see Testing uninstalled components ( see page 1324).
Testing your components after installing allows you to debug the component that
only generates design-time exceptions when dropped on a form.
Testing Uninstalled Components ( see page 1324) You can test the runtime behavior of a component before you install it on the
Tool palette. This is particularly useful for debugging newly created components,
but the same technique works with any component, whether or not it is on the
Tool palette. For information on testing already installed components, see
Testing installed components ( see page 1324).
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.

3.2.1.8.1 Overview of Component Creation 3


This set of topics provides an overview of component design and the process of writing components for Delphi applications. The
material here assumes that you are familiar with Delphi and its standard components.

The main topics discussed are

• Class library ( see page 1314)


• Components and classes ( see page 1315)

1313
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

• Creating components ( see page 1315)


• What goes into a component? ( see page 1323)
• Creating a new component ( see page 1317)
• Testing uninstalled components ( see page 1324)
• Testing installed components ( see page 1324)
For information on installing new components, see Installing component packages ( see page 2217).
See Also
Object-oriented Programming for Component Writers: Overview ( see page 1369)

Creating Properties: Overview ( see page 1249)

Creating Events: Overview ( see page 1233)

Creating Methods: Overview ( see page 1243)

Using Graphics in Components: Overview ( see page 1380)

Responding to Messages ( see page 1308)

Making Components Available at Design Time: Overview ( see page 1350)

Working with Frames ( see page 2012)

Creating and Using Component Templates ( see page 1975)

Reusing Components and Groups of Components ( see page 2000)

3.2.1.8.2 Class library


Delphi's components reside in the Visual Component Library (VCL) . The following figure shows the relationship of selected
classes that make up the VCL hierarchy. For a more detailed discussion of class hierarchies and the inheritance relationships
among classes, see Object-oriented programming for component writers ( see page 1369)

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

What Goes into a Component ( see page 1323)

Creating a New Component ( see page 1317)

Testing Uninstalled Components ( see page 1324)

3.2.1.8.3 Components and Classes


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,

• 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

Creating Components ( see page 1315)

What Goes into a Component ( see page 1323)

Creating a New Component ( see page 1317)

Testing Uninstalled Components ( see page 1324)

3.2.1.8.4 Creating Components


A component can be almost any program element that you want to manipulate at design time. Creating a component means
deriving a new class from an existing one. You can derive a new component in several ways:

• Modifying existing controls ( see page 1316)


• Creating windowed controls ( see page 1316)
• Creating graphic controls ( see page 1318)
• Subclassing Windows controls ( see page 1321)
• Creating nonvisual components ( see page 1318)
The following table summarizes the different kinds of components and the classes you use as starting points for each.
Component creation starting points

To do this Start with this type


Modify an existing component Any existing component, such as TButton or TListBox, or an abstract
component type, such as TCustomListBox
Create a windowed control TWinControl 3
Create a graphic control TGraphicControl
Subclassing a control Any Windows control
Create a nonvisual component TComponent

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)

Components and Classes ( see page 1315)

What Goes into a Component ( see page 1323)

Creating a New Component ( see page 1317)

Testing Uninstalled Components ( see page 1324)

3.2.1.8.5 Modifying Existing Controls


The simplest way to create a component is to customize an existing one. You can derive a new component from any of the
components provided in the component library.

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)

Windowed Controls ( see page 1316)

Graphical Controls ( see page 1318)

Subclassed Controls ( see page 1321)

3.2.1.8.6 Creating Original Controls


Windowed controls in the component library are objects that appear at runtime and that the user can interact with. Each
windowed control has a window handle, accessed through its Handle property, that lets the operating system identify and
operate on the control. If using VCL controls, the handle allows the control to receive input focus and can be passed to Windows
API functions. Each widget-based control has a handle, accessed through its Handle property, that identifies the underlying
widget.-->
3 All windowed controls descend from the TWinControlclass. These include most standard windowed controls, such as
pushbuttons, list boxes, and edit boxes. While you could derive an original control (one that's not related to any existing control)
directly from TWinControl, Delphi provides the TCustomControl component for this purpose. TCustomControl is a specialized
windowed control that makes it easier to draw complex visual images.

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

3.2.1.8.7 Creating a New Component


This topic describes how to create and setup a component.

To create a component, follow these steps:


1. Creating a unit file ( see page 1317)
2. Deriving the component ( see page 1318)
3. Registering the component ( see page 1320)
Now you will have a minimally functional component ready to install on the Tool palette. After installing, you can add your new
component to a form and test it at both design time and runtime. You can then add more features to the component, update
the Tool palette, and continue testing.

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. .

3.2.1.8.8 Creating a Unit File


A unit is a separately compiled module of Delphi code. Delphi uses units for several purposes. Every form has its own unit, and
most components (or groups of related components) have their own units as well.

When you create a component, you either create a new unit for the component or add the new component to an existing unit.

To create a new unit for a component: 3


1. Choose either:
• File New Unit.
• File New Other to display the New Items dialog box, select Delphi Projects Delphi Files Unit, and choose OK. The
IDE creates a new unit file and opens it in the Code editor.
2. Save the file with a meaningful name.
3. Derive the component class.

1317
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

To open an existing unit:


1. Choose File Open and select the source code unit to which you want to add your component.
Note: When adding a component to an existing unit, make sure that the unit contains only component code. For example,
adding component code to a unit that contains a form causes errors in the Tool palette.

2. Derive the component class.

3.2.1.8.9 Declaring A New Constructor (C++)


Each new component must have a constructor that overrides the constructor of the class from which it was derived. When you
write the constructor for your new component, it must always call the inherited constructor.

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.

3.2.1.8.10 Deriving the Component


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.

3.2.1.8.11 Creating Nonvisual Components


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
3 likely to be visual controls. Nonvisual components can be derived directly from TComponent, the abstract base class for all
components.

3.2.1.8.12 Creating Graphic Controls


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

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.

3.2.1.8.13 Encapsulating Graphics


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 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)

3.2.1.8.14 Setting Properties, Methods, and Events


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.

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.

There are several advantages to using properties:

• 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.

3.2.1.8.15 Registering the Component


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)

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)

Deriving the Component Object ( see page 1318)

Declaring a New Constructor ( see page 1318)

1320
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

3.2.1.8.16 Removing Dependencies


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 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.

3.2.1.8.17 Registering Components (Introduction)


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)

3.2.1.8.18 Subclassing Windows Controls


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 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 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:

• The class from which the component is derived.


• The class name for the new component.
• The Tool palette category where you want it to appear.

1321
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

• The name of the unit in which the component is created.


• The search path where the unit is found.
• The name of the package in which you want to place the component.
The Component wizard performs the same tasks you would when creating a component manually:
• Creating a unit.
• Deriving the component.
• Registering the component.
The Component wizard cannot add components to an existing unit. You must add components to existing units manually.

To add a new component with the Component Wizard


1. To start the Component wizard, choose one of these two methods:
• Choose Component New VCL Component.
• Choose File New Other, goto the Delphi Projects Delphi Files page and double-click Component.
2. Fill in the fields in the Component wizard:
• In the Ancestor Type field, specify the class from which you are deriving your new component.
• In the Class Name field, specify the name of your new component class.
• In the Palette Page field, specify the category on the Tool palette on which you want the new component to be installed.
• In the Unit file name field, specify the name of the unit you want the component class declared in. If the unit is not on the
search path, edit the search path in the Search Path field as necessary.
3. After you fill in the fields in the Component wizard, Click Install. To place the component in a new or existing package, click
Component Install and use the dialog box that appears to specify a package.
4. Click OK. The IDE creates a new unit.
Warning: If you derive a component from a class whose name begins with "custom" (such as TCustomControl), do not try to
place the new component on a form until you have overridden any abstract methods in the original component. Delphi cannot
create instance objects of a class that has abstract properties or methods.
To see the source code for your unit, click View Units... (If the Component wizard is already closed, open the unit file in the
Code editor by selecting File Open.) Delphi creates a new unit containing the class declaration and the Register procedure,
and adds a uses clause that includes all the standard Delphi units.
The unit looks like this:
unit MyControl;
interface
uses
Windows, Messages, SysUtils, Types, Classes, Controls;
type
TMyControl = class(TCustomControl)
private
{ Private declarations }
protected
{ Protected declarations }
public
3 { Public declarations }
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TMyControl]); //In CLX, use a different page than
'Samples'
end;

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
}
}

3.2.1.8.20 What Goes into a Component?


To make your components reliable parts of the Delphi environment, you need to follow certain conventions in their design. This
section discusses the following topics:

• Removing dependencies ( see page 1321)


• Setting properties ( see page 1319) 3
• Encapsulating graphics ( see page 1319)
• Registering components ( see page 1321)

3.2.1.8.21 Making Source Files Available


Component writers should make all source files used by a component should be located in the same directory. These files

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.

3.2.1.8.22 Testing Installed Components


You can test the design-time behavior of a component after you install it on the Tool palette. This is particularly useful for
debugging newly created components, but the same technique works with any component, whether or not it is on the Tool
palette. For information on testing components that have not yet been installed, see Testing uninstalled components ( see page
1324).

Testing your components after installing allows you to debug the component that only generates design-time exceptions when
dropped on a form.

Test an installed component using a second running instance of the IDE:


1. Choose Project Options Debugger and set the Debug Source Path to point to the component's source file.
2. Then select Tools Options. On the Debugger Options Borland Debuggers Language Exceptions page, enable the
exceptions you want to track.
3. Open the component source file and set breakpoints.
4. Select Run Parameters and set the Host Application field to the name and location of the Delphi executable file.
5. In the Run Parameters dialog, click the Load button to start a second instance of Delphi.
6. Then drop the components to be tested on the form, which should break on your breakpoints in the source.

3.2.1.8.23 Testing Uninstalled Components


You can test the runtime behavior of a component before you install it on the Tool palette. This is particularly useful for
debugging newly created components, but the same technique works with any component, whether or not it is on the Tool
palette. For information on testing already installed components, see Testing installed components ( see page 1324).

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.

To test an uninstalled component,


1. Add the name of component's unit to the form unit's uses clause.
2. Add an object field to the form to represent the component. This is one of the main differences between the way you add
components and the way Delphi does it. You add the object field to the public part at the bottom of the form's type declaration.
Delphi would add it above, in the part of the type declaration that it manages. Never add fields to the Delphi-managed part of
the form's type declaration. The items in that part of the type declaration correspond to the items stored in the form file.
Adding the names of components that do not exist on the form can render your form file invalid.
3
3. Attach a handler to the form's OnCreate event.
4. Construct the component in the form's OnCreate handler. When you call the component's constructor, you must pass a
parameter specifying the owner of the component (the component responsible for destroying the component when the time
comes). You will nearly always pass Self as the owner. In a method, Self is a reference to the object that contains the method.
In this case, in the form's OnCreate handler, Self refers to the form.
5. Assign the Parent property. Setting the Parent property is always the first thing to do after constructing a control. The parent is
the component that contains the control visually; usually it is the form on which the control appears, but it might be a group
box or panel. Normally, you'll set Parent to Self, that is, the form. Always set Parent before setting other properties of the

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.

6. Set any other component properties as desired.

3.2.1.9 Making a control data aware


Topics
Name Description
Adding the Data Link ( see page 1327) The connection between a control and a database is handled by a class called a
data link. The data link class that connects a control with a single field in a
database is TFieldDataLink. There are also data links for entire tables.
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)
Adding the ReadOnly property ( see page 1328) By adding a ReadOnly property, you will provide a way to make the control
read-only at design time. When that property is set to True, you can make all
cells in the control unable to be selected.
Allowing Needed Updates ( see page 1329) The read-only calendar uses the SelectCell method for all kinds of changes,
including setting the Row and Col properties. The UpdateCalendar method sets
Row and Col every time the date changes, but because SelectCell disallows
changes, the selection remains in place, even though the date changes.
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:
Changing the Default Value of FReadOnly ( see page 1330) Because this is a data editing control, the ReadOnly property should be set to
False by default. To make the ReadOnly property False, change the value of
FReadOnly in the constructor:
Creating a Data Browsing Control ( see page 1330) Creating a data-aware calendar control, whether it is a read-only control or one in
which the user can change the underlying data in the dataset, involves the
following steps:

• Creating and registering the component ( see page


1331).
• Adding the data link ( see page 1327).
• Responding to data changes ( see page 1334).
Creating a Data Editing Control ( see page 1330) When you create a data editing control, you create and register the component
and add the data link just as you do for a data browsing control. You also
respond to data changes in the underlying field in a similar manner, but you must
handle a few more issues.
For example, you probably want your control to respond to both key and mouse
events. Your control must respond when the user changes the contents of the
control. When the user exits the control, you want the changes made in the
control to be reflected in the dataset.
The data editing... more ( see page 1330)

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:

• Call the component's unit DBCal.


• Derive a new component class called TDBCalendar,
descended from the component TSampleCalendar. The
section Customizing a grid ( see page 1264) shows you
how to create the TSampleCalendar component.
• Register TDBCalendar on the Samples page of the Tool
palette.
The resulting unit descending from TCustomGrid in a... more
( see page 1331)
Declaring the Access Properties for a Data-aware Control ( see page 1331) Every data-aware control has a DataSource property that specifies which data
source class in the application provides the data to the control. In addition, a
control that accesses a single field needs a DataField property to specify that
field in the data source.
Unlike the access properties for the owned classes in the example in Creating a
graphic control ( see page 1220) these access 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... more ( see page 1331)
Declaring the Class Field ( see page 1332) A component needs a field for each of its owned classes, as explained in
Declaring the class fields ( see page 1222). In this case, the calendar needs a
field of type TFieldDataLink for its data link.
Declare a field for the data link in the calendar:
Handling Mouse-down and Key-down Messages ( see page 1332) When the user of the control begins interacting with it, the control receives either
mouse-down messages (WM_LBUTTONDOWN, WM_MBUTTONDOWN, or
WM_RBUTTONDOWN) or a key-down message (WM_KEYDOWN) from
Windows. To enable a control to respond to these messages, you must write
handlers that respond to these messages.

• Responding to mouse-down messages ( see page


1336).
• Responding to key-down messages ( see page 1335).
Initializing the Data Link ( see page 1332) A data-aware control needs access to its data link throughout its existence, so it
must construct the data link object as part of its own constructor, and destroy the
data link object before it is itself destroyed.
Override the Create and Destroy methods of the calendar to construct and
destroy the datalink object, respectively:
Making a Control Data Aware ( see page 1333) When working with database connections, it is often convenient to have controls
that are data aware. That is, the application can establish a link between the
control and some part of a database. Delphi includes data-aware labels, edit
boxes, list boxes, combo boxes, lookup controls, and grids. You can also make
your own controls data aware. For more information about using data-aware
controls, see Using data controls ( see page 1778) .
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... more ( see page 1333)
Making the Control Read-only ( see page 1333) 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.
3 Making the calendar read-only involves:

• Adding the ReadOnly property. ( see page 1328)


• Allowing needed updates. ( see page 1329)
Note: Note that if you started with the TCalendar
component from Delphi's Samples page instead of
TSampleCalendar, it already has a ReadOnly property, so
you can skip these steps.

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 change in a field value that must be reflected in the


data-aware control.
• A change in the data-aware control that must be reflected
in the field value.
The TDBCalendar component already has a DataChange
method that handles a change in the field's value in the
dataset by assigning that value to the CalendarDate
property. The DataChange method is the handler for the
OnDataChange event. So the calendar component can
handle the first type of data change.
Similarly, the field data link class also has an OnUpdateData
event that occurs as the user... more ( see page 1338)

3.2.1.9.1 Adding the Data Link


The connection between a control and a database is handled by a class called a data link. The data link class that connects a 3
control with a single field in a database is TFieldDataLink. There are also data links for entire tables.

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)

Establishing a data link as an owned class requires these three steps:


1. Declaring the class field ( see page 1332).
2. Declaring the access properties ( see page 1331).

1327
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

3. Initializing the data link ( see page 1332).

3.2.1.9.2 Adding the ReadOnly property


By adding a ReadOnly property, you will provide a way to make the control read-only at design time. When that property is set to
True, you can make all cells in the control unable to be selected.

To add the ReadOnly property, follow these steps:


1. Add the property declaration and a private field to hold the value:
type
TDBCalendar = class(TSampleCalendar)
private
FReadOnly: Boolean; { field for internal storage }
public
constructor Create(AOwner: TComponent); override; { must override to set default }
published
property ReadOnly: Boolean read FReadOnly write FReadOnly default True;
end;
.
.
.
constructor TDBCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { always call the inherited constructor! }
FReadOnly := True; { set the default value }
end;
//header file
class PACKAGE TDBCalendar : public TSampleCalendar
{
private:
bool FReadOnly; // field for internal storage
protected:
public:
virtual __fastcall TDBCalendar(TComponent* Owner);
__published:
__property ReadOnly = {read=FReadOnly, write=FReadOnly, default=true};
};
//implementation file:
virtual __fastcall TDBCalendar::TDBCalendar(TComponent* Owner) :
TSampleCalendar(Owner)
{
FReadOnly = true; // sets the default value
}
2. Override the SelectCell method to disallow selection if the control is read-only. Use of SelectCell is explained in Excluding
blank cells ( see page 1265).
function TDBCalendar.SelectCell(ACol, ARow: Longint): Boolean;
begin
if FReadOnly then Result := False { cannot select if read only }
else Result := inherited SelectCell(ACol, ARow); { otherwise, use inherited method }
end;
3 bool __fastcall TDBCalendar::SelectCell(long ACol, long ARow)
{
if (FReadOnly) return false; // can't select if read only
return TSampleCalendar::SelectCell(ACol, ARow); // otherwise, use inherited method
}
Remember to add the declaration of SelectCell to the type declaration of TDBCalendar, and append the override directive.

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

3.2.1.9.3 Allowing Needed Updates


The read-only calendar uses the SelectCell method for all kinds of changes, including setting the Row and Col properties. The
UpdateCalendar method sets Row and Col every time the date changes, but because SelectCell disallows changes, the
selection remains in place, even though the date changes.

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.

3.2.1.9.4 Changing the Default Value of FReadOnly


Because this is a data editing control, the ReadOnly property should be set to False by default. To make the ReadOnly property
False, change the value of FReadOnly in the constructor:
constructor TDBCalendar.Create(AOwner: TComponent);
begin
.
.
.
FReadOnly := False; { set the default value }
.
.
.
end;
__fastcall TDBCalendar::TDBCalendar (TComponent* Owner) : TSampleCalendar(Owner)
{
FReadOnly = false; // set the default value
.
.
.
}

3.2.1.9.5 Creating a Data Browsing Control


Creating a data-aware calendar control, whether it is a read-only control or one in which the user can change the underlying data
in the dataset, involves the following steps:

• Creating and registering the component ( see page 1331).


• Adding the data link ( see page 1327).
• Responding to data changes ( see page 1334).

3.2.1.9.6 Creating a Data Editing Control


When you create a data editing control, you create and register the component and add the data link just as you do for a data
browsing control. You also respond to data changes in the underlying field in a similar manner, but you must handle a few more
issues.
3
For example, you probably want your control to respond to both key and mouse events. Your control must respond when the
user changes the contents of the control. When the user exits the control, you want the changes made in the control to be
reflected in the dataset.

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.

Modifying the existing control to make it a data editing control involves:

1330
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

• Changing the default value of FReadOnly. ( see page 1330)


• Handling mouse-down and key-down messages. ( see page 1332)
• Updating the field data link class. ( see page 1338)
• Modifying the Change method. ( see page 1334)
• Updating the dataset. ( see page 1337)

3.2.1.9.7 Creating and registering the data-aware component


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:

• Call the component's unit DBCal.


• Derive a new component class called TDBCalendar, descended from the component TSampleCalendar. The section
Customizing a grid ( see page 1264) shows you how to create the TSampleCalendar component.
• Register TDBCalendar on the Samples page of the Tool palette.
The resulting unit descending from TCustomGrid in a VCL application should look like this:
unit CalSamp;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids;
type
TSampleCalendar = class(TCustomGrid)
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TSampleCalendar]);
end;
end.
If you install the calendar component now, you will find that it appears on the Samples page. 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).

3.2.1.9.8 Declaring the Access Properties for a Data-aware Control


Every data-aware control has a DataSource property that specifies which data source class in the application provides the data
to the control. In addition, a control that accesses a single field needs a DataField property to specify that field in the data source.

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

3.2.1.9.9 Declaring the Class Field


A component needs a field for each of its owned classes, as explained in Declaring the class fields ( see page 1222). In this
case, the calendar needs a field of type TFieldDataLink for its data link.

Declare a field for the data link in the calendar:


type
TDBCalendar = class(TSampleCalendar)
private
FDataLink: TFieldDataLink;
.
.
.
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
private:
TFieldDataLink *FDataLink;
.
.
.
};
#include <DB.hpp>
#include <DBTables.hpp>
Before you can compile the application, you need to add DB and DBCtrls to the unit's uses clause.

3.2.1.9.10 Handling Mouse-down and Key-down Messages


When the user of the control begins interacting with it, the control receives either mouse-down messages
(WM_LBUTTONDOWN, WM_MBUTTONDOWN, or WM_RBUTTONDOWN) or a key-down message (WM_KEYDOWN) from
Windows. To enable a control to respond to these messages, you must write handlers that respond to these messages.

• Responding to mouse-down messages ( see page 1336).


• Responding to key-down messages ( see page 1335).

3.2.1.9.11 Initializing the Data Link


A data-aware control needs access to its data link throughout its existence, so it must construct the data link object as part of its
own constructor, and destroy the data link object before it is itself destroyed.

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

FDataLink.Control := self; {let the datalink know about the calendar }


FReadOnly := True; { this is already here }
end;
destructor TDBCalendar.Destroy;
begin
FDataLink.Free; { always destroy owned objects first... }
inherited Destroy; { ...then call inherited destructor }
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
public:
virtual __fastcall TDBCalendar(TComponent *Owner);
__fastcall ~TDBCalendar();
};
__fastcall TDBCalendar::TDBCalendar(TComponent* Owner) : TSampleCalendar(Owner)
{
FReadOnly = true;
FDataLink = new TFieldDataLink();
FDataLink->Control = this;
}
__fastcall TDBCalendar::~TDBCalendar()
{
FDataLink->Control = NULL;
FDataLink->OnUpdateData = NULL;
delete FDataLink;
}
Now you have a complete data link, but you have not yet told the control what data it should read from the linked field. The next
section ( see page 1334) explains how to do that.

See Also
Declaring the Access Properties for a Data-aware Control ( see page 1331)

3.2.1.9.12 Making a Control Data Aware


When working with database connections, it is often convenient to have controls that are data aware. That is, the application can
establish a link between the control and some part of a database. Delphi includes data-aware labels, edit boxes, list boxes,
combo boxes, lookup controls, and grids. You can also make your own controls data aware. For more information about using
data-aware controls, see Using data controls ( see page 1778) .

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.

Making the calendar read-only involves:

• Adding the ReadOnly property. ( see page 1328)

1333
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

• Allowing needed updates. ( see page 1329)


Note: Note that if you started with the TCalendar component from Delphi's Samples page instead of TSampleCalendar, it
already has a ReadOnly property, so you can skip these steps.

3.2.1.9.14 Modifying the Change Method


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.

These are the steps to follow:


1. Add a new Change method to the TDBCalendar component:
type
TDBCalendar = class(TSampleCalendar);
private
procedure Change; override;
.
.
.
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
protected:
virtual void __fastcall Change();
.
.
.
};
2. Write the Change method, calling the Modified method that informs the dataset the data has changed, then call the inherited
Change method:
procedure TDBCalendar.Change;
begin
FDataLink.Modified; { call the Modified method }
inherited Change; { call the inherited Change method }
end;
void __fastcall TDBCalendar::Change()
{
if (FDataLink != NULL)
FDataLink->Modified(); // call the Modified method
TSampleCalendar::Change(); // call the inherited Change method
}

3.2.1.9.15 Responding to Data Changes


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.
3
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, 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

3.2.1.9.16 Responding to Key-down Messages


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.

To override KeyDown, follow these steps:


1. Add a KeyDown method to the TDBCalendar class:
type
TDBCalendar = class(TSampleCalendar);
.
.
.
protected
procedure KeyDown(var Key: Word; Shift: TShiftState; X: Integer; Y: Integer);
override;
.
.
.
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
.
.
.
protected:
virtual void __fastcall KeyDown(unsigned short &Key, TShiftState Shift);
.
.
.
};
2. Implement the KeyDown method:
procedure KeyDown(var Key: Word; Shift: TShiftState);
var
MyKeyDown: TKeyEvent;
begin
if not ReadOnly and (Key in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_END,
VK_HOME, VK_PRIOR, VK_NEXT]) and FDataLink.Edit then
inherited KeyDown(Key, Shift)
else
begin
MyKeyDown := OnKeyDown;
if Assigned(MyKeyDown) then MyKeyDown(Self, Key, Shift);
end;
end;
void __fastcall TDBCalendar::KeyDown(unsigned short &Key, TShiftState Shift)
{
TKeyEvent MyKeyDown; // declare event type
Set<unsigned short,0,8> keySet;
keySet = keySet << VK_UP << VK_DOWN << VK_LEFT // assign virtual keys to set
<< VK_RIGHT << VK_END << VK_HOME << VK_PRIOR << VK_NEXT; 3
if (!FReadOnly && // if control is not read only...
(keySet.Contains(Key)) && // ...and key is in the set...
FDataLink->Edit() ) // ...and field is in edit mode
{
TCustomGrid::KeyDown(Key, Shift); // call the inherited KeyDown method
}
else
{
MyKeyDown = OnKeyDown; // assign OnKeyDown event
if (MyKeyDown != NULL) MyKeyDown(this,Key,Shift); // execute code in...

1335
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

} // ...OnKeyDown event handler


}
When KeyDown responds to a mouse-down message, the inherited KeyDown method is called only if the control's ReadOnly
property is False, the key pressed is one of the cursor control keys, and the data link object is in edit mode, which means the
field can be edited. If the field cannot be edited or some other key is pressed, the code the programmer put in the OnKeyDown
event handler, if one exists, is executed.

3.2.1.9.17 Responding to Mouse-down Messages


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:


type
TDBCalendar = class(TSampleCalendar);
.
.
.
protected
procedure MouseDown(Button: TButton, Shift: TShiftState, X: Integer, Y: Integer);
override;
.
.
.
end;
procedure TDBCalendar.MouseDown(Button: TButton; Shift: TShiftState; X, Y: Integer);
var
MyMouseDown: TMouseEvent;
begin
if not ReadOnly and FDataLink.Edit then
inherited MouseDown(Button, Shift, X, Y)
else
begin
MyMouseDown := OnMouseDown;
if Assigned(MyMouseDown then MyMouseDown(Self, Button, Shift, X, Y);
end;
end;
//header file
class PACKAGE TDBCalendar : public TSampleCalendar
{
.
.
.
protected:
virtual void __fastcall MouseDown(TMouseButton Button, TShiftState Shift, int X,
int Y);
.
.
.
};
3 //implmentation file
void __fastcall TDBCalendar::MouseDown(TMouseButton Button, TShiftState Shift, int X, int
Y)
{
TMouseEvent MyMouseDown; // declare event type
if (!FReadOnly && FDataLink->Edit()) // if the field can be edited
TSampleCalendar::MouseDown(Button, Shift, X, Y); // call the inherited MouseDown
else
{
MyMouseDown = OnMouseDown; // assign OnMouseDown event
if (MyMouseDown != NULL) MyMouseDown(this, Button, // execute code in the...

1336
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

Shift, X, Y); // ...OnMouseDown event handler


}
}
When MouseDown responds to a mouse-down message, the inherited MouseDown method is called only if the control's
ReadOnly property is False and the data link object is in edit mode, which means the field can be edited. If the field cannot be
edited, the code the programmer put in the OnMouseDown event handler, if one exists, is executed.

3.2.1.9.18 Updating the Dataset


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 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)

To update the dataset within a message handler, follow these steps:


1. Add the message handler to the TDBCalendar component:
type
TDBCalendar = class(TSampleCalendar);
private
procedure CMExit(var Message: TWMNoParams); message CM_EXIT;
.
.
.
end;
class PACKAGE TDBCalendar : public TSampleCalendar
{
private:
void __fastcall CMExit(TWMNoParams Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_EXIT, TWMNoParams, CMExit)
END_MESSAGE_MAP
};
2. Implement the CMExit 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;
end;
void __fastcall TDBCalendar::CMExit(TWMNoParams &Message)
{ 3
try
{
FDataLink.UpdateRecord(); // tell data link to update database
}
catch(...)
{
SetFocus(); // if it failed, don't let focus leave
throw;
}

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
}

3.2.1.9.19 Updating the Field Data Link Class


There are two types of data changes:

• A change in a field value that must be reflected in the data-aware control.


• A change in the data-aware control that must be reflected in the field value.
The TDBCalendar component already has a DataChange method that handles a change in the field's value in the dataset by
3 assigning that value to the CalendarDate property. The DataChange method is the handler for the OnDataChange event. So
the calendar component can handle the first type of data change.
Similarly, the field data link class also has an OnUpdateData event that occurs as the user of the control modifies the contents of
the data-aware control. The calendar control has a UpdateData method that becomes the event handler for the
OnUpdateData event. UpdateData assigns the changed value in the data-aware control to the field data link.

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
}

3.2.1.10 Making components available at design time


Topics
Name Description
Adding Clipboard Formats ( see page 1344) By default, when a user chooses Copy while a component is selected in the IDE,
the component is copied in Delphi's internal format. It can then be pasted into
another form or data module. Your component can copy additional formats to the
Clipboard by overriding the Copy method.
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.
Adding Component Editors ( see page 1344) Component editors determine what happens when the component is
double-clicked in the designer and add commands to the context menu that 3
appears when the component is right-clicked. They can also copy your
component to the Windows clipboard in custom formats.
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... more ( see page 1344)

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:

• Specifying menu items ( see page 1355)


• Implementing commands ( see page 1349)
Adding Property Editors ( see page 1345) The Object Inspector provides default editing for all types of properties. You can,
however, provide an alternate editor for specific properties by writing and
registering property editors. You can register property editors that apply only to
the properties in the components you write, but you can also create editors that
apply to all properties of a certain type.
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.... more ( see
page 1345)
Changing the Double-click Behavior ( see page 1345) When the component is double-clicked, the Edit method of the component editor
is called. By default, the Edit method executes the first command added to the
context menu. Thus, in the previous example ( see page 1349), double-clicking
the component executes the DoThis command.
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

• you are not adding any commands to the context menu.


• you want to display a dialog that combines several
commands when the component is double-clicked.
Override the Edit method to specify a... more ( see page
1345)
Compiling Components into Packages ( see page 1346) Once your components are registered, you must compile them as packages
before they can be installed in the IDE. A package can contain one or several
components as well as custom property editors. For more information about
packages, see Working with packages and components ( see page 2211) .
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).
Creating the Entries ( see page 1346) To make your component's Help integrate seamlessly with the Help for the rest of
the components in the library, observe the following conventions:
Each component should have a Help topic:
The component topic should show which unit the component is declared in and
briefly describe the component. The component topic should link to secondary
windows that describe the component's position in the object hierarchy and list all
of its properties, events, and methods. Application developers access this topic
by selecting the component on a form and pressing F1. For an example of a
component topic, place any component on... more ( see page 1346)
Creating the Help File ( see page 1347) You can use any tool you want to create the source file for a Windows Help file
(in .rtf format). Delphi includes the Microsoft Help Workshop, which compiles your
Help files and provides an online Help authoring guide. You can find complete
information about creating Help files in the online guide for Help Workshop.
Composing Help files for components consists of the steps:

• Creating the entries ( see page 1346).


• Making component Help context-sensitive ( see page
3 1350).
Declaring the Register Procedure ( see page 1347) Registration involves writing a single procedure in the unit, which must have the
name Register. The Register procedure must appear in the interface part of the
unit, and (unlike the rest of Delphi) its name is case-sensitive.
Note: Although Delphi is a case insensitive language, the Register procedure is
case sensitive and must be spelled with an uppercase R.
The following code shows the outline of a simple unit that creates and registers
new components:

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:

• Registering components ( see page 1352)


• Providing Help for your component ( see page 1351)
• Adding property editors ( see page 1345)
• Adding component editors ( see page 1344)
• Compiling components into packages ( see page 1346)
Not all these steps apply to every component. For example,
if you don't define any new properties or events, you don't
need to provide Help for them. The only steps that are
always necessary are registration and compilation.
Once your components have been registered and compiled
into packages, they can be distributed to other developers
and installed in the IDE. For information on installing
packages in the IDE, see Installing component packages
( see page 2217).... more ( see page 1350)
Property Categories ( see page 1350) In the IDE, the Object Inspector lets you selectively hide and display properties
based on property categories. The properties of new custom components can be
fit into this scheme by registering properties in categories. Do this at the same
time you register the component by calling RegisterPropertyInCategory or
RegisterPropertiesInCategory. Use RegisterPropertyInCategory to register a
single property. Use RegisterPropertiesInCategory to register multiple properties
in a single function call. These functions are defined in the unit DesignIntf. 3
Note that it is not mandatory that you register properties or that you register all of
the properties of a custom component... more ( see page 1350)
Specifying Property Categories ( see page 1351) When you register properties in a category, you can use any string you want as
the name of the category. If you use a string that has not been used before, the
Object Inspector generates a new property category class with that name. You
can also, however, register properties into one of the categories that are built-in.
The built-in property categories are described in the following table:
Property categories

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:

• Declaring the Register procedure ( see page 1347)


• Writing the Register procedure ( see page 1357)
Registering Multiple Properties at Once ( see page 1352) Register multiple properties at one time and associate them with a property
category using the RegisterPropertiesInCategory function.
RegisterPropertiesInCategory comes in three overloaded variations, each
providing a different set of criteria for identifying the property in the custom
component to be associated with property categories.
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.'
Registering One Property at a Time ( see page 1353) Register one property at a time and associate it with a property category using
the RegisterPropertyInCategory function. RegisterPropertyInCategory comes in
four overloaded variations, each providing a different set of criteria for identifying
the property in the custom component to be associated with the property
category.
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".
Registering the Component Editor ( see page 1353) Once the component editor is defined, it can be registered to work with a
particular component class. A registered component editor is created for each
component of that class when it is selected in the form designer.
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:
Registering the Property Editor ( see page 1354) Once you create a property editor, you need to register it with Delphi. Registering
a property editor associates a type of property with a specific property editor. You
can register the editor with all properties of a given type or just with a particular
property of a particular type of component.
To register a property editor, call the RegisterPropertyEditor procedure.
RegisterPropertyEditor takes four parameters:

• 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(TMyCompone
nt).
3 • The type of the component to which this editor applies—if
this... more ( see page 1354)
Setting the Property Value ( see page 1354) The property editor's SetValue method takes a string typed by the user in the
Object Inspector, converts it into the appropriate type, and sets the value of the
property. If the string does not represent a proper value for the property,
SetValue should throw an exception and not use the improper value.
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.

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:

• Missing PACKAGE modifier on the Register function


• Missing PACKAGE modifier on the class
• Missing #pragma package(smart_init) in the C++
source file
• Register function is not found in a namespace with the
same name as the source code module name.
• Register is not being successfully exported. Use tdump
on the .BPL to look for the exported function:
tdump -ebpl... more ( see page 1356)
Using the IsPropertyInCategory Function ( see page 1356) An application can query the existing registered properties to determine whether
a given property is already registered in a specified category. This can be
especially useful in situations like a localization utility that checks the
categorization of properties preparatory to performing its localization operations.
Two overloaded variations of the IsPropertyInCategory function are available,
allowing for different criteria in determining whether a property is in a category.
The first variation lets you base the comparison criteria on a combination of the
class type of the owning component and the property's name. In the command
line below, for IsPropertyInCategory to return True... more ( see page 1356)
Using the RegisterComponents Function ( see page 1357) Within the Register procedure, call RegisterComponents to register the
components in the classes array. RegisterComponents is a function that takes
two parameters: the name of a Tool palette category and the array of component
classes.
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 3
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... more ( see page 1357)

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:

1. Specifying the components. ( see page 1355)


2. Specifying the palette page. ( see page 1356)
3. Using the RegisterComponents function ( see page
1357).

3.2.1.10.1 Adding Clipboard Formats


By default, when a user chooses Copy while a component is selected in the IDE, the component is copied in Delphi's internal
format. It can then be pasted into another form or data module. Your component can copy additional formats to the Clipboard by
overriding the Copy method.

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);
}

3.2.1.10.2 Adding Component Editors


Component editors determine what happens when the component is double-clicked in the designer and add commands to the
context menu that appears when the component is right-clicked. They can also copy your component to the Windows clipboard
in custom formats.

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.

Adding a custom component editor consists of the steps:

• Adding items to the context menu ( see page 1345)


• Changing the double-click behavior ( see page 1345)
• Adding clipboard formats ( see page 1344)

1344
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

• Registering the component editor ( see page 1353)

3.2.1.10.3 Adding Items to the Context Menu


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:

• Specifying menu items ( see page 1355)


• Implementing commands ( see page 1349)

3.2.1.10.4 Adding Property Editors


The Object Inspector provides default editing for all types of properties. You can, however, provide an alternate editor for specific
properties by writing and registering property editors. You can register property editors that apply only to the properties in the
components you write, but you can also create editors that apply to all properties of a certain type.

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.

Writing a property editor requires these five steps:

1. Deriving a property-editor class ( see page 1348).


2. Editing the property as text.
3. Editing the property as a whole ( see page 1349).
4. Specifying editor attributes ( see page 1354).
5. Registering the property editor ( see page 1354).

3.2.1.10.5 Changing the Double-click Behavior


When the component is double-clicked, the Edit method of the component editor is called. By default, the Edit method executes
the first command added to the context menu. Thus, in the previous example ( see page 1349), double-clicking the component
executes the DoThis command.

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

• you are not adding any commands to the context menu.


• you want to display a dialog that combines several commands when the component is double-clicked.
Override the Edit method to specify a new behavior when the component is double-clicked. For example, the following Edit
method brings up a font dialog when the user double-clicks the component:
procedure TMyEditor.Edit;
var
3
FontDlg: TFontDialog;
begin
FontDlg := TFontDialog.Create(Application);
try
if FontDlg.Execute then
MyComponent.FFont.Assign(FontDlg.Font);
finally
FontDlg.Free
end;

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:

procedure TMyEditor.EditProperty(PropertyEditor: TPropertyEditor;


Continue, FreeEditor: Boolean)
begin
if (PropertyEditor.ClassName = 'TMethodProperty') and
(PropertyEditor.GetName = 'OnSpecialEvent') then
// DefaultEditor.EditProperty(PropertyEditor, Continue, FreeEditor);
end;
void __fastcall TMyEditor::EditProperty(TPropertyEditor* PropertyEditor,
bool &Continue, bool &FreeEditor)
{
if (PropertyEditor->ClassNameIs("TMethodProperty") &&
CompareText(PropertyEditor->GetName, "OnSpecialEvent") == 0)
{
TDefaultEditor::EditProperty(PropertyEditor, Continue, FreeEditor);
}
}

3.2.1.10.6 Compiling Components into Packages


Once your components are registered, you must compile them as packages before they can be installed in the IDE. A package
can contain one or several components as well as custom property editors. For more information about packages, see Working
with packages and components ( see page 2211) .

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).

3.2.1.10.7 Creating the Entries


To make your component's Help integrate seamlessly with the Help for the rest of the components in the library, observe the
following conventions:

Each component should have a Help topic:


3
The component topic should show which unit the component is declared in and briefly describe the component. The component
topic should link to secondary windows that describe the component's position in the object hierarchy and list all of its properties,
events, and methods. Application developers access this topic by selecting the component on a form and pressing F1. For an
example of a component topic, place any component on a form and press F1.

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.

Each component should include the following secondary navigational topics:

• 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.

3.2.1.10.8 Creating the Help File


You can use any tool you want to create the source file for a Windows Help file (in .rtf format). Delphi includes the Microsoft Help
Workshop, which compiles your Help files and provides an online Help authoring guide. You can find complete information about
creating Help files in the online guide for Help Workshop.

Composing Help files for components consists of the steps:

• Creating the entries ( see page 1346).


• Making component Help context-sensitive ( see page 1350). 3

3.2.1.10.9 Declaring the Register Procedure


Registration involves writing a single procedure in the unit, which must have the name Register. The Register procedure must
appear in the interface part of the unit, and (unlike the rest of Delphi) its name is case-sensitive.

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.

3.2.1.10.10 Deriving a Property-editor Class


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 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.

Predefined property-editor types

Type Properties edited


TOrdinalProperty All ordinal-property editors (those for integer, character, and enumerated properties) descend from
TOrdinalProperty.
TIntegerProperty All integer types, including predefined and user-defined subranges.
TCharProperty Char-type and subranges of Char, such as 'A'..'Z'.
TEnumProperty Any enumerated type.
TFloatProperty All floating-point numbers.
3 TStringProperty Strings.
TSetElementProperty Individual elements in sets, shown as Boolean values
TSetProperty All sets. Sets are not directly editable, but can expand into a list of set-element properties.
TClassProperty Classes. Displays the name of the class and allows expansion of the class's properties.
TMethodProperty Method pointers, most notably events.
TComponentProperty Components in the same form. The user cannot edit the component's properties, but can point to a
specific component of a compatible type.

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.

3.2.1.10.11 Editing the Property as a Whole


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 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.

Within your implementation of the Edit method, follow these steps:


1. Construct the editor you are using for the property.
2. Read the current value and assign it to the property using a Get method.
3. When the user selects a new value, assign that value to the property using a Set method.
4. Destroy the editor.

3.2.1.10.12 Implementing Commands


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.
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;
}
}

3.2.1.10.13 Making Component Help Context-sensitive


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:
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

3.2.1.10.14 Making Components Available at Design Time: Overview


Making your components available at design time requires several steps:

• Registering components ( see page 1352)


• Providing Help for your component ( see page 1351)
• Adding property editors ( see page 1345)
• Adding component editors ( see page 1344)
• Compiling components into packages ( see page 1346)
Not all these steps apply to every component. For example, if you don't define any new properties or events, you don't need to
provide Help for them. The only steps that are always necessary are registration and compilation.
Once your components have been registered and compiled into packages, they can be distributed to other developers and
installed in the IDE. For information on installing packages in the IDE, see Installing component packages ( see page 2217).
See Also
Extending the IDE ( see page 1285)
3
3.2.1.10.15 Property Categories
In the IDE, the Object Inspector lets you selectively hide and display properties based on property categories. The properties of
new custom components can be fit into this scheme by registering properties in categories. Do this at the same time you register
the component by calling RegisterPropertyInCategory or RegisterPropertiesInCategory. Use RegisterPropertyInCategory to
register a single property. Use RegisterPropertiesInCategory to register multiple properties in a single function call. These
functions are defined in the unit DesignIntf.

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.

• Registering one property at a time ( see page 1353)


• Registering multiple properties at once ( see page 1352)
• Specifying property categories ( see page 1351)
• Using the IsPropertyInCategory function ( see page 1356)

3.2.1.10.16 Specifying Property Categories


When you register properties in a category, you can use any string you want as the name of the category. If you use a string that
has not been used before, the Object Inspector generates a new property category class with that name. You can also, however,
register properties into one of the categories that are built-in. The built-in property categories are described in the following table:

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.

3.2.1.10.17 Providing Help for Your Component


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

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.

3.2.1.10.18 Registering Components


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:

• Declaring the Register procedure ( see page 1347)


• Writing the Register procedure ( see page 1357)

3.2.1.10.19 Registering Multiple Properties at Once


Register multiple properties at one time and associate them with a property category using the RegisterPropertiesInCategory
function. RegisterPropertiesInCategory comes in three overloaded variations, each providing a different set of criteria for
identifying the property in the custom component to be associated with property categories.

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

3.2.1.10.20 Registering One Property at a Time


Register one property at a time and associate it with a property category using the RegisterPropertyInCategory function.
RegisterPropertyInCategory comes in four overloaded variations, each providing a different set of criteria for identifying the
property in the custom component to be associated with the property category.

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.

3.2.1.10.21 Registering the Component Editor


Once the component editor is defined, it can be registered to work with a particular component class. A registered component
editor is created for each component of that class when it is selected in the form designer.

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

RegisterComponents("Miscellaneous", classes, 0);


RegisterComponentEditor(classes[0], __classid(TMyEditor));
}
}

3.2.1.10.22 Registering the Property Editor


Once you create a property editor, you need to register it with Delphi. Registering a property editor associates a type of property
with a specific property editor. You can register the editor with all properties of a given type or just with a particular property of a
particular type of component.

To register a property editor, call the RegisterPropertyEditor procedure.

RegisterPropertyEditor takes four parameters:

• 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.

3.2.1.10.23 Setting the Property Value


The property editor's SetValue method takes a string typed by the user in the Object Inspector, converts it into the appropriate
type, and sets the value of the property. If the string does not represent a proper value for the property, SetValue should throw
an exception and not use the improper value.

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.

3.2.1.10.24 Specifying Editor Attributes


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

Flag Related method Meaning if included

3 paValueList GetValues The editor can give a list of enumerated values.


paSubProperties GetProperties The property has subproperties that can display.
paDialog Edit The editor can display a dialog box for editing the entire property.
paMultiSelect N/A The property should display when the user selects more than one component.
paAutoUpdate SetValue Updates the component after every change instead of waiting for approval of
the value.

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.

3.2.1.10.25 Specifying Menu Items


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 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

3.2.1.10.26 Specifying the Components


Within the Register procedure, pass the component names in an open array, which you can construct inside the call to
RegisterComponents.
RegisterComponents('Miscellaneous', [TMyComponent]);
TMetaClass classes[1] = {__classid(TNewComponent)};

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);

3.2.1.10.27 Specifying the Palette Page


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.

3.2.1.10.28 Troubleshooting Custom Components (C++)


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:

• Missing PACKAGE modifier on the Register function


• Missing PACKAGE modifier on the class
• Missing #pragma package(smart_init) in the C++ source file
• Register function is not found in a namespace with the same name as the source code module name.
• Register is not being successfully exported. Use tdump on the .BPL to look for the exported function:
tdump -ebpl mypack.bpl mypack.dmp
In the exports section of the dump, you should see the Register function (within the namespace) being exported.

3.2.1.10.29 Using the IsPropertyInCategory Function


An application can query the existing registered properties to determine whether a given property is already registered in a
specified category. This can be especially useful in situations like a localization utility that checks the categorization of properties
preparatory to performing its localization operations. Two overloaded variations of the IsPropertyInCategory function are
available, allowing for different criteria in determining whether a property is in a category.
3
The first variation lets you base the comparison criteria on a combination of the class type of the owning component and the
property's name. In the command line below, for IsPropertyInCategory to return True, the property must belong to a TCustomEdit
descendant, have the name "Text," and be in the property category 'Localizable'.
IsItThere := IsPropertyInCategory('Localizable', TCustomEdit, 'Text');
IsItThere = IsPropertyInCategory("Localizable", __classid(TCustomEdit), "Text");
The second variation lets you base the comparison criteria on a combination of the class name of the owning component and the
property's name. In the command line below, for IsPropertyInCategory to return True, the property must be a TCustomEdit

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");

3.2.1.10.30 Using the RegisterComponents Function


Within the Register procedure, call RegisterComponents to register the components in the classes array. RegisterComponents is
a function that takes two parameters: the name of a Tool palette category and the array of component classes.

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);
}
}

3.2.1.10.31 Writing the Register Procedure


Inside the Register procedure of a unit containing components, you must register each component you want to add to the Tool
3
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:

1. Specifying the components. ( see page 1355)


2. Specifying the palette page. ( see page 1356)
3. Using the RegisterComponents function ( see page 1357).

1357
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

3.2.1.11 Making a dialog box a component


Topics
Name Description
Adding Interface Properties ( see page 1359) Before proceeding, decide on the properties your wrapper needs to enable
developers to use your dialog box as a component in their applications. Then,
you can add declarations for those properties to the component's class
declaration.
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... more ( see page 1359)
Adding the Execute Method ( see page 1359) The final part of the component interface is a way to open the dialog box and
return a result when it closes. As with the common dialog box components, you
use a boolean function called Execute that returns True if the user clicks OK, or
False if the user cancels the dialog box.
The declaration for the Execute method always looks like this:
Creating and Registering the Component (Dialog Box) ( see page 1360) Creation of every component begins 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:

• Call the component's unit AboutDlg.


• Derive a new component type called TAboutBoxDlg,
descended from TComponent.
• Register TAboutBoxDlg on the Samples page of the Tool
palette.
The resulting unit should look like this:
Creating the Component Interface ( see page 1361) These are the steps to create the component interface:

1. Including the form unit files ( see page 1361).


2. Adding interface properties ( see page 1359).
3. Adding the Execute method ( see page 1359).
Defining the Component Interface ( see page 1361) Before you can create the component for your dialog box, you need to decide
how you want developers to use it. You create an interface between your dialog
box and applications that use it.
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... more ( see page 1361)
Including the Form Unit ( see page 1361) For your wrapper component to initialize and display the wrapped dialog box, you
must add the form's unit to the uses clause of the wrapper component's unit.
Append About to the uses clause of the AboutDlg unit.
The uses clause now looks like this:

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:

1. Defining the component interface ( see page 1361)


2. Creating and registering the component ( see page
1360)
3. Creating the component interface ( see page 1361)
4. Testing the component ( see page 1362)
The Delphi "wrapper" component associated with the dialog
box creates and executes the... more ( see page 1362)
Testing the Component ( see page 1362) Once you have installed the dialog box component, you can use it as you would
any of the common dialog boxes, by placing one on a form and executing it. A
quick way to test the About box is to add a command button to a form and
execute the dialog box when the user clicks the button.

3.2.1.11.1 Adding Interface Properties


Before proceeding, decide on the properties your wrapper needs to enable developers to use your dialog box as a component in
their applications. Then, you can add declarations for those properties to the component's class declaration.

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.

3.2.1.11.2 Adding the Execute Method


The final part of the component interface is a way to open the dialog box and return a result when it closes. As with the common
dialog box components, you use a boolean function called Execute that returns True if the user clicks OK, or False if the user
cancels the dialog box.

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.

3.2.1.11.3 Creating and Registering the Component (Dialog Box)


Creation of every component begins 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:

• Call the component's unit AboutDlg.


• Derive a new component type called TAboutBoxDlg, descended from TComponent.
• Register TAboutBoxDlg on the Samples page of the Tool palette.
The resulting unit should look like this:
unit AboutDlg;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms;
type
TAboutBoxDlg = class(TComponent)
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TAboutBoxDlg]);
end;
end.
#include <vcl\vcl.h>
#pragma hdrstop
#include "AboutDlg.h"
//---------------------------------------------------------------------------
#pragma package(smart_init);
//---------------------------------------------------------------------------
static inline TAboutBoxDlg *ValidCtrCheck()
{
return new TAboutBoxDlg(NULL);
}
//---------------------------------------------------------------------------
namespace AboutDlg {
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TAboutBoxDlg)};
RegisterComponents("Samples", classes, 0);
}
}
3 #ifndef AboutDlgH
#define AboutDlgH
//---------------------------------------------------------------------------
#include <vcl\sysutils.hpp>
#include <vcl\controls.hpp>
#include <vcl\classes.hpp>
#include <vcl\forms.hpp>
//---------------------------------------------------------------------------
class PACKAGE TAboutBoxDlg : public TComponent
{
private:

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.

3.2.1.11.4 Creating the Component Interface


These are the steps to create the component interface:

1. Including the form unit files ( see page 1361).


2. Adding interface properties ( see page 1359).
3. Adding the Execute method ( see page 1359).

3.2.1.11.5 Defining the Component Interface


Before you can create the component for your dialog box, you need to decide how you want developers to use it. You create an
interface between your dialog box and applications that use it.

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.

3.2.1.11.6 Including the Form Unit


For your wrapper component to initialize and display the wrapped dialog box, you must add the form's unit to the uses clause of
the wrapper component's unit.

Append About to the uses clause of the AboutDlg unit.

The uses clause now looks like this:


uses
Windows, SysUtils, Messages, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms,
About; 3
// for C++
#include "About.h"
#pragma link "About.obj"
The form unit always declares an instance of the form class. In the case of the About box, the form class is TAboutBox, and the
About unit includes the following declaration:
var
AboutBox: TAboutBox;
extern TAboutBox *AboutBox;

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.

3.2.1.11.7 Making a Dialog Box a Component: Overview


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:

1. Defining the component interface ( see page 1361)


2. Creating and registering the component ( see page 1360)
3. Creating the component interface ( see page 1361)
4. Testing the component ( see page 1362)
The Delphi "wrapper" component associated with the dialog box creates and executes the dialog box at runtime, passing along
the data the user specified. The dialog-box component is therefore both reusable and customizable.
In this section, you will see how to create a wrapper component around the generic About Box form provided in the Delphi Object
Repository.
Note: Copy the files ABOUT.PAS and ABOUT.DFM into your working directory.
There are not many special considerations for designing a dialog box that will be wrapped into a component. Nearly any form
can operate as a dialog box in this context.

3.2.1.11.8 Testing the Component


Once you have installed the dialog box component, you can use it as you would any of the common dialog boxes, by placing one
on a form and executing it. A quick way to test the About box is to add a command button to a form and execute the dialog box
when the user clicks the button.

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

3.2.1.12 Modifying an existing component


Topics
Name Description
Creating and Registering the Modified Component ( see page 1363) You create every component the same way: you create a unit, derive a
component class, register 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:

• Call the component's unit Memos.


• Derive a new component type called TWrapMemo,
descended from TMemo.
• Register TWrapMemo on the Samples page of the Tool
palette.
• The resulting unit should look like this:
Modifying an Existing Component: Overview ( see page 1365) The easiest way to create a component is to derive it from a component that
does nearly everything you want, then make whatever changes you need. What
follows is a simple example that modifies the standard memo component to
create a memo that does not wrap words by default.
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... more ( see page 1365)
Modifying the Component Object ( see page 1365) Once you have created a new component class, you can modify it in almost any
way. In this case, you will change only the initial value of one property in the
memo component. This involves two small changes to the component class:

• Overriding the constructor.


• Specifying the new default property value.
The constructor actually sets the value of the property. The
default tells Delphi what values to store in the form (.dfm
for VCL applications ) file. Delphi stores only values that
differ from the default, so it is important to perform both
steps.
Overriding the Constructor ( see page 1365) When a component is placed on a form at design time, or when an application
constructs a component at runtime, the component's constructor sets the
property values. When a component is loaded from a form file, the application
sets any properties changed at design time.
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... more ( see page 1365)
Specifying the New Default Property Value ( see page 1366) When Delphi stores a description of a form in a form file, it stores the values only
of properties that differ from their defaults. Storing only the differing values keeps
the form files small and makes loading the form faster. If you create a property or
change the default value, it is a good idea to update the property declaration to
include the new default. Form files, loading, and default values are explained in 3
more detail in Making components available at design time ( see page 1350).
To change the default value of a property, redeclare the property name, followed
by the directive... more ( see page 1366)

3.2.1.12.1 Creating and Registering the Modified Component


You create every component the same way: you create a unit, derive a component class, register it, and install it on the Tool
palette. This process is outlined in Creating a new component. ( see page 1317)

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:

• Call the component's unit Memos.


• Derive a new component type called TWrapMemo, descended from TMemo.
• Register TWrapMemo on the Samples page of the Tool palette.
• The resulting unit should look like this:
unit Memos;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, StdCtrls;
type
TWrapMemo = class(TMemo)
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TWrapMemo]);
end;
end.
#include <vcl.h>
#pragma hdrstop
#include "Yelmemo.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(TYellowMemo *)
{
new TYellowMemo(NULL);
}
//---------------------------------------------------------------------------
__fastcall TYellowMemo::TYellowMemo(TComponent* Owner)
: TMemo(Owner)
{
}
//---------------------------------------------------------------------------
namespace Yelmemo
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TYellowMemo)};
RegisterComponents("Samples", classes, 0); //"Common Controls" in CLX applications
}
}
#ifndef YelMemoH
#define YelmemoH
//---------------------------------------------------------------------------
#include <sysutils.hpp>
#include <controls.hpp>
3 #include <classes.hpp>
#include <forms.hpp>
#include <StdCtrls.hpp>
//---------------------------------------------------------------------------
class PACKAGE TYellowMemo : public TMemo
{
private:
protected:
public:
__published:
};

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.

3.2.1.12.2 Modifying an Existing Component: Overview


The easiest way to create a component is to derive it from a component that does nearly everything you want, then make
whatever changes you need. What follows is a simple example that modifies the standard memo component to create a memo
that does not wrap words by default.

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.

Modifying an existing component takes only two steps:

• Creating and registering the component ( see page 1363).


• Modifying the component class ( see page 1365).

3.2.1.12.3 Modifying the Component Object


Once you have created a new component class, you can modify it in almost any way. In this case, you will change only the initial
value of one property in the memo component. This involves two small changes to the component class:

• Overriding the constructor.


• Specifying the new default property value.
The constructor actually sets the value of the property. The default tells Delphi what values to store in the form (.dfm for VCL
applications ) file. Delphi stores only values that differ from the default, so it is important to perform both steps.

3.2.1.12.4 Overriding the Constructor


When a component is placed on a form at design time, or when an application constructs a component at runtime, the
component's constructor sets the property values. When a component is loaded from a form file, the application sets any
properties changed at design time.

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

WordWrap := False; { set the new desired value }


end;
class PACKAGE TYellowMemo : public TMemo
{
public:
virtual __fastcall TYellowMemo(TComponent* Owner); // the constructor declaration
__published:
__property Color;
};
__fastcall TYellowMemo::TYellowMemo(TComponent* Owner)
: TMemo(Owner) // the constructor implementation
first... // ...calls the constructor for TMemo
{
Color = clYellow; // colors the component yellow
}
Now you can install the new component on the Tool palette and add it to a form. Note that the WordWrap property is now
initialized to False.

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.

3.2.1.12.5 Specifying the New Default Property Value


When Delphi stores a description of a form in a form file, it stores the values only of properties that differ from their defaults.
Storing only the differing values keeps the form files small and makes loading the form faster. If you create a property or change
the default value, it is a good idea to update the property declaration to include the new default. Form files, loading, and default
values are explained in more detail in Making components available at design time ( see page 1350).

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

__property Color = {default=clYellow};


__property WordWrap = {default=false};
};
Specifying the default property value does not affect the workings of the component. You must still initialize the value in the
component's constructor. Redeclaring the default ensures that Delphi knows when to write WordWrap to the form file.

3.2.1.13 Object-oriented programming for component writers


Topics
Name Description
Object-oriented Programming for Component Writers: Overview ( see page If you have written applications with Delphi, you know that a class contains both
1369) data and code, and that you can manipulate classes at design time and at
runtime. In that sense, you've become a component user.
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,... more ( see page 1369)
Defining New Classes ( see page 1370) The difference between component writers and application developers is that
component writers create new classes while application developers manipulate
instances of classes.
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... more ( see page 1370)
Deriving New Classes ( see page 1370) There are two reasons to derive a new class:

• To change class defaults to avoid repetition ( see page


1371)
• To add new capabilities to a class ( see page 1370)
In either case, the goal is to create reusable objects. If you
design components with reuse in mind, you can save work
later on. Give your classes usable default values, but
allow them to be customized.
Abstract Class Members ( see page 1370) When a method is declared as abstract in an ancestor class, you should surface
it (by redeclaring and implementing it) in any descendant component before you
use the new component in applications. On the Win32 platform, Delphi can
create instances of a class that contains abstract members. This is not
recommended, however. For more information about surfacing inherited parts of
classes, see Creating properties ( see page 1249) and Creating methods. (
see page 1243)
Adding New Capabilities to a Class ( see page 1370) A common reason for creating new components is to add capabilities not found in
existing components. When you do this, you derive the new component from
either an existing component or an abstract base class, such as TComponent or
TControl.
Derive your new component from the class that contains the closest subset of the
features you want. You can add capabilities to 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... more ( see page 1370) 3
Ancestors, Descendants, and Class Hierarchies ( see page 1371) Application developers take for granted that every control has properties named
Top and Left that determine its position on the form. To them, it may not matter
that all controls inherit these properties from a common ancestor, TControl.
When you create a component, however, you must know which class to derive it
from so that it inherits the appropriate features. And you must know everything
that your control inherits, so you can take advantage of inherited features without
recreating them.
The class from which you derive a component is called its immediate ancestor.
Each component inherits from its... more ( see page 1371)

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

• The method does not exist in the ancestor class.


• The ancestor's method of that name is static.
• The declarations are not otherwise identical (number and
type of arguments parameters differ).
Regular Methods (C++) ( see page 1375) Class methods are regular (or nonvirtual) unless you specifically declare them as
virtual, or unless they override a virtual method in a base class. The compiler
can determine the exact address of a regular class member at compile time. This
is known as compile-time binding.
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...
more ( see page 1375)
Static Methods ( see page 1375) All methods are static unless you specify otherwise when you declare them.
Static methods work like regular procedures or functions. The compiler
determines the exact address of the method and links the method at compile time.
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 address of their methods at runtime, which takes somewhat longer.
A static method does not change when inherited by a descendant class.... more
( see page 1375)

3.2.1.13.1 Object-oriented Programming for Component Writers: Overview


If you have written applications with Delphi, you know that a class contains both data and code, and that you can manipulate
classes at design time and at runtime. In that sense, you've become a component user.

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):

• Defining new classes ( see page 1370)


• Ancestors ( see page 1371)
• Controlling access ( see page 1371)
• Dispatching methods ( see page 1373)

1369
Component Writer's Guide RAD Studio 3.2 Win32 Developer's Guide

• Abstract class members ( see page 1370)


• Classes and pointers ( see page 1374)

3.2.1.13.2 Defining New Classes


The difference between component writers and application developers is that component writers create new classes while
application developers manipulate instances of classes.

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)

Declaring a New Component Type ( see page 1372)

3.2.1.13.3 Deriving New Classes


There are two reasons to derive a new class:

• To change class defaults to avoid repetition ( see page 1371)


• To add new capabilities to a class ( see page 1370)
In either case, the goal is to create reusable objects. If you design components with reuse in mind, you can save work later on.
Give your classes usable default values, but allow them to be customized.

3.2.1.13.4 Abstract Class Members


When a method is declared as abstract in an ancestor class, you should surface it (by redeclaring and implementing it) in any
descendant component before you use the new component in applications. On the Win32 platform, Delphi can create instances
of a class that contains abstract members. This is not recommended, however. For more information about surfacing inherited
parts of classes, see Creating properties ( see page 1249) and Creating methods. ( see page 1243)

3.2.1.13.5 Adding New Capabilities to a Class


A common reason for creating new components is to add capabilities not found in existing components. When you do this, you
derive the new component from either an existing component or an abstract base class, such as TComponent or TControl.

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

3.2.1.13.6 Ancestors, Descendants, and Class Hierarchies


Application developers take for granted that every control has properties named Top and Left that determine its position on the
form. To them, it may not matter that all controls inherit these properties from a common ancestor, TControl. When you create a
component, however, you must know which class to derive it from so that it inherits the appropriate features. And you must know
everything that your control inherits, so you can take advantage of inherited features without recreating them.

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.

3.2.1.13.7 Changing Class Defaults to Avoid Repetition


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 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.

3.2.1.13.8 Controlling Access


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: 3
Levels of visibility within an object

Visibility Meaning Used for


private Accessible only to code in the unit where the class is Hiding implementation details. ( see page 1374)
defined.

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)

Defining the Component Writer's Interface ( see page 1373)

Defining the Runtime Interface ( see page 1373)

Defining the Design-time Interface ( see page 1372)

3.2.1.13.9 Declaring a New Component Class


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.

See Also
Deriving New Types ( see page 1370)

3.2.1.13.10 Defining the Design-time Interface


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 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)

Defining the Component Writer's Interface ( see page 1373)

Defining the Runtime Interface ( see page 1373)

1372
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

3.2.1.13.11 Defining the Component Writer's Interface


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 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)

Defining the Runtime Interface ( see page 1373)

Defining the Design-time Interface ( see page 1372)

3.2.1.13.12 Defining the Runtime Interface


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.

See Also
Hiding Implementation Details ( see page 1374)

Defining the Component Writer's Interface ( see page 1373)

Defining the Design-time Interface ( see page 1372)

3.2.1.13.13 Dispatching Methods


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
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.

3.2.1.13.15 Hiding Implementation Details


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.

See Also
Defining the Component Writer's Interface ( see page 1373)

Defining the Runtime Interface ( see page 1373)

Defining the Design-time Interface ( see page 1372)

3.2.1.13.16 Virtual Methods


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 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)

Overriding Methods ( see page 1374)

3.2.1.13.17 Classes and Pointers


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.

3.2.1.13.18 Overriding Methods


3
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

• The method does not exist in the ancestor class.


• The ancestor's method of that name is static.

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)

3.2.1.13.19 Regular Methods (C++)


Class methods are regular (or nonvirtual) unless you specifically declare them as virtual, or unless they override a virtual
method in a base class. The compiler can determine the exact address of a regular class member at compile time. This is known
as compile-time binding.

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();
}

3.2.1.13.20 Static Methods


All methods are static unless you specify otherwise when you declare them. Static methods work like regular procedures or
functions. The compiler determines the exact address of the method and links the method at compile time.

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

3.2.1.14 Using graphics in components


Topics
Name Description
Creating and Managing Off-screen Bitmaps ( see page 1378) When creating complex graphic images, you should avoid drawing them directly
on a canvas that appears onscreen. Instead of drawing on the canvas for a form
or control, you can construct a bitmap object, draw on its canvas, and then copy
its completed image to the onscreen canvas.
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:
Loading and Storing Graphics ( see page 1378) All pictures and graphics in Delphi can load their images from files and store
them back again (or into different files). You can load or store the image of a
picture at any time.
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... more ( see
page 1378)
Handling Palettes ( see page 1378) For VCL components, when running on a palette-based device (typically, a
256-color video mode), Delphi controls automatically support palette realization.
That is, if you have a control that has a palette, you can use two methods
inherited from TControl to control how Windows accommodates that palette.
Palette support for controls has these two aspects:

• Specifying a palette for a control ( see page 1380)


• Responding to palette changes ( see page 1380)
Most controls have no need for a palette, but controls that
contain "rich color" graphic images (such as the image
control) might need to interact with Windows and the
screen device driver to ensure the proper... more ( see
page 1378)
Off-screen Bitmaps ( see page 1379) When drawing complex graphic images, a common technique in graphics
programming is to create an off-screen bitmap, draw the image on the bitmap,
and then copy the complete image from the bitmap to the final destination
onscreen. Using an off-screen image reduces flicker caused by repeated drawing
directly to the screen.
The bitmap class in Delphi, which represents bitmapped images in resources and
files, can also work as an off-screen image.
There are two main aspects to working with off-screen bitmaps:

• Creating and managing off-screen bitmaps. ( see page


1378)
• Copying bitmapped images.
Overview of Graphics ( see page 1379) Delphi encapsulates the Windows GDI at several levels. The most important to
you as a component writer is the way components display their images on the
screen. When calling GDI functions directly, you need to have a handle to a
device context, into which you have selected various drawing tools such as pens,
brushes, and fonts. After rendering your graphic images, you must restore the
device context to its original state before disposing of it.
3 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...
more ( see page 1379)

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:

• 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 classes. By defining a
minimal standard interface for all graphics, TGraphic
provides a... more ( see page 1379)
Responding to Changes ( see page 1380) All graphic objects, including canvases and their owned objects (pens, brushes,
and fonts) have events built into them for responding to changes in the object. By
using these events, you can make your components (or the applications that use
them) respond to changes by redrawing their images.
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... more ( see page 1380)
Responding to Palette Changes ( see page 1380) If your VCL control specifies a palette by overriding GetPalette, Delphi
automatically takes care of responding to palette messages from Windows. The
method that handles the palette messages is PaletteChanged.
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... more ( see page 1380)
Specifying a Palette for a Control ( see page 1380) To specify a palette for a control, override the control's GetPalette method to
return the handle of the palette.
Specifying the palette for a control does these things for your application:

• It tells the application that your control's palette needs to


be realized.
• It designates the palette to use for realization.
Using Graphics in Components: Overview ( see page 1380) Windows provides a powerful graphics device interface (GDI) for drawing
device-independent graphics. The GDI, however, imposes extra requirements on
the programmer, such as managing graphic resources. Delphi takes care of all
the GDI drudgery, allowing you to focus on productive work instead of searching
for lost handles or unreleased resources.
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.
The topics in this section include:

• Overview of graphics ( see page 1379)


• Using the canvas ( see page 1381)
• Working with pictures ( see page 1381)... more ( see
page 1380)
Using the Canvas ( see page 1381) The canvas class encapsulates graphics controls at several levels, including
high-level functions for drawing individual lines, shapes, and text; intermediate 3
properties for manipulating the drawing capabilities of the canvas; and in the
component library, provides low-level access to the Windows GDI.
The following table summarizes the capabilities of the canvas.
Canvas capability summary

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:

• Using a picture ( see page 1379)


• Loading and storing graphics ( see page 1378)
• Handling palettes ( see page 1378)

3.2.1.14.1 Creating and Managing Off-screen Bitmaps


When creating complex graphic images, you should avoid drawing them directly on a canvas that appears onscreen. Instead of
drawing on the canvas for a form or control, you can construct a bitmap object, draw on its canvas, and then copy its completed
image to the onscreen canvas.

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;

3.2.1.14.2 Loading and Storing Graphics


All pictures and graphics in Delphi can load their images from files and store them back again (or into different files). You can
load or store the image of a picture at any time.

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.

3 3.2.1.14.3 Handling Palettes


For VCL components, when running on a palette-based device (typically, a 256-color video mode), Delphi controls automatically
support palette realization. That is, if you have a control that has a palette, you can use two methods inherited from TControl to
control how Windows accommodates that palette.

Palette support for controls has these two aspects:

• Specifying a palette for a control ( see page 1380)

1378
3.2 Win32 Developer's Guide RAD Studio Component Writer's Guide

• Responding to palette changes ( see page 1380)


Most controls have no need for a palette, but controls that contain "rich color" graphic images (such as the image control) might
need to interact with Windows and the screen device driver to ensure the proper appearance of the control. Windows refers to
this process as realizing palettes.
Realizing palettes is the process of ensuring that the foremost window uses its full palette, and that windows in the background
use as much of their palettes as possible, then map any other colors to the closest available colors in the "real" palette. As
windows move in front of one another, Windows continually realizes the palettes.
Note: Delphi itself provides no specific support for creating or maintaining palettes, other than in bitmaps. If you have a
palette handle, however, Delphi controls can manage it for you.

3.2.1.14.4 Off-screen Bitmaps


When drawing complex graphic images, a common technique in graphics programming is to create an off-screen bitmap, draw
the image on the bitmap, and then copy the complete image from the bitmap to the final destination onscreen. Using an
off-screen image reduces flicker caused by repeated drawing directly to the screen.

The bitmap class in Delphi, which represents bitmapped images in resources and files, can also work as an off-screen image.

There are two main aspects to working with off-screen bitmaps:

• Creating and managing off-screen bitmaps. ( see page 1378)


• Copying bitmapped images.

3.2.1.14.5 Overview of Graphics


Delphi encapsulates the Windows GDI at several levels. The most important to you as a component writer is the way
components display their images on the screen. When calling GDI functions directly, you need to have a handle to a device
context, into which you have selected various drawing tools such as pens, brushes, and fonts. After rendering your graphic
images, you must restore the device context to its original state before disposing of it.

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.

3.2.1.14.7 Responding to Changes


All graphic objects, including canvases and their owned objects (pens, brushes, and fonts) have events built into them for
responding to changes in the object. By using these events, you can make your components (or the applications that use them)
respond to changes by redrawing their images.

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.

3.2.1.14.8 Responding to Palette Changes


If your VCL control specifies a palette by overriding GetPalette, Delphi automatically takes care of responding to palette
messages from Windows. The method that handles the palette messages is PaletteChanged.

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.

3.2.1.14.9 Specifying a Palette for a Control


To specify a palette for a control, override the control's GetPalette method to return the handle of the palette.

Specifying the palette for a control does these things for your application:

• It tells the application that your control's palette needs to be realized.


• It designates the palette to use for realization.

3.2.1.14.10 Using Graphics in Components: Overview


3 Windows provides a powerful graphics device interface (GDI) for drawing device-independent graphics. The GDI, however,
imposes extra requirements on the programmer, such as managing graphic resources. Delphi takes care of all the GDI drudgery,
allowing you to focus on productive work instead of searching for lost handles or unreleased resources.

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.

The topics in this section include:

• Overview of graphics ( see page 1379)

1380
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

• Using the canvas ( see page 1381)


• Working with pictures ( see page 1381)
• Off-screen bitmaps ( see page 1379)
• Responding to changes ( see page 1380)

3.2.1.14.11 Using the Canvas


The canvas class encapsulates graphics controls at several levels, including high-level functions for drawing individual lines,
shapes, and text; intermediate properties for manipulating the drawing capabilities of the canvas; and in the component library,
provides low-level access to the Windows GDI.

The following table summarizes the capabilities of the canvas.

Canvas capability summary

Level Operation Tools


High Drawing lines and shapes Methods such as MoveTo, LineTo, Rectangle, and Ellipse
Displaying and measuring text TextOut, TextHeight, TextWidth, and TextRect methods
Filling areas FillRect and FloodFill methods
Intermediate Customizing text and graphics Pen, Brush, and Font properties
Manipulating pixels Pixels property.
Copying and merging images Draw, StretchDraw, BrushCopy, and CopyRect methods; CopyMode
property
Low Calling Windows GDI functions Handle property

3.2.1.14.12 Working with Pictures


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:

• Using a picture ( see page 1379)


• Loading and storing graphics ( see page 1378)
• Handling palettes ( see page 1378)

3.2.2 Developing COM-based Applications


3
Contains the Developer's Guide topics for creating COM-based applications in Delphi.

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

Creating simple COM servers ( see page 1427)


Working with type libraries ( see page 1441)

3.2.2.1 COM basics


Topics
Name Description
Overview of COM Technologies ( see page 1385) 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 or servers that
implement COM objects, Automation servers (including Active Server Objects),
ActiveX controls, or ActiveForms.
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... more ( see page 1385)
Parts of a COM Application ( see page 1386) When implementing a COM application, you supply the following:
COM Interfaces ( see page 1386) 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. The standard way
to depict a COM interface is as follows:

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

• 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... more ( see page 1390)
Aggregation (COM) ( see page 1391) Sometimes, a server object makes use of another COM object to perform some
of its functions. For example, an inventory management object might make use of
a separate invoicing object to handle customer invoices. If the inventory
management object wants to present the invoice interface to clients, however,
there is a problem: Although a client that has the inventory interface can call
QueryInterface to obtain the invoice interface, when the invoice object was
created it did not know about the inventory management object and can't return
an inventory interface in response to a call to QueryInterface. A client that... more
( see page 1391)
COM Clients ( see page 1391) 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 (or even where) an object provides the services; they simply
rely on server objects to provide the services they advertise through their
interfaces.
There are two types of COM clients, controllers and containers.... more ( see
page 1391)
COM Extensions ( see page 1392) COM was originally designed to provide core communication functionality and to
enable the broadening of this functionality through extensions. COM itself has
extended its core functionality by defining specialized sets of interfaces for
specific purposes.
The following lists some of the services COM extensions currently provide.
Automation Servers ( see page 1393) Automation refers to the ability of an application to control the objects in another
application programmatically, like 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.
Automation is characterized by two key points:

• 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... more ( see page 1393)
Active Server Pages ( see page 1393) The Active Server Page (ASP) technology lets you write simple scripts, called
Active Server Pages, that can be launched by clients via a Web server. Unlike
ActiveX controls, which run on the client, Active Server Pages run on the server, 3
and return a resulting HTML page to clients.
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... more ( see
page 1393)

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:

• A simple COM object


• An Automation object
• A COM+ Event Object
• A Type library
• An ActiveX library
The wizards handle many of the tasks involved in creating
each type of COM object. They provide the required COM
interfaces for each type of object. With a simple COM
object, the wizard implements the one required COM
interface, IUnknown, which provides an interface pointer
to the object.

The COM object... more ( see page 1397)

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)

3.2.2.1.1 Overview of COM Technologies


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 or servers that implement COM objects, Automation servers (including Active Server Objects),
ActiveX controls, or ActiveForms.

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).

COM as a specification and implementation


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
process spaces and on different platforms. As long as the objects adhere to the written specification, they can communicate. 3
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 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)

Creating Active Server Pages: Overview ( see page 1400)

3.2.2.1.2 Parts of a COM Application


When implementing a COM application, you supply the following:

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.2.2.1.3 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. The standard way to depict
a COM interface is as follows:

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.

Key aspects of COM interfaces are as follows:

• 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)

COM Interface Pointers ( see page 1387)

3.2.2.1.4 The Fundamental COM Interface, IUnknown


All COM objects must support the fundamental interface, called IUnknown, a typedefto the base interface type IInterface.
IUnknown contains the following routines:

QueryInterface Provides pointers to other interfaces that the object supports.


AddRef and Simple reference counting methods that keep track of the object's lifetime so that an object can delete itself
Release when the client no longer needs its service.

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)

COM Interface Pointers ( see page 1387)

3.2.2.1.5 COM Interface Pointers


An interface pointer is a pointer to an object instance that points, in turn, to the implementation of each method in the interface. 3
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 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)

COM Interfaces ( see page 1386)

3.2.2.1.6 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 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.

As a minimum, a COM server must perform the following:

• 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)

CoClasses and Class Factories ( see page 1388)

In-process ( see page 1389)

3.2.2.1.7 CoClasses and Class Factories


A COM object is an instance of a CoClass, which is a class that implements one or more COM interfaces. The COM object

1388
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

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.)

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 ( see page 1389)

Aggregation ( see page 1391)

3.2.2.1.8 In-process, Out-of-process, and Remote Servers


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:

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)

COM Servers ( see page 1388)

The Marshaling Mechanism ( see page 1390)

Aggregation ( see page 1391)

3.2.2.1.9 The Marshaling Mechanism


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

• 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)

Automation ( see page 1393)

Aggregation ( see page 1391)

3.2.2.1.10 Aggregation (COM)


Sometimes, a server object makes use of another COM object to perform some of its functions. For example, an inventory
management object might make use of a separate invoicing object to handle customer invoices. If the inventory management
object wants to present the invoice interface to clients, however, there is a problem: Although a client that has the inventory
interface can call QueryInterface to obtain the invoice interface, when the invoice object was created it did not know about the
inventory management object and can't return an inventory interface in response to a call to QueryInterface. A client that has the
invoice interface can't get back to the inventory interface.

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)

Automation ( see page 1393)

The Marshaling Mechanism ( see page 1390)

3.2.2.1.11 COM Clients


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 (or even where) an object provides the services; they simply rely on server objects to
provide the services they advertise through their interfaces.

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)

3.2.2.1.12 COM Extensions


COM was originally designed to provide core communication functionality and to enable the broadening of this functionality
through extensions. COM itself has extended its core functionality by defining specialized sets of interfaces for specific purposes.

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.

COM object requirements

1392
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

Object Visual Process space Communication Type library


Object?
Active Document Usually In-process, or OLE Verbs No
out-of-process
Automation Occasionally In-process, Automatically marshaled using the IDispatch Required for
Server out-of-process, or remote interface (for out-of process and remote automatic
servers) marshaling
ActiveX Control Usually In-process Automatically marshaled using the IDispatch Required
interface
COM+ Occasionally In-process for MTS,any Automatically marshaled via a type library Required
for COM+
In-process Optionally In-process No marshaling required for in-process servers Recommended
custom interface
object
Other custom Optionally In-process,out-of-process, Automatically marshaled via a type library; Recommended
interface object or remote otherwise, manually marshaled using custom
interfaces

3.2.2.1.13 Automation Servers


Automation refers to the ability of an application to control the objects in another application programmatically, like 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.

Automation is characterized by two key points:

• 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)

Working with Type Libraries: Overview ( see page 1445)


3
Creating Active Server Pages ( see page 1400)

3.2.2.1.14 Active Server Pages


The Active Server Page (ASP) technology lets you write simple scripts, called Active Server Pages, that can be launched by
clients via a Web server. Unlike ActiveX controls, which run on the client, Active Server Pages run on the server, and return a

1393
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide

resulting HTML page to clients.

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)

Working with Type Libraries: Overview ( see page 1445)

3.2.2.1.15 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 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 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)

3.2.2.1.16 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.

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.

3.2.2.1.17 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
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.

The content of type libraries


Type libraries contain type information, which indicates which interfaces exist in which COM objects, and the types and numbers
of arguments to the interface methods. These descriptions include the unique identifiers for the CoClasses (CLSIDs) and the
interfaces (IIDs), so that they can be properly accessed, as well as the dispatch identifiers (dispIDs) for Automation interface
methods and properties.

Type libraries can also contain the following information:

• Descriptions of custom type information associated with custom interfaces


• Routines that are exported by the Automation or ActiveX server, but that are not interface methods
• Information about enumeration, record (structures), unions, alias, and module data types
• References to type descriptions from other type libraries
Creating type libraries
With traditional development tools, you create type libraries by writing scripts in the Interface Definition Language (IDL) or the
Object Description Language (ODL), then running that script through a compiler. However, Delphi automatically generates a type
library when you create a COM object (including ActiveX controls, Automation objects, remote data modules, and so on) using
any of the wizards on either the ActiveX or Multitier page of the new items dialog. You can also create a type library by choosing
File New Other, selecting the ActiveX folder under Delphi Projects or C++Builder Projects, and in the right pane choosing
Type Library.

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:

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.

Benefits of using type libraries


Even if your application does not require a type library, you can consider the following benefits of using one:

• Type checking can be performed at compile time.


• You can use early binding with Automation, and controllers that do not support vtables or dual interfaces can encode dispIDs
at compile time, improving runtime performance.
• Type browsers can scan the library, so clients can see the characteristics of your objects.
• The RegisterTypeLib function can be used to register your exposed objects in the registration database.
• The UnRegisterTypeLib function can be used to completely uninstall an application's type library from the system registry.
• Local server access is improved because Automation uses information from the type library to package the parameters that
are passed to an object in another process.
3
• GenTLB.exe is a utility provided by CodeGear that generates a .tlb file from a RIDL file (an intermediate text-based file used
by the Type Library Editor).
Using type library tools
The tools for working with type libraries are listed below.

• 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)

3.2.2.1.18 Implementing COM Objects with Wizards


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:

• A simple COM object


• An Automation object
• A COM+ Event Object
• A Type library
• An ActiveX library
The wizards handle many of the tasks involved in creating each type of COM object. They provide the required COM interfaces
for each type of object. With a simple COM object, the wizard implements the one required COM interface, IUnknown, which
provides an interface pointer to the object.

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

Wizard Implemented What the wizard does


interfaces
COM server IUnknown Exports routines that handle server registration, class registration, loading and unloading the
( see page (and IDispatch server, and object instantiation.
1430) if you select a Creates and manages class factories for objects implemented on the server.
default
Provides registry entries for the object that specify the selected threading model.
interface that
descends Declares the methods that implement a selected interface, providing skeletal implementations
from for you to complete.
IDispatch) Provides a type library, if requested.
Allows you to select an arbitrary interface that is registered in the type library and implement it.
If you do this, you must use a type library.
Automation IUnknown, Performs the tasks of a COM server wizard (described above), plus:
server ( IDispatch Implements the interface that you specify, either dual or dispatch.
see page
Provides server-side support for generating events, if requested.
1432)
Provides a type library automatically.
COM+ Event None, by Creates a COM+ event object that you can define using the Type Library editor. Unlike the
object default other object wizards, the COM+ Event object wizard does not create an implementation unit
because event objects have no implementation (it is provided by event subscriber objects).
Type Library None, by Creates a new type library and associates it with the active project.
( see page default
1445)
ActiveX None, by Creates a new ActiveX or Com server DLL and exposes the necessary export functions.
library default

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.2.2.1.19 Code Generated by Wizards


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:

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:

DAX Base classes for generated implementation classes

1398
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

Wizard Base class from Inherited support


DAX

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.

3.2.2.1.20 COM+ Event And Event Subscriber Objects


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+ 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

3.2.2.2 Creating an Active Server Page


Topics
Name Description
Creating Active Server Pages: Overview ( see page 1400) If you are using the Microsoft Internet Information Server (IIS) environment to
serve your Web pages, you can use Active Server Pages (ASP) to create
dynamic Web-based client/server applications. Active Server Pages let you write
a script that gets called every time the server loads the Web page. This script
can, in turn, call on Automation objects ( see page 1430) to obtain information
that it includes in a generated HTML page. For example, you can write a Delphi
Automation server, such as one to create a bitmap or connect to a database, and
use this control to access data that gets updated every... more ( see page
1400)
Creating an Active Server Object ( see page 1401) An Active Server Object is an Automation object that has access to information
about the entire ASP application and the HTTP messages it uses to
communicate with browsers. It descends from TASPObject or TASPMTSObject
(which is in turn a descendant of TAutoObject), and supports Automation
protocols, exposing itself for other applications (or the script in the Active Server
page) to use. You create an Active Server Object using the Active Server Object
wizard.
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 ( see page 1405)... more ( see page 1401)
Using the ASP Intrinsics ( see page 1402) The ASP intrinsics are a set of COM objects supplied by ASP to the objects
running in an Active Server Page. They let your Active Server Object access
information that reflects the messages passing between your application and the
Web browser, as well as a place to store information that is shared among Active
Server Objects that belong to the same ASP application.
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... more ( see page 1402)
Creating ASPs for In-process or Out-of-process Servers ( see page 1405) You can use Server.CreateObject in an ASP page to launch either an
in-process or out-of-process ( see page 1389) server, depending on your
requirements. However, launching in-process servers is more common.
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... more ( see page 1405)
Registering an Active Server Object ( see page 1405) You can register the Active Server Page as an in-process or an out-of-process
server ( see page 1405). However, in-process servers are more common.
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.
Testing and Debugging the Active Server Page Application ( see page 1406) Debugging any in-process server such as an Active Server Object is much like
debugging a DLL. You choose a host application that loads the DLL, and debug
as usual.

3.2.2.2.1 Creating Active Server Pages: Overview


If you are using the Microsoft Internet Information Server (IIS) environment to serve your Web pages, you can use Active Server
3 Pages (ASP) to create dynamic Web-based client/server applications. Active Server Pages let you write a script that gets called
every time the server loads the Web page. This script can, in turn, call on Automation objects ( see page 1430) to obtain
information that it includes in a generated HTML page. For example, you can write a Delphi Automation server, such as one to
create a bitmap or connect to a database, and use this control to access data that gets updated every time the server loads the
Web page.

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)

Creating Simple COM Servers: Overview ( see page 1430)

3.2.2.2.2 Creating an Active Server Object


An Active Server Object is an Automation object that has access to information about the entire ASP application and the HTTP
messages it uses to communicate with browsers. It descends from TASPObject or TASPMTSObject (which is in turn a
descendant of TAutoObject), and supports Automation protocols, exposing itself for other applications (or the script in the Active
Server page) to use. You create an Active Server Object using the Active Server Object wizard.

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).

To display the Active Server Object wizard:


1. Choose File New Other.
2. Select the folder labeled ActiveX under Delphi Projects.
3. Double-click the Active Server Object icon. In the wizard, give your new Active Server Object a name, and specify the
instancing ( see page 1433) and threading ( see page 1433) models you want to support. These details influence the way
your object can be called. You must write the implementation so that it adheres to the model (for example, avoiding thread 3
conflicts). The thing that makes an Active Server Object unique is its ability to access information about the ASP application
and the HTTP messages that pass between the Active Server page and client Web browsers. This information is accessed
using the ASP intrinsics ( see page 1402). In the wizard, you can specify how your object accesses these by setting the
Active Server Type:
• If you are working with IIS 3 or IIS 4, you use Page Level Event Methods. Under this model, your object implements the
methods, OnStartPage and OnEndPage, which are called when the Active Server page loads and unloads. When your object
is loaded, it automatically obtains an IScriptingContext interface, which it uses to access the ASP intrinsics. These interfaces
are, in turn, surfaced as properties inherited from the base class (TASPObject).

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)

Using the Automation Object Wizard ( see page 1432)

Code Generated by Wizards ( see page 1398)

Creating Simple COM Servers: Overview ( see page 1430)

3.2.2.2.3 Using the ASP Intrinsics


The ASP intrinsics are a set of COM objects supplied by ASP to the objects running in an Active Server Page. They let your
Active Server Object access information that reflects the messages passing between your application and the Web browser, as
well as a place to store information that is shared among Active Server Objects that belong to the same ASP application.

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.

IApplicationObject includes the following:

IApplicationObject interface members

Property, Method, Meaning


or Event
3
Contents property Lists all the objects that were added to the application using script commands. This interface has two
methods, Remove and RemoveAll, that you can use to delete one or all objects from the list.
StaticObjects Lists all the objects that were added to the application with the <OBJECT> tag.
property
Lock method Prevents other clients from locking the Application object until you call Unlock. All clients should call Lock
before accessing shared memory (such as the properties).

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.

IRequest includes the following:

IRequest interface members

Property, Method, Meaning


or Event
ClientCertificate Indicates the values of all fields in the client certificate that is sent with the HTTP message.
property
Cookies property Indicates the values of all Cookie headers on the HTTP message.
Form property Indicates the values of form elements in the HTTP body. These can be accessed by name.
QueryString property Indicates the values of all variables in the query string from the HTTP header.
ServerVariables Indicates the values of various environment variables. These variables represent most of the common
property HTTP header variables.
TotalBytes property Indicates the number of bytes in the request body. This is an upper limit on the number of bytes
returned by the BinaryRead method.
BinaryRead method Retrieves the content of a Post message. Call the method, specifying the maximum number of bytes to
read. The resulting content is returns as a Variant array of bytes. After calling BinaryRead, you can't use
the Form property.

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.

IResponse includes the following:

IResponse interface members

Property, Method, or Meaning


Event
Cookies property Determines the values of all Cookie headers on the HTTP message.
Buffer property Indicates whether page output is buffered When page output is buffered, the server does not send
a response to the client until all of the server scripts on the current page are processed.
CacheControl property Determines whether proxy servers can cache the output in the response. 3
Charset property Adds the name of the character set to the content type header.
ContentType property Specifies the HTTP content type of the response message's body.
Expires property Specifies how long the response can be cached by a browser before it expires.
ExpiresAbsolute property Specifies the date and time when the response expires.
IsClientConnected Indicates whether the client has disconnected from the server.
property

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.

ISessionObject includes the following:

ISessionObject interface members

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.

IServer includes the following:

IServer interface members

1404
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

Property, Method, or Meaning


Event
ScriptTimeOut property Same as the TimeOut property on the Session object.
CreateObject method Instantiates a specified Active Server Object.
Execute method Executes the script in a specified .asp file.
GetLastError method Returns an ASPError object that describes the error condition.
HTMLEncode method Encodes a string for use in an HTML header, replacing reserved characters by the appropriate
symbolic constants.
MapPath method Maps a specified virtual path (an absolute path on the current server or a path relative to the
current page) into a physical path.
Transfer method Sends all of the current state information to another Active Server Page for processing.
URLEncode method Applies URL encoding rules, including escape characters, to a specified string

See Also
Creating ASPs for In-process or Out-of-process Servers ( see page 1405)

Defining a COM Object's Interface ( see page 1435)

3.2.2.2.4 Creating ASPs for In-process or Out-of-process Servers


You can use Server.CreateObject in an ASP page to launch either an in-process or out-of-process ( see page 1389) server,
depending on your requirements. However, launching in-process servers is more common.

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)

3.2.2.2.5 Registering an Active Server Object


You can register the Active Server Page as an in-process or an out-of-process server ( see page 1405). However, in-process
servers are more common.

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.

Registering an in-process server


To register an in-process server (DLL or OCX), choose Run Register ActiveX Server.

To unregister an in-process server, choose Run Unregister ActiveX Server.

Registering an out-of-process server


To register an out-of-process server, run the server with the /regserver command-line option. You can also register the server by
running it.

To unregister an out-of-process server, run the server with the /unregserver command-line option.

3.2.2.2.6 Testing and Debugging the Active Server Page Application


Debugging any in-process server such as an Active Server Object is much like debugging a DLL. You choose a host application
that loads the DLL, and debug as usual.

To test and debug an Active Server Object,


1. Turn on debugging information using the Compiler tab on the Project Options dialog box, if necessary. Also, turn on
Integrated Debugging in the Tools Options Debugger Options dialog.
2. Choose Run Parameters, type the name of your Web Server in the Host Application box, and choose OK.
3. Choose Run Run.
4. Set breakpoints in the Active Server Object implementation.
5. Use the Web browser to interact with the Active Server Page.
The debugger pauses when the breakpoints are reached.

3.2.2.3 Using ActiveX controls


Topics
Name Description
Elements of an ActiveX Control ( see page 1408) An ActiveX control involves many elements which each perform a specific
function. The elements include a VCL control, a corresponding COM object
wrapper that exposes properties, methods, and events, and one or more
associated type libraries.
Designing an ActiveX Control ( see page 1409) When designing an ActiveX control, you start by creating a custom VCL control.
This forms the basis of your ActiveX control. For information on creating custom
controls, see Creating custom components ( see page 1313).
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.
In addition, you should make... more ( see page 1409)
3
Generating an ActiveX Control Based On a VCL Form ( see page 1410) Unlike other ActiveX controls, Active Forms are not first designed and then
wrapped by an ActiveX wrapper class. Instead, the ActiveForm wizard generates
a blank form that you design later when the wizard leaves you in the Form
Designer.
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,... more ( see page 1410)

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:

1. Add DefinePropertyPage with the GUID constant of the


property page as the parameter to the
DefinePropertyPages method implementation in the
control's implementation for the unit. For example,
procedure
TButtonX.DefinePropertyPages(DefineProperty
Page:
TDefinePropertyPage); begin
DefinePropertyPage(Class_PropertyPage1);
>end; BEGIN_PROPERTY_MAP(TActiveFormXImpl)
// Define property pages here. Property
pages are defined using // the PROP_PAGE
macro with the class id of the page. For
example, //
PROP_PAGE(CLSID_ActiveFormXPage)
PROP_PAGE(CLSID_PropertyPage1)
END_PROPERTY_MAP() The GUID constant,
Class_PropertyPage1, of the property page can be found
3 in the property pages unit. The GUID... more ( see page
1417)

3.2.2.3.1 Elements of an ActiveX Control


An ActiveX control involves many elements which each perform a specific function. The elements include a VCL control, a
corresponding COM object wrapper that exposes properties, methods, and events, and one or more associated type libraries.

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).

3.2.2.3.2 Designing an ActiveX Control


When designing an ActiveX control, you start by creating a custom VCL control. This forms the basis of your ActiveX control. For
information on creating custom controls, see Creating custom components ( see page 1313).

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)

Elements of an ActiveX Control ( see page 1408)

3.2.2.3.3 Generating an ActiveX Control Based On a VCL Form


Unlike other ActiveX controls, Active Forms are not first designed and then wrapped by an ActiveX wrapper class. Instead, the
ActiveForm wizard generates a blank form that you design later when the wizard leaves you in the Form Designer.

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.

To start the ActiveForm wizard,


1. Choose File New Other to open the New Items dialog box.
2. Select the tab labeled ActiveX.
3. Double-click the ActiveForm icon.
On the Active Form wizard, you can't specify the name of the VCL class to wrap. This is because Active forms are always based
on TActiveForm.
You can change the default names for the CoClass, implementation unit, and ActiveX library project. Similarly, this wizard lets
you indicate whether you want your Active Form to require a license, whether it should include version information, and
whether you want an About box form.
When you exit the wizard, it generates the following:
• An ActiveX Library project file, which contains the code required to start an ActiveX control. You usually don't change this file.
• A type library, which defines and CoClass for your control, the interface it exposes to clients, and any type definitions that
these require. For more information about the type library, see Working with type libraries ( see page 1445).
• A form that descends from TActiveForm. This form appears in the form designer, where you can use it to visually design the
Active Form that appears to clients. Its implementation appears in the generated implementation unit. In the initialization
section of the implementation unit, a class factory is created, setting up TActiveFormControl as the ActiveX wrapper for this
form.
• An About box form and unit if you requested them.
• A .LIC file if you enabled licensing.
At this point, you can add controls and design the form as you like.
After you have designed and compiled the ActiveForm project into an ActiveX library (which has the OCX extension), you can
deploy the project to your Web server and Delphi creates a test HTML page with a reference to the ActiveForm.
See Also
Elements of an ActiveX Control ( see page 1408)
3 Implementing COM objects with Wizards ( see page 1397)

Code Generated by Wizards ( see page 1398)

3.2.2.3.4 Licensing ActiveX Controls


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.

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.

3.2.2.3.5 Customizing the ActiveX Control's Interface


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 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

implementation that indicates the problem.

See Also
Generating an ActiveX Control Based On a VCL Form ( see page 1410)

3.2.2.3.6 Adding Additional Properties, Methods, and Events


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).

See Also
Customizing the ActiveX Control's Interface ( see page 1411)

3.2.2.3.7 How Delphi Adds Properties


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 you must
implement, just as when you add a method to the interface, the wrapper class gains a corresponding method for you to
implement. Thus, adding properties to the wrapper class's interface is essentially the same as adding methods: the wrapper
class definition gains new skeletal method implementations for you to complete.

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;

procedure TButtonX.Set_Caption(const Value: WideString);


begin
FDelphiControl.Caption := TCaption(Value);
end;
STDMETHODIMP TButtonXImpl::get_Caption(BSTR* Value)
{
try
{
*Value = WideString(m_VclCtl->Caption).Copy();
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
STDMETHODIMP TButtonXImpl::set_Caption(BSTR Value)
{
try
{
m_VclCtl->Caption = AnsiString(Value);
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
In some cases, you may need to add code to convert the COM data types to native Delphi types. The preceding example
manages this with typecasting.

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)

3.2.2.3.8 How Delphi Adds Events


The ActiveX control can fire events to its container in the same way that an automation object fires events to clients. This

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.

Use the type library to enable simple data binding,


1. On the toolbar, click the property that you want to bind.
2. Choose the flags page.
3. Select the following binding attributes:

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)

3.2.2.3.10 Creating a Property Page for an ActiveX Control


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.

The process of creating a property page is similar to creating a form, you


1. Create a new property page ( see page 1416).
2. Add controls to the property page ( see page 1416).
3. Associate the controls the property page with the properties of an ActiveX control ( see page 1416). 3
4. Connect the property page to the ActiveX control ( see page 1417).
Note: When adding properties to an ActiveX control or ActiveForm, you must publish the properties that you want to persist.
If they are not published in the underlying VCL control, you must make a custom descendant of the VCL control that
redeclares the properties as published and then create an ActiveX control from the descendant class.

1415
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide

3.2.2.3.11 Creating a New Property Page


You use the Property Page wizard to create a new property page.

To create a new property page,


1. Choose File New Other.
2. Select the ActiveX folder under Delphi Projects .
3. Double-click the Property Page icon in the right pane.
The wizard creates a new form and implementation unit for the property page. The form is a descendant of TPropertyPage,
which lets you associate the form with the ActiveX control whose properties it edits.
See Also
Creating a Property Page for an ActiveX Control ( see page 1415)

3.2.2.3.12 Adding Controls to a Property Page


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.

See Also
Creating a Property Page for an ActiveX Control ( see page 1415)

3.2.2.3.13 Associating Property Page Controls with ActiveX Control Properties


After adding the controls you need to the property page, you must associate 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.

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&apos;s edit control (InputMask) with tthe current value of the ActiveX
control&apos;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)

3.2.2.3.15 Updating the Object


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):
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)

3.2.2.3.16 Connecting a Property Page to an ActiveX Control


Describes the steps in connecting an ActiveX control to a property page.

To connect a property page to an ActiveX control: 3


1. Add DefinePropertyPage with the GUID constant of the property page as the parameter to the DefinePropertyPages method
implementation in the control's implementation for the unit. For example, procedure
TButtonX.DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage); begin
DefinePropertyPage(Class_PropertyPage1); >end; BEGIN_PROPERTY_MAP(TActiveFormXImpl) //
Define property pages here. Property pages are defined using // the PROP_PAGE macro with
the class id of the page. For example, // PROP_PAGE(CLSID_ActiveFormXPage)
PROP_PAGE(CLSID_PropertyPage1) END_PROPERTY_MAP() The GUID constant, Class_PropertyPage1, of the
property page can be found in the property pages unit. The GUID is defined in the property page's implementation unit .

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)

3.2.2.4 Creating COM clients


Topics
Name Description
Creating COM Clients ( see page 1419) COM clients are applications that make use of a COM object implemented by
another application or library. The most common types are applications that
control an Automation server ( see page 1430) (Automation controllers) and
applications that host an ActiveX control (ActiveX containers).
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... more ( see page 1419)
Importing Type Library Information ( see page 1420) To make information about the COM server available to your client application,
you must import the information about the server that is stored in the server's
type library ( see page 1395). Your application can then use the resulting
generated classes to control the server object.
There are two ways to import type library information:

• 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... more ( see page 1420)
Code Generated When You Import Type Library Information ( see page 1421) Once you import a type library, you can view the generated TypeLibName_TLB
unit. At the top, you will find the following:
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,... more ( see page 1421)
Controlling an Imported Object ( see page 1422) After importing type library information ( see page 1420), you are ready to start
programming with the imported objects. How you proceed depends in part on the
objects, and in part on whether you have chosen to create component wrappers.
There are two basic approaches:

• Using component wrappers ( see page 1422).

3 • Writing client code based on type library definitions ( see


page 1423).

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:

• Connect to the server ( see page 1424).


• Control the Automation server using a dual interface (
see page 1424).
• Control the Automation server using a dispinterface (
see page 1424).
• Respond to events generated by the Automation ( see
page 1425)... more ( see page 1423)
Connecting to a Server ( see page 1424) Before you can drive an Automation server from your controller application, you
must obtain a reference to an interface it supports. Typically, you connect to a
server through its main interface.
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... more ( see page 1424)
Controlling an Automation Server Using a Dual Interface ( see page 1424) After using the automatically generated creator class to connect to the server (
see page 1424), you call methods of the interface. For example,
Controlling an Automation Server Using a Dispatch Interface ( see page 1424) Typically, you use the dual interface ( see page 1424) to control the
Automation server. However, you may find a need to control an Automation
server with a dispatch interface ( see page 1438) because no dual interface is
available.
Handling Events in an Automation Controller ( see page 1425) When you generate a Component wrapper for an object whose type library you
import, you can respond to events simply using the events that are added to the
generated component. If you do not use a Component wrapper, however, (or if
the server uses COM+ events), you must write the event sink code yourself.
Creating Clients for Servers That Do Not Have a Type Library ( see page 1426) 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.2.2.4.1 Creating COM Clients


COM clients are applications that make use of a COM object implemented by another application or library. The most common 3
types are applications that control an Automation server ( see page 1430) (Automation controllers) and applications that host
an ActiveX control (ActiveX containers).

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)

Working with Type Libraries: Overview ( see page 1445)

Overview of COM Technologies ( see page 1385)

3.2.2.4.2 Importing Type Library Information


To make information about the COM server available to your client application, you must import the information about the server
that is stored in the server's type library ( see page 1395). Your application can then use the resulting generated classes to
control the server object.

There are two ways to import type library information:

• 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)

Controlling an Imported Object ( see page 1422)

3.2.2.4.3 Code Generated When You Import Type Library Information


Once you import a type library, you can view the generated TypeLibName_TLB unit. At the top, you will find the following:

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

3.2.2.4.4 Controlling an Imported Object


After importing type library information ( see page 1420), you are ready to start programming with the imported objects. How
you proceed depends in part on the objects, and in part on whether you have chosen to create component wrappers. There are
two basic approaches:

• Using component wrappers ( see page 1422).


• Writing client code based on type library definitions ( see page 1423).
See Also
Importing Type Library Information ( see page 1420)

3.2.2.4.5 Using Component Wrappers


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 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.

Automation object wrappers


The wrappers for Automation objects let you control how you want to form the connection to your server object:

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)

3.2.2.4.6 Writing Client Code Based On Type Library Definitions


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:

• Connect to the server ( see page 1424).


3
• Control the Automation server using a dual interface ( see page 1424).
• Control the Automation server using a dispinterface ( see page 1424).
• Respond to events generated by the Automation server ( see page 1425).
See Also
Using Component Wrappers ( see page 1422)

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

3.2.2.4.7 Connecting to a Server


Before you can drive an Automation server from your controller application, you must obtain a reference to an interface it
supports. Typically, you connect to a server through its main interface.

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)

Controlling an Automation Server Using a Dual Interface ( see page 1424)

Handling Events in an Automation Controller ( see page 1425)

3.2.2.4.8 Controlling an Automation Server Using a Dual Interface


After using the automatically generated creator class to connect to the server ( see page 1424), you call methods of the
interface. For example,
var
MyInterface : _Application;
begin
MyInterface := CoWordApplication.Create;
MyInterface.DoSomething;
TComApplication AppPtr = CoWordApplication_.Create();
AppPtr->DoSomething;
The interface and creator class are defined in the TypeLibName_TLB unit that is generated automatically when you import a type
library.

See Also
Controlling an Automation Server Using a Dispatch Interface ( see page 1424)

3.2.2.4.9 Controlling an Automation Server Using a Dispatch Interface


3
Typically, you use the dual interface ( see page 1424) to control the Automation server. However, you may find a need to
control an Automation server with a dispatch interface ( see page 1438) because no dual interface is available.

To call the methods of a dispatch interface,


1. Connect to the server ( see page 1424), using the global CreateOleObject function.
2. Use the as operator to cast the IDispatch interface returned by CreateOleObject to the dispinterface for the CoClass. This
dispinterface type is declared in the TypeLibName_TLB unit.

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)

3.2.2.4.10 Handling Events in an Automation Controller


When you generate a Component wrapper for an object whose type library you import, you can respond to events simply using
the events that are added to the generated component. If you do not use a Component wrapper, however, (or if the server uses
COM+ events), you must write the event sink code yourself.

Handling Automation events programmatically


Before you can handle events, you must define an event sink. This is a class that implements the event dispatch interface that is
defined in the server's type library.

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

• The interface to the server that generates events.


• The GUID for the event interface that your event sink handles.
• An IUnknown interface for your event sink.
• A variable that receives a Longint that represents the connection between the server and your event sink.
{MyInterface is the server interface you got when you connected to the server }
InterfaceConnect(MyInterface, DIID_TheServerEvents,
MyEventSinkObject as IUnknown, cookievar);
pInterface = CoServerClassName.CreateRemote("Machine1");
MyEventSinkClass ES; 3
ES.ConnectEvents(pInterface);
After calling InterfaceConnect, your event sink is connected and receives calls from the server when events occur.

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.

Handling COM+ events


Under COM+, servers use a special helper object to generate events rather than a set of special interfaces
(IConnectionPointContainer and IConnectionPoint). Because of this, you can't use an event sink that descends from
TEventDispatcher. TEventDispatcher is designed to work with those interfaces, not COM+ event objects.

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)

Controlling an Automation Server Using a Dual 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)

3.2.2.5 Creating simple COM servers


Topics
Name Description
Creating Simple COM Servers: Overview ( see page 1430) Delphi provides wizards to help you create various COM objects. The simplest
COM objects are servers that expose properties and methods (and possibly
events) through a default interface that clients can call.
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).... more (
see page 1430)
Designing a COM Object ( see page 1430) When designing the COM object, you need to decide what COM interfaces you
want to implement. You can write a COM object to implement an interface that
has already been defined, or you can define a new interface for your object to
implement. In addition, you can have your object support more than one
interface. For information about standard COM interfaces that you might want to
support, see the MSDN documentation.

• 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,... more ( see page 1430)
3

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:

• Creates a new unit.


• Defines a new class that descends from TCOMObject and
sets up the class factory constructor. For more information
on the base class, see Code generated by wizards ( see
page 1398).
• Adds a type library to your project and adds your object
and its interface to the type library.
• Opens the type library in the Type Library Editor
Before you create a COM object, create or open the project
for the application containing functionality that you want to
implement. The project can be either an application or
ActiveX library, depending on... more ( see page 1431)
Using the Automation Object Wizard ( see page 1432) The Automation object wizard performs the following tasks:

• Creates a new unit.


• Defines a new class that descends from TAutoObject and
sets up the class factory constructor. For more information
on the base class, see Code generated by wizards ( see
page 1398).
• Adds a type library to your project and adds your object
and its interface to the type library.
Before you create an Automation object, create or open the
project for an application containing functionality that you
want to expose. The project can be either an application
or ActiveX library, depending on your needs.
COM Object Instancing Types ( see page 1433) Many of the COM wizards require you to specify an instancing mode for the
object. Instancing determines how many instances of your object clients can
create in a single executable. If you specify a Single Instance model, for
example, then once a client has instantiated your object, COM removes the
application from view so that other clients must launch their own instances of the
application. Because this affects the visibility of your application as a whole, the
instancing mode must be consistent across all objects in your application that can
be instantiated by clients. That is, you should not create... more ( see page
1433)
Choosing a Threading Model ( see page 1433) When creating an object using a wizard, you select a threading model that your
object agrees to support. By adding thread support to your COM object, you can
improve its performance, because multiple clients can access your application at
the same time.
The following table lists the different threading models you can specify.
Threading models for COM objects
Defining a COM Object's Interface ( see page 1435) When you use a wizard to create a COM object, the wizard automatically
generates a type library (unless you specify otherwise in the COM object wizard).
The type library provides a way for host applications to find out what the object
can do. It also lets you define your object's interface using the Type Library editor
( see page 1446). The interfaces you define in the Type Library editor define
what properties, methods, and events your object exposes to clients.
Note: If you selected an existing interface in the COM object wizard, you do not
need to add properties and methods. The definition... more ( see page 1435)
3 Managing Events in Your Automation Object ( see page 1437) The Automation wizard automatically generates event code if you check the
option, Generate Support Code in the Automation Object wizard dialog box.
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.
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... more ( see page 1437)

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

• 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 ( see page 1438) A dual interface is a custom interface and a dispinterface at the same time. It is
implemented as a COM VTable interface that derives from IDispatch. For those
controllers that can access the object only at runtime, the dispinterface is
available. For objects that can take advantage of compile-time binding, the more
efficient VTable interface is used.
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... more ( see page 1438)
Dispatch Interfaces ( see page 1438) Automation controllers are clients that use the COM IDispatch interface to access
the COM server objects. The controller must first create the object, then query
the object's IUnknown interface for a pointer to its IDispatch interface. IDispatch
keeps track of methods and properties internally by a dispatch identifier (dispID),
which is a unique identification number for an interface member. Through
IDispatch, a controller retrieves the object's type information for the dispatch
interface and then maps interface member names to specific dispIDs. These
dispIDs are available at runtime, and controllers get them by calling the IDispatch
method,GetIDsOfNames.
Once... more ( see page 1438)
Custom Interfaces ( see page 1439) Custom interfaces are user-defined interfaces that allow clients to invoke
interface methods based on their order in the VTable and knowledge of the
argument types. The VTable lists the addresses of all the properties and methods
that are members of the object, including the member functions of the interfaces
that it supports. If the object does not support IDispatch, the entries for the
members of the object's custom interfaces immediately follow the members of
IUnknown.
If the object has a type library, you can access the custom interface through its
VTable layout, which you can get using the... more ( see page 1439)
Marshaling Data ( see page 1439) For out-of-process and remote servers, you must consider how COM marshals
data outside the current process. You can provide marshaling:

• Automatically, using the IDispatch interface.


• Automatically, by creating a type library with your server
and marking the interface with the OLE Automation flag.
COM knows how to marshal all the 3
Automation-compatible types in the type library and can
set up the proxies and stubs for you. Some type
restrictions apply to enable automatic marshaling.
• Manually by implementing all the methods of the IMarshal
interface. This is called custom marshaling.
Note: The first method (using IDispatch) is only
available... more ( see page 1439)

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.

3.2.2.5.1 Creating Simple COM Servers: Overview


Delphi provides wizards to help you create various COM objects. The simplest COM objects are servers that expose properties
and methods (and possibly events) through a default interface that clients can call.

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.

It involves these steps:


1. Design ( see page 1430) the COM object.
2. Use the COM Object wizard ( see page 1431) or the Automation Object wizard ( see page 1432) to create the server
object.
3. Define the interface ( see page 1435) that the object exposes to clients.
4. Register the COM object ( see page 1440).
5. Test and debug ( see page 1440) the application.
See Also
Overview of COM Technologies ( see page 1385)

Creating Active Server Pages ( see page 1400)

3.2.2.5.2 Designing a COM Object


When designing the COM object, you need to decide what COM interfaces you want to implement. You can write a COM object
3 to implement an interface that has already been defined, or you can define a new interface for your object to implement. In
addition, you can have your object support more than one interface. For information about standard COM interfaces that you
might want to support, see the MSDN documentation.

• 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.

3.2.2.5.3 Using the COM Object Wizard


The COM object wizard performs the following tasks:

• Creates a new unit.


• Defines a new class that descends from TCOMObject and sets up the class factory constructor. For more information on the
base class, see Code generated by wizards ( see page 1398).
• Adds a type library to your project and adds your object and its interface to the type library.
• Opens the type library in the Type Library Editor
Before you create a COM object, create or open the project for the application containing functionality that you want to
implement. The project can be either an application or ActiveX library, depending on your needs.

To bring up the COM object wizard


1. Choose File New Other to open the New Items dialog box.
2. Select the folder labeled ActiveX under Delphi Projects
3. Double-click the COM object icon in the right pane.
In the wizard, you must specify the following:
• CoClass name: This is the name of the object as it appears to clients. The class created to implement your object has this
name with a 'T' prepended. If you do not choose to implement an existing interface, the wizard gives your CoClass a default
interface that has this name with an 'I' prepended.
• Instancing ( see page 1433): Unless you are creating an in-process server, you need to indicate how COM launches the
application that houses your COM object. If your application implements more than one COM object, you should specify the
same instancing for all of them.
• Threading Model ( see page 1433): Typically, client requests to your object enter on different threads of execution. You can
specify how COM serializes these threads when it calls your object. Your choice of threading model determines how the
object is registered. You are responsible for providing any threading support implied by the model you choose. For information
on how to provide thread support to your application, see Writing multi-threaded applications
• Interface: The wizard gives your object a default interface that descends from IUnknown ( see page 1387). By default, the
wizard gives your interface the same name as the CoClass, preceded by “I” to indicate interface. After exiting the wizard, you
can then use the Type Library editor to add properties and methods to this interface. However, you can also select a
pre-defined interface for your object to implement. Click the [...] button in the COM object wizard to bring up the Interface
Selection wizard, where you can select any dual or custom interface ( see page 1438) defined in a type library registered on
your system. The interface you select becomes the default interface for your new CoClass. The wizard adds all the methods
on this interface to the generated implementation class, so that you only need to fill in the bodies of the methods in the
implementation unit. Note that if you select an existing interface, the interface is not added to your project's type library. This
means that when deploying your object, you must also deploy the type library that defines the interface.
• Include Type Library ( see page 1395): You can choose whether you want to include a type library for your object. This is
recommended for two reasons: it lets you use the Type Library editor to define interfaces, thereby updating much of the 3
implementation, and it gives clients an easy way to obtain information about your object and its interfaces. If you are
implementing an existing interface, Delphi requires your project to use a type library. This is the only way to provide access to
the original interface declaration.
• Mark interface Oleautomation ( see page 1439): If you have opted to create a type library and are willing to confine yourself
to Automation-compatible types, you can let COM handle the marshaling for you when you are not generating an in-process
server. By marking your object's interface as OleAutomation in the type library, you enable COM to set up the proxies and
stubs for you and handles passing parameters across process boundaries. You can only specify whether your interface is
Automation-compatible if you are generating a new interface. If you select an existing interface, its attributes are already

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)

Designing a COM Object ( see page 1430)

Defining a COM Object's Interface ( see page 1435)

Registering a COM Object ( see page 1440)

3.2.2.5.4 Using the Automation Object Wizard


The Automation object wizard performs the following tasks:

• Creates a new unit.


• Defines a new class that descends from TAutoObject and sets up the class factory constructor. For more information on the
base class, see Code generated by wizards ( see page 1398).
• Adds a type library to your project and adds your object and its interface to the type library.
Before you create an Automation object, create or open the project for an application containing functionality that you want to
expose. The project can be either an application or ActiveX library, depending on your needs.

To display the Automation wizard:


1. Choose File New Other to open the New Items dialog box.
2. Select the folder labeled ActiveX under Delphi Projects.
3. Double-click the Automation Object icon in the right pane.
4. In the wizard dialog, specify the following:
• CoClass name: This is the name of the object as it appears to clients. Your object's default interface is created with a name
based on this CoClass name with an 'I' prepended, and the class created to implement your object has this name with a 'T'
prepended.
• Instancing ( see page 1433): Unless you are creating an in-process server, you need to indicate how COM launches the
application that houses your COM object. If your application implements more than one COM object, you should specify the
same instancing for all of them.
• Threading Model ( see page 1433): Typically, client requests to your object enter on different threads of execution. You can
specify how COM serializes these threads when it calls your object. Your choice of threading model determines how the
object is registered. You are responsible for providing any threading support implied by the model you choose. For information
on how to provide thread support to your application, see Writing multi-threaded applications.
• Generate Event support code ( see page 1437): You must indicate whether you want your object to generate events to
which clients can respond. The wizard can provide support for the interfaces required to generate events and the dispatching
of calls to client event handlers.
3 The 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)

Designing a COM Object ( see page 1430)

Defining a COM Object's Interface ( see page 1435)

1432
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

Registering a COM Object ( see page 1440)

Using the COM Object Wizard ( see page 1431)

3.2.2.5.5 COM Object Instancing Types


Many of the COM wizards require you to specify an instancing mode for the object. Instancing determines how many instances
of your object clients can create in a single executable. If you specify a Single Instance model, for example, then once a client
has instantiated your object, COM removes the application from view so that other clients must launch their own instances of the
application. Because this affects the visibility of your application as a whole, the instancing mode must be consistent across all
objects in your application that can be instantiated by clients. That is, you should not create one object in your application that
uses Single Instance mode and another in the same application that uses Multiple Instance mode.

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

3.2.2.5.6 Choosing a Threading Model


When creating an object using a wizard, you select a threading model that your object agrees to support. By adding thread
support to your COM object, you can improve its performance, because multiple clients can access your application at the same
time.

The following table lists the different threading models you can specify.

Threading models for COM objects

Threading Description Implementation pros and cons


model
Single The server provides no thread support. Clients are handled one at a time so no threading support is
COM serializes client requests so that needed.
the application receives one request at No performance benefit.
a time.
Apartment (or COM ensures that only one client Objects can safely access their own instance data, but global data
Single-threaded thread can call the object at a time. All must be protected using critical sections or some other form of
apartment) client calls use the thread in which the serialization.
object was created.
3
The thread's local variables are reliable across multiple calls.
Some performance benefits.
Free (also Objects can receive calls on any Objects must protect all instance and global data using critical
called number of threads at any time. sections or some other form of serialization.
multi-threaded Thread local variables are not reliable across multiple calls.
apartment)

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.

Writing an object that supports the free threading model


Use the free threading (or both) model rather than apartment threading whenever the object needs to be accessed from more
than one thread. A common example is a client application connected to an object on a remote machine. When the remote client
calls a method on that object, the server receives the call on a thread from the thread pool on the server machine. This receiving
thread makes the call locally to the actual object; and, because the object supports the free threading model, the thread can
make a direct call into the object.

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.

Note that if the instance data is read-only, serialization is not needed.

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.

3.2.2.5.7 Defining a COM Object's Interface


When you use a wizard to create a COM object, the wizard automatically generates a type library (unless you specify otherwise
in the COM object wizard). The type library provides a way for host applications to find out what the object can do. It also lets you
define your object's interface using the Type Library editor ( see page 1446). The interfaces you define in the Type Library
editor define what properties, methods, and events your object exposes to clients.

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.

Adding a property to the object's interface


When you add a property ( see page 1462) to your object's interface using the Type Library Editor, it automatically adds a
method to read the property's value and/or a method to set the property's value. The Type Library Editor, in turn, adds these
methods to your implementation class, and in your implementation unit creates empty method implementations for you to
complete.
3
To add a property to your object's interface
1. In the Type Library Editor, select the default interface for the object. The default interface should be the name of the object
preceded by the letter "I." To determine the default, in the Type Library Editor, click the CoClass and then select the
Implements tab, and check the list of implemented interfaces for the one marked, "Default."
2. To expose a read/write property, click the New Property button on the toolbar; otherwise, click the arrow next to the New
Property button on the toolbar, and then click the type of property to expose.

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.

To expose a method via your object's interface


1. In the Type Library Editor, select the default interface for the object. The default interface should be the name of the object
preceded by the letter "I". To determine the default, in the Type Library Editor, click the CoClass and select the Implements
tab, and check the list of implemented interfaces for the one marked, "Default."
2. Click the New Method button.
3. In the Attributes pane, specify the name of the method.
4. In the Parameters pane, specify the method's return type and add the appropriate parameters.
5. On the Type Library Editor toolbar, click the Refresh Implementation button. A definition and skeletal implementation for
the method is inserted into the object's implementation unit.
6. In the implementation unit, locate the newly inserted method implementation. The method is completely empty. Fill in the body
to perform whatever task the method represents.
Exposing events to clients
There are two types of events that a COM object can generate: traditional events and COM+ events.

• 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
.

In order for an object to generate events, you need to do the following:


1. In the Automation Object wizard, check the box, Generate event support code. The wizard creates an object that includes
an Events interface as well as the default interface. This Events interface has a name of the form ICoClassnameEvents. It is
an outgoing (source) interface, which means that it is not an interface your object implements, but rather is an interface that
clients must implement and which your object calls. (You can see this by selecting your CoClass, going to the Implements
page, and noting that the Source column on the Events interface says true.) In addition to the Events interface, the wizard
adds the IConnectionPointContainer interface to the declaration of your implementation class, and adds several class
members for handling events. Of these new class members, the most important are FConnectionPoint and
3 FConnectionPoints, which implement the IConnectionPoint and IConnectionPointContainer interfaces using built-in VCL
classes. FConnectionPoint is maintained by another method that the wizard adds, EventSinkChanged.
2. In the Type Library Editor, select the outgoing Events interface for your object. (This is the one with a name of the form
ICoClassNameEvents)
3. Click the New Method button from the Type Library Editor toolbar. Each method you add to the Events interface represents
an event handler that the client must implement.
4. In the Attributes pane, specify the name of the event handler, such as MyEvent.

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)

3.2.2.5.8 Managing Events in Your Automation Object


The Automation wizard automatically generates event code if you check the option, Generate Support Code in the Automation
Object wizard dialog box.

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)

3.2.2.5.9 Automation Interfaces


The Automation Object wizard implements a dual interface ( see page 1438) by default, which means that the Automation
object supports both

• 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.

3.2.2.5.10 Dual Interfaces


A dual interface is a custom interface and a dispinterface at the same time. It is implemented as a COM VTable interface that
derives from IDispatch. For those controllers that can access the object only at runtime, the dispinterface is available. For objects
that can take advantage of compile-time binding, the more efficient VTable interface is used.

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.

3.2.2.5.11 Dispatch Interfaces


Automation controllers are clients that use the COM IDispatch interface to access the COM server objects. The controller must
first create the object, then query the object's IUnknown interface for a pointer to its IDispatch interface. IDispatch keeps track of
methods and properties internally by a dispatch identifier (dispID), which is a unique identification number for an interface
member. Through IDispatch, a controller retrieves the object's type information for the dispatch interface and then maps interface
member names to specific dispIDs. These dispIDs are available at runtime, and controllers get them by calling the IDispatch
3 method,GetIDsOfNames.

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.

3.2.2.5.12 Custom Interfaces


Custom interfaces are user-defined interfaces that allow clients to invoke interface methods based on their order in the VTable
and knowledge of the argument types. The VTable lists the addresses of all the properties and methods that are members of the
object, including the member functions of the interfaces that it supports. If the object does not support IDispatch, the entries for
the members of the object's custom interfaces immediately follow the members of IUnknown.

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.

3.2.2.5.13 Marshaling Data


For out-of-process and remote servers, you must consider how COM marshals data outside the current process. You can
provide marshaling:

• Automatically, using the IDispatch interface.


• Automatically, by creating a type library with your server and marking the interface with the OLE Automation flag. COM knows
how to marshal all the Automation-compatible types in the type library and can set up the proxies and stubs for you. Some
type restrictions apply to enable automatic marshaling.
• Manually by implementing all the methods of the IMarshal interface. This is called custom marshaling.
Note: The first method (using IDispatch) is only available on Automation servers. The second method is automatically
available on all objects that are created by wizards and which use a type library.
Automation compatible types
Function result and parameter types of the methods declared in dual and dispatch interfaces and interfaces that you mark as
OLE Automation must be Automation-compatible types. The following types are OLE Automation-compatible:

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.

Fourth, dispinterface types defined in a type library.

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

Type restrictions for automatic marshaling


For an interface to support automatic marshaling (also called Automation marshaling or type library marshaling), the following
restrictions apply. When you edit your object using the type library editor, the editor enforces these restrictions:

• 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)

Automation Interfaces ( see page 1438)

3.2.2.5.14 Registering a COM Object


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.

Registering an in-process server


To register an in-process server (DLL or OCX), choose Run Register ActiveX Server.

To unregister an in-process server, choose Run Unregister ActiveX Server.

Registering an out-of-process server


To register an out-of-process server, run the server with the /regserver command-line option. You can set command-line options
with the Run Parameters dialog box. You can also register the server by running 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.)

3.2.2.5.15 Testing and Debugging the Application


Once you have created a COM server application, you will want to test it before you deploy it.

1440
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

To test and debug your COM server application,


1. Turn on debugging information using the Compiler page on the Project Options dialog box, if necessary. Also, turn on
Integrated Debugging in the Tools Options Debugger Options dialog.
2. For an in-process server, choose Run Parameters, type the name of the Automation controller in the Host Application
box, and choose OK.
3. Choose Run Run.
4. Set breakpoints in the Automation server.
5. Use the Automation controller to interact with the Automation server.
The Automation server pauses when the breakpoints are reached.
Note: As an alternate approach, if you are also writing the Automation controller, you can debug into an in-process server by
enabling COM cross-process support. Use the CodeGear Debuggers
page of the Tools Options Debugger Options dialog to enable cross-process support.

3.2.2.6 Working with type libraries


Topics
Name Description
Working with Type Libraries: Overview ( see page 1445) Type libraries are files that include information about data types, interfaces,
member functions, and object classes exposed by a COM object. They provide a
way to identify the types of objects and interfaces that are available on a server.
For a detailed overview on why and when to use type libraries, see Type
libraries ( see page 1395).
A type library can contain any and all of the following:

• 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... more ( see page
1445)
Type Library Editor ( see page 1446) The Type Library Editor enables developers to examine and create type
information for COM objects. Using the Type Library Editor can greatly simplify
the task of developing COM objects by centralizing the tasks of defining
interfaces, CoClasses, and types, obtaining GUIDs for new interfaces,
associating interfaces with CoClasses, updating implementation units, and so on.
The Type Library Editor outputs two types of file that represent the contents of
the type library:
Type Library editor files
Parts of the Type Library Editor ( see page 1446) The main elements of the Type Library Editor are described in the following
table:
Type Library editor parts
Toolbar ( see page 1447) 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 3
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:
Icons Representing... more ( see page 1447)

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:

• 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... more ( see page 1451)
Using the Type Library Editor ( see page 1453) Using the type library editor, you can create new type libraries or edit existing
ones. Typically, an application developer uses a wizard to create the objects that
are exposed in the type library, letting Delphi generate the type library
automatically. Then, the automatically-generated type library is opened in the
Type Library editor so that the interfaces can be defined (or modified), type
definitions added, and so on.
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... more ( see page 1453)
Valid Types ( see page 1454) In the Type Library editor, you use different type identifiers, depending on
whether you are working in IDL or Delphi. Specify the language you want to use
in the Environment options dialog.
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.
SafeArrays ( see page 1455) COM requires that arrays be passed via a special data type known as a
3 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... more ( see page 1455)

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.

• You can change the interface's attributes using the page


of type information that contains the information you want
to change. Select the interface in the Object List pane
and then use the controls on the appropriate page of type
information. For example, you may want to change the
parent interface using the attributes page, or use the flags
page to change whether or not it is a dual interface.
• You can edit the interface declaration directly by selecting
the interface in the object list pane and... more ( see
page 1461)
Adding Properties and Methods to the Type Library ( see page 1462)
Adding a CoClass to the Type Library ( see page 1463) The easiest way to add a CoClass to your project is to choose
File New Other from the main menu in the IDE and use the appropriate
wizard ( see page 1397) on the ActiveX page of the New Items dialog. The
advantage to this approach is that, in addition to adding the CoClass and its
interface to the type library, the wizard adds an implementation unit and updates
the project file to include the new implementation unit in its uses clause.
If you are not using a wizard, however, you can create a CoClass by clicking the
CoClass icon on the toolbar and... more ( see page 1463)
Adding an Interface to a CoClass ( see page 1463) CoClasses are defined by the interfaces they present to clients. While you can
add any number of properties and methods to the implementation class of a
CoClass, clients can only see those properties and methods that are exposed by
interfaces associated with the CoClass.
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... more ( see page 1463)
Adding an Enumeration to the Type Library ( see page 1464)
Adding an Alias to the Type Library ( see page 1464)
Adding a Record or Union to the Type Library ( see page 1464)
Adding a Module to the Type Library ( see page 1465) 3

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:

• 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... more ( see page
1465)
Apply Updates Dialog ( see page 1466) The Apply Updates dialog appears when you refresh, register, or save the type
library if you have selected Display updates before refreshing in the
Tools Options Type Library page (which is not checked off by default ).
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... more ( see page 1466)
Saving a Type Library ( see page 1466) For 2009, RAD Studio stores type libraries as separate text-based files (RIDL, or
Restricted Interface Definition Language); The RIDL file, which represents the
TLB file in the Editor, is also linked into the server (.EXE, DLL, or .OCX). When
you build your project, the RIDL file is saved on disk as both a .tlb file as well
as a .ridl file.
There are three ways to save a type library.

• 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... more ( see page 1466)
Refreshing the Type Library ( see page 1467) To refresh the type library, choose the Refresh Implementation icon on the
Type Library Editor toolbar.
Refreshing the type library does the following:

• 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++
3 Options Type Library dialog box, you can designate
specific instances when the... more ( see page 1467)

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)

3.2.2.6.1 Working with Type Libraries: Overview


Type libraries are files that include information about data types, interfaces, member functions, and object classes exposed by a
COM object. They provide a way to identify the types of objects and interfaces that are available on a server. For a detailed
overview on why and when to use type libraries, see Type libraries ( see page 1395).

A type library can contain any and all of the following:

• 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)

Overview of COM Technologies ( see page 1385)

3.2.2.6.2 Type Library Editor


The Type Library Editor enables developers to examine and create type information for COM objects. Using the Type Library
Editor can greatly simplify the task of developing COM objects by centralizing the tasks of defining interfaces, CoClasses, and
types, obtaining GUIDs for new interfaces, associating interfaces with CoClasses, updating implementation units, and so on.

The Type Library Editor outputs two types of file that represent the contents of the type library:

Type Library editor files

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:

• Parts of the Type Library editor ( see page 1446)


• Using the Type Library editor ( see page 1453)
See Also
Type Library Editor Window

RIDL File ( see page 1468)

Toolbar ( see page 1447)

Object list pane ( see page 1448)

Status Bar ( see page 1449)

Pages of Type Information ( see page 1449)


3
3.2.2.6.3 Parts of the Type Library Editor
The main elements of the Type Library Editor are described in the following table:

Type Library editor parts

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)

Type Library Editor

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:

Icons Representing Type Library Elements

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:

Icons Representing Members of a Type Library

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

A property on an interface or dispinterface.


A write-only property. (available from the drop-down list on the property button)
A read-write property. (available from the drop-down list on the property button)
A read-only property. (available from the drop-down list on the property button)
A field in a record or union.
A constant in an enum or a module.

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).

Icons Representing Actions You can Perform

Icon Meaning
Refresh implementation.

Register Type Library.

Save as TLB File.

See Also
Object List Pane ( see page 1448)

Status Bar ( see page 1449)

Pages of Type Information ( see page 1449)

Elements of Type Libraries ( see page 1451)

3.2.2.6.5 Object List Pane


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:

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)

Status Bar ( see page 1449)

3.2.2.6.6 Status Bar


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).

See Also
Object List Pane ( see page 1448)

Toolbar ( see page 1447)

Pages of Type Information ( see page 1449)

3.2.2.6.7 Pages of Type Information


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 Info Page of Contents of page


element type
information
Type library Attributes Name, version, and GUID for the type library, as well as information linking the type library to help.

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

IDL compiler for C++ code generation or marshaling support).

See Also
Object List Pane ( see page 1448)

Toolbar ( see page 1447)

Status Bar ( see page 1449)

Type Library Elements ( see page 1451)

3.2.2.6.8 Type Library Elements


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:

• 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.

Special Icons for 'get' and 'set' Methods

A write (set, put) by value property function.


A read (get) | write (set, put) | write by reference property function.
A read (get) property function.

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.

mbLeft = 0 [helpstring 'mbLeft'];


mbRight = 1 [helpstring 'mbRight'];
mbMiddle = 3 [helpstring 'mbMiddle'];
typedef enum TxMouseButton
{
[helpstring("mbLeft")]
mbLeft = 0,
[helpstring("mbRight)]
mbRight = 1.
[helpstring("mbMiddle)]
mbMiddle = 2
} TxMouseButton;
An alias creates an alias (type definition) for a type. You can use the alias to define types that you want to use in other type info
such as records or unions. Associate the alias with the underlying type definition by setting the Type attribute on the Attributes
page.
3 A record consists of a list of structure members or fields. A union is a record with only a variant part. Like a record, a union
consists of a list of structure members or fields. However, unlike the members of records, each member of a union occupies the
same physical address, so that only one logical value can be stored.

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

• Specifying a DLL that it represents on the attributes page.


• Adding methods and constants using the toolbar or the object list pane context menu. For each method or constant, you must
then define its attributes by selecting the it in the object list pane and setting the values on the Attributes page.
For module methods, you must assign a name and DLL entry point using the attributes page. Declare the function's parameters
and return type using the parameters page.
For module constants, use the Attributes page to specify a name, type, and value.
Note: The Type Library Editor
does not generate any declarations or implementation related to a module. The specified DLL must be created as a separate
project.
See Also
Pages of Type Information ( see page 1449)

Toolbar ( see page 1447)

Type Library Editor

Type Library Explorer (Read-Only)

3.2.2.6.9 Using the Type Library Editor


Using the type library editor, you can create new type libraries or edit existing ones. Typically, an application developer uses a
wizard to create the objects that are exposed in the type library, letting Delphi generate the type library automatically. Then, the
automatically-generated type library is opened in the Type Library editor so that the interfaces can be defined (or modified), type
definitions added, and so on.

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

The following topics describe how to:

• Create a new type library ( see page 1460)


• Open an existing type library ( see page 1460)
• Add an interface to the type library ( see page 1461)
• Modify an interface ( see page 1461)
• Add properties and methods to the type library ( see page 1462)
• Add a CoClass to the type library ( see page 1463)
• Add an interface to a CoClass ( see page 1463) 3
• Add an enumeration to the type library ( see page 1464)
• Add an alias to the type library ( see page 1464)
• Add a record or union to the type library ( see page 1464)
• Add a module to the type library ( see page 1465)
• Save and register type library information ( see page 1465)

1453
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide

See Also
Type Libraries ( see page 1395)

Parts of the Type Library Editor ( see page 1446)

3.2.2.6.10 Valid Types


In the Type Library editor, you use different type identifiers, depending on whether you are working in IDL or Delphi. Specify the
language you want to use in the Environment options dialog.

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.

Delphi type IDL type variant type Automation Description


compatible
Smallint short VT_I2 Yes 2-byte signed integer
Integer long VT_I4 Yes 4-byte signed integer
Single single VT_R4 Yes 4-byte real
Double double VT_R8 Yes 8-byte real
Currency CURRENCY VT_CY Yes currency
TDateTime DATE VT_DATE Yes date
WideString BSTR VT_BSTR Yes binary string
IDispatch IDispatch VT_DISPATCH Yes pointer to IDispatch interface
SCODE SCODE VT_ERROR Yes Ole Error Code
WordBool VARIANT_BOOL VT_BOOL Yes True = -1, False = 0
OleVariant VARIANT VT_VARIANT Yes Ole Variant
IUnknown IUnknown VT_UNKNOWN Yes pointer to IUnknown interface
Shortint byte VT_I1 No 1 byte signed integer
Byte unsigned char VT_UI1 Yes 1 byte unsigned integer
Word unsigned short VT_UI2 Yes* 2 byte unsigned integer
LongWord unsigned long VT_UI4 Yes* 4 byte unsigned integer
Int64 __int64 VT_I8 No 8 byte signed integer
Largeuint uint64 VT_UI8 No 8 byte unsigned integer
SYSINT int VT_INT Yes* system dependent integer (Win32=Integer)
SYSUINT unsigned int VT_UINT Yes* system dependent unsigned integer
HResult HRESULT VT_HRESULT No 32 bit error code
3
Pointer VT_PTR -> No untyped pointer
VT_VOID
SafeArray SAFEARRAY VT_SAFEARRAY No OLE Safe Array
PAnsiChar LPSTR VT_LPSTR No pointer to Char
PChar LPWSTR VT_LPWSTR No pointer to WideChar
PWideChar LPWSTR VT_LPWSTR No pointer to WideChar

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)

3.2.2.6.12 Using Object Pascal or IDL Syntax


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 (_).

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

Attribute name Example Applies to


aggregatable [aggregatable] typeinfo
appobject [appobject] CoClass typeinfo
bindable [bindable] members except CoClass members

1455
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide

control [control] type library, typeinfo


custom [custom anything
'{7B5687A1-F4E9-11D1-92A8-00C04F8C8FC4}'
0]
default [default] CoClass members
defaultbind [defaultbind] members except CoClass members
defaultcollection [defaultcollection] members except CoClass members
dispid [dispid] members except CoClass members
displaybind [displaybind] members except CoClass members
dllname [dllname 'Helper.dll'] module typeinfo
dual [dual] interface typeinfo
helpfile [helpfile 'c:\help\myhelp.hlp'] type library
helpstringdll [helpstringdll 'c:\help\myhelp.dll'] type library
helpcontext [helpcontext 2005] anything except CoClass members and
parameters
helpstring [helpstring 'payroll interface'] anything except CoClass members and
parameters
helpstringcontext [helpstringcontext $17] anything except CoClass members and
parameters
hidden [hidden] anything except parameters
lcid [lcid $324] type library
licensed [licensed] type library, CoClass typeinfo
nonbrowsable [nonbrowsable] members except CoClass members
nonextensible [nonextensible] interface typeinfo
oleautomation [oleautomation] interface typeinfo
predeclid [predeclid] typeinfo
propget [propget] members except CoClass members
propput [propput] members except CoClass members
propputref [propputref] members except CoClass members
public [public] alias typeinfo
readonly [readonly] members except CoClass members
replaceable [replaceable] anything except CoClass members and
parameters
requestedit [requestedit] members except CoClass members
restricted [restricted] anything except parameters
3
source [source] all members
uidefault [uidefault] members except CoClass members
usesgetlasterror [usesgetlasterror] members except CoClass members
uuid [uuid type library, typeinfo (required)
'{7B5687A1-F4E9-11D1-92A8-00C04F8C8FC4}'
]

1456
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

vararg [vararg] members except CoClass members


version [version 1.1] type library, typeinfo

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

For example, the following text declares a record:


Tasks = record [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring 'Task description']
ID: Integer;
StartDate: TDate;
EndDate: TDate;
Ownername: WideString;
Subtasks: safearray of Integer;
end;
The corresponding syntax in Microsoft IDL is
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring "Task description"]
typedef struct
{
long ID;
DATE StartDate;
DATE EndDate;
BSTR Ownername;
SAFEARRAY (int) Subtasks;
} Tasks;
Union syntax
The Delphi syntax for declaring Union type information has the form
unionname = record [attributes]
case Integer of
0: field1;
1: field2;
...
end;
For example, the following text declares a union:
MyUnion = record [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring "item description"]
case Integer of
0: (Name: WideString);
1: (ID: Integer);
3: (Value: Double);
end;
The corresponding syntax in Microsoft IDL is
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring "item description"]
typedef union
{
BSTR Name;
long ID;
double Value;
} MyUnion;
Module syntax
The Delphi syntax for declaring Module type information has the form
3
modulename = module constants entrypoints end;
For example, the following text declares the type information for a module:
MyModule = module [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
dllname 'circle.dll']
PI: Double = 3.14159;
function area(radius: Double): Double [ entry 1 ]; stdcall;
function circumference(radius: Double): Double [ entry 2 ]; stdcall;
end;

1459
Developing COM-based Applications RAD Studio 3.2 Win32 Developer's Guide

The corresponding syntax in Microsoft IDL is


[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
dllname("circle.dll")]
module MyModule
{
double PI = 3.14159;
[entry(1)] double _stdcall area([in] double radius);
[entry(2)] double _stdcall circumference([in] double radius);
};
See Also
Valid Types ( see page 1454)

3.2.2.6.13 Creating a New Type Library


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 implementation.

To create a new type library


1. If you have a project open, click File Close All.
2. Choose File New Other to open the New Items dialog box.
3. Choose the ActiveX folder under either Delphi Projects or C++Builder Projects.
4. Select the Type Library icon in the right pane.
5. Choose OK. The wizard creates an empty RIDL file and opens it in the Design page of the Type Library Editor(in the Code
Editor window).
6. Enter a name for the type library in the Namefield.
7. Continue by adding elements to your type library by using the toolbar ( see page 1447) buttons.
See Also
Opening an Existing Type Library ( see page 1460)

Using the Type Library Editor ( see page 1453)

Working with Type Libraries ( see page 1441)

RIDL File ( see page 1468)

3.2.2.6.14 Opening an Existing Type Library


When you use the wizards to create an Automation object, COM object, transactional object, or a remote data module, a type
3 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.

To open a legacy type library (.tlb file)


1. Choose File Open.

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)

3.2.2.6.15 Adding an Interface to the Type Library


To add an interface
1. On the toolbar, click on the interface icon. An interface is added to the object list pane prompting you to add a name.
2. Type a name for the interface.
The new interface contains default attributes that you can modify as needed.
You can add properties (represented by getter/setter functions) and methods to suit the purpose of the interface.
See Also
Toolbar ( see page 1447)

Adding Properties and Methods to the Type Library ( see page 1462)

Modifying an Interface Using the Type Library ( see page 1461)

3.2.2.6.16 Modifying an Interface Using the Type Library


There are several ways to modify an interface or dispinterface once it is created. 3
• You can change the interface's attributes using the page of type information that contains the information you want to change.
Select the interface in the Object List pane and then use the controls on the appropriate page of type information. For
example, you may want to change the parent interface using the attributes page, or use the flags page to change whether or
not it is a dual interface.
• You can edit the interface declaration directly by selecting the interface in the object list pane and then editing the declarations
on the Text page.
• You can Add properties and methods to the interface ( 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.2.2.6.17 Adding Properties and Methods to the Type Library


To add properties or methods to an interface or dispinterface
1. Select the interface, and choose either a property or method icon from the toolbar. If you are adding a property, you can click
directly on the property icon to create a read/write property (with both a getter and a setter), or click the down arrow to display
a menu of property types. The property access method members or method member is added to the object list pane,
prompting you to add a name.
2. Type a name for the member.
The new member contains default settings on its attributes, parameters, and flags pages that you can modify to suit the member.
For example, you will probably want to assign a type to a property on the attributes page. If you are adding a method, you will
probably want to specify its parameters on the parameters page.
As an alternate approach, you can add properties and methods by typing directly into the text page using Delphi or IDL syntax.
For example, if you are working in Delphi syntax, you can type the following property declarations into the text page of an
interface:
Interface1 = interface(IDispatch)
[ uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',
version 1.0,
dual,
oleautomation ]
function AutoSelect: Integer [propget, dispid $00000002]; safecall; // Add this
function AutoSize: WordBool [propget, dispid $00000001]; safecall; // And this
procedure AutoSize(Value: WordBool) [propput, dispid $00000001]; safecall; // And this
end;
If you are working in IDL, you can add the same declarations as follows:

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

HRESULT _stdcall AutoSize([out, retval] VARIANT_BOOL Value );


[propput, id(0x00000003)]
HRESULT _stdcall AutoSize([in] VARIANT_BOOL Value );
};
After you have added members to an interface using the interface text page, the members appear as separate items in the
object list pane, each with its own attributes, flags, and parameters pages. You can modify each new property or method by
selecting it in the object list pane and using these pages, or by making edits directly in the text page.

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)

Adding an Interface to the Type Library ( see page 1461)

Toolbar ( see page 1447)

3.2.2.6.18 Adding a CoClass to the Type Library


The easiest way to add a CoClass to your project is to choose File New Other from the main menu in the IDE and use the
appropriate wizard ( see page 1397) on the ActiveX page of the New Items dialog. The advantage to this approach is that, in
addition to adding the CoClass and its interface to the type library, the wizard adds an implementation unit and updates the
project file to include the new implementation unit in its uses clause.

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)

Code Generated by Wizards ( see page 1398)

3.2.2.6.19 Adding an Interface to a CoClass 3


CoClasses are defined by the interfaces they present to clients. While you can add any number of properties and methods to the
implementation class of a CoClass, clients can only see those properties and methods that are exposed by interfaces associated
with the CoClass.

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)

Adding a CoClass to the Type Library ( see page 1463)

3.2.2.6.20 Adding an Enumeration to the Type Library


To add enumerations to a type library
1. On the toolbar, click on the enum icon. An enum type is added to the Object List pane .
2. Type a name for the enumeration. The new enum is empty and contains default attributes in its attributes page for you to
modify.
Add values to the enum by right clicking the enum and selecting the New Const button . Then, select each enumerated value
and assign it a name (and possibly a value) using the attributes page.
Once you have added an enumeration, 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 enumeration as the type for a property or parameter.
See Also
Adding an Alias to the Type Library ( see page 1464)

Adding a Record or Union to the Type Library ( see page 1464)

Adding a Module to the Type Library ( see page 1465)

3.2.2.6.21 Adding an Alias to the Type Library


To add an alias to a type library
1. On the toolbar, click on the alias icon. An alias type is added to the object list pane .
2. Type a name for the alias. By default, the new alias stands for a Long Integer type. Use the Attributes page to change this to
the type you want the alias to represent.
Once you have added an alias, 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 alias as the type for a property or parameter.
See Also
Adding an Enumeration to the Type Library ( see page 1464)

Adding a Record or Union to the Type Library ( see page 1464)


3 Adding a Module to the Type Library ( see page 1465)

3.2.2.6.22 Adding a Record or Union to the Type Library


To add a record or union to a type library
1. On the toolbar, click on the record icon or the union icon. The selected type element is added to the object list pane .
2. Type a name for the record or union. At this point, the new record or union contains no fields.

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)

Adding an Alias to the Type Library ( see page 1464)

Adding a Module to the Type Library ( see page 1465)

3.2.2.6.23 Adding a Module to the Type Library


To add a module to a type library
1. On the toolbar, click on the module icon. The selected module is added to the object list pane .
2. Type a name for the module.
3. On the Attributes page, specify the name of the DLL whose entry points the Module represents.
4. Add any methods from the DLL you specified in step 3 by clicking on the Method icon in the toolbar and then using the
attributes pages to describe the method.
5. Add any constants you want the module to define by clicking on the Const icon on the toolbar. For each constant, specify a
name, type, and value.
See Also
Adding an Enumeration to the Type Library ( see page 1464)

Adding an Alias to the Type Library ( see page 1464)

3.2.2.6.24 Saving and Registering Type Library Information


After modifying your type library, you'll want to save and register the type library information.

Saving the type library automatically updates:

• 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

RIDL File ( see page 1468)

Registering the Type Library ( see page 1467)

Saving a Type Library ( see page 1466)

3.2.2.6.25 Apply Updates Dialog


The Apply Updates dialog appears when you refresh, register, or save the type library if you have selected Display updates
before refreshing in the Tools Options Type Library page (which is not checked off by default ).

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)

Registering the Type Library ( see page 1467)

3.2.2.6.26 Saving a Type Library


For 2009, RAD Studio stores type libraries as separate text-based files (RIDL, or Restricted Interface Definition Language); The
RIDL file, which represents the TLB file in the Editor, is also linked into the server (.EXE, DLL, or .OCX). When you build your
project, the RIDL file is saved on disk as both a .tlb file as well as a .ridl file.

There are three ways to save a type library.

• 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)

Refreshing the Type Library ( see page 1467)

Registering the Type Library ( see page 1467)

1466
3.2 Win32 Developer's Guide RAD Studio Developing COM-based Applications

Type Library Editor Window

RIDL File ( see page 1468)

3.2.2.6.27 Refreshing the Type Library


To refresh the type library, choose the Refresh Implementation icon on the Type Library Editor toolbar.

Refreshing the type library does the following:

• 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)

Saving a Type Library ( see page 1466)

Registering the Type Library ( see page 1467)

3.2.2.6.28 Registering the Type Library


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.

See Also
Apply Updates Dialog ( see page 1466)

Saving a Type Library ( see page 1466)

Refreshing the Type Library ( see page 1467)


3

3.2.2.6.29 Deploying Type Libraries


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.

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

To create AppName.tlb from the contents of AppName.ridl:


C:\> gentlb AppName.ridl
To create a type library based on a differently named .ridl file, use the -T option to specify the name of the type library. To create
AppName.tlb from the contents of model.ridl:
C:\> gentlb -TAppName.tlb model.ridl
See Also
Type Library Editor

RIDL File ( see page 1468)

Object List Pane ( see page 1448)

Toolbar ( see page 1447)

Pages of Type Information ( see page 1449)

Using the COM Wizards ( see page 79)

3.2.2.6.31 RIDL File


3 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 now works on top of a .text file (the RIDL file) instead of the binary .tlb.

This change means that:

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

GenTLB.exe ( see page 1468)

Object List Pane ( see page 1448)

Toolbar ( see page 1447)

Pages of Type Information ( see page 1449)

Using the COM Wizards ( see page 79)

3.2.3 Developing Database Applications


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.

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

3.2.3.1 Working with ADO components


Topics
Name Description
ADO Connection Events ( see page 1474) In addition to the usual events that occur for all database connection
components, TADOConnection generates a number of additional events that
occur during normal usage.
Accessing the Connection Object ( see page 1475) Use the ConnectionObject property of TADOConnection to access the underlying
ADO connection object. Using this reference it is possible to access properties
and call methods of the underlying ADO Connection object.
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.
Accessing the Connection's Datasets ( see page 1475) Like other database connection components, you can access the datasets
associated with the connection ( see page 1505) using the DataSets and
DataSetCount properties. However, dbGo also includes TADOCommand objects,
which are not datasets, but which maintain a similar relationship to the
connection component.
You can use the Commands and CommandCount properties of
TADOConnection to access the associated ADO command objects in the same
way you use the DataSets and DataSetCount properties to access the
associated datasets. Unlike DataSets and DataSetCount, which only list active
datasets, Commands and CommandCount provide references to all
TADOCommand components associated with the connection component.
Commands is a... more ( see page 1475)
Applying the Batch Updates to Base Tables ( see page 1476) Apply pending data changes that have not yet been applied or canceled by
calling the UpdateBatch method. Rows that have been changed and are applied
have their changes put into the base tables on which the recordset is based. A
cached row marked for deletion causes the corresponding base table row to be
deleted. A record insertion (exists in the cache but not the base table) is added to
the base table. Modified rows cause the columns in the corresponding rows in
the base tables to be changed to the new column values in the cache.
Used alone with no... more ( see page 1476)
Canceling Batch Updates ( see page 1476) Cancel pending data changes that have not yet been canceled or applied by
calling the CancelBatch method. When you cancel pending batch updates, field
values on rows that have been changed revert to the values that existed prior to
the last call to CancelBatch or UpdateBatch, if either has been called, or prior to
the current pending batch of changes.
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.... more ( see page 1476)
Canceling Commands ( see page 1477) If you are executing the command asynchronously, then after calling Execute you
can abort the execution by calling the Cancel method:
Connecting to ADO Data Stores ( see page 1477) dbGo applications use Microsoft ActiveX Data Objects (ADO) 2.1 to interact with
an OLE DB provider that connects to a data store and accesses its data. One of
the items a data store can represent is a database. An ADO-based application
requires that ADO 2.1 be installed on the client computer. ADO and OLE DB is
supplied by Microsoft and installed with Windows.
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... more ( see page 1477)
Connecting to a Data Store Using TADOConnection ( see page 1478) One or more ADO dataset and command components can share a single
connection to a data store by using TADOConnection. To do so, associated
3 dataset and command components with the connection component through their
Connection properties. At design-time, select the desired connection component
from the drop-down list for the Connection property in the Object Inspector. At
runtime, assign the reference to the Connection property. For example, the
following line associates a TADODataSet component with a TADOConnection
component.
Connecting an ADO Dataset to a Data Store ( see page 1479) ADO datasets can connect to an ADO data store either collectively or individually.
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.

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:

• Forcing asynchronous connections ( see page 1483)


• Controlling time-outs ( see page 1480)
• Indicating the types of operations the connection supports
( see page 1485)
• Specifying whether the connection automatically initiates
transactions ( see page 1489)
Forcing Asynchronous Connections ( see page 1483) Use the ConnectOptions property to force the connection to be asynchronous.
Asynchronous connections allow your application to continue processing without
waiting for the connection to be completely opened.
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:

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:

• 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... more ( see page 1484)
Indicating the Types of Operations the Connection Supports ( see page 1485) ADO connections are established using a specific mode, similar to the mode you
use when opening a file. The connection mode determines the permissions
available to the connection, and hence the types of operations (such as reading
and writing) that can be performed using that connection.
Use the Mode property to indicate the connection mode. The possible values are
listed in the following table:
ADO connection modes
Inspecting the Update Status of Individual Rows ( see page 1485) Determine the update status of a given row by making it current and then
inspecting the RecordStatus property of the ADO data component. RecordStatus
reflects the update status of the current row and only that row.
Loading Data from and Saving Data to Files ( see page 1486) The data retrieved via an ADO dataset component can be saved to a file for later
retrieval on the same or a different computer. The data is saved in one of two
proprietary formats: ADTG or XML. These two file formats are the only formats
supported by ADO. However, both formats are not necessarily supported in all
versions of ADO. Consult the ADO documentation for the version you are using
to determine what save file formats are supported.
Save the data to a file using the SaveToFile method. SaveToFile takes two
parameters, the name of the file to which data... more ( see page 1486)
Opening the Dataset in Batch Update Mode ( see page 1487) To open an ADO dataset in batch update mode, it must meet these criteria:

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... more ( see page 1487)
Overview of ADO Components ( see page 1487) The ADO page 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. They require
3 ADO 2.1 (or higher) 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.
Most dbGo components have direct counterparts in the components available for
other data access mechanisms: a database connection component (... more (
see page 1487)

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:

• Connecting to an ADO datastore ( see page 1479)


• Accessing the underlying Recordset object ( see page
1494)
• Filtering records based on bookmarks ( see page 1482)
• Fetching records asynchronously ( see page 1481)
• Performing batch updates (caching updates) ( see page
1491)
• Using files on disk to store data ( see page 1486)
There are four ADO datasets:
• TADOTable, a table-type dataset ( see page 1620) that
represents... more ( see page 1490)
Using Batch Updates ( see page 1491) One approach for caching updates is to connect the ADO dataset to a client
dataset using a dataset provider. This approach is discussed in Using a client
dataset to cache updates ( see page 1731).
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:
Comparison of ADO and client dataset cached updates
3
Using Command Objects ( see page 1492) In the ADO environment, commands are textual representations of
provider-specific action requests. Typically, they are Data Definition Language
(DDL) and Data Manipulation Language (DML) SQL statements. The language
used in commands is provider-specific, but usually compliant with the SQL-92
standard for the SQL language.
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... more ( see page 1492)

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:

• 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. TADODataSet supports table-type
tasks such as
• Assigning indexes ( see page 1609) to sort records or
form the basis of record-based searches.... more ( see
page 1492)
Using the Execute Method ( see page 1493) Before TADOCommand can execute its command, it must have a valid
connection to a data store. This is established just as with an ADO dataset. See
Connecting an ADO dataset to a data store ( see page 1479) for details.
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:
Working with ADO Components ( see page 1494) The dbGo components provide data access through the ADO framework. ADO,
(Microsoft ActiveX Data Objects) is a set of COM objects that access data
through an OLE DB provider. The dbGo components encapsulate these ADO
objects in the Delphi database architecture.
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... more ( see page 1494)
Working with Record Sets ( see page 1494) The Recordset property provides direct access to the ADO recordset object
underlying the dataset component. Using this object, it is possible to access
properties and call methods of the recordset object from an application. Use of
Recordset to directly 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... more ( see page
1494)

3.2.3.1.1 ADO Connection Events


In addition to the usual events that occur for all database connection components, TADOConnection generates a number of
additional events that occur during normal usage.

Events when establishing a connection


In addition to the BeforeConnect and AfterConnect events that are common to all database connection components,
TADOConnection also generates an OnWillConnect and OnConnectComplete event when establishing a connection. These
events occur after the BeforeConnect event.

• 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.

Events when managing transactions


The ADO connection component provides a number of events for detecting when transaction-related processes have been
completed. These events indicate when a transaction process initiated by a BeginTrans, CommitTrans, and RollbackTrans
method has been successfully completed at the data store.

• 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)

Connecting to a Data Store Using TADOConnection ( see page 1478)

Connecting to a Data Store Using TADOConnection ( see page 1478)

Accessing the Connection's Datasets ( see page 1475)

3.2.3.1.2 Accessing the Connection Object


Use the ConnectionObject property of TADOConnection to access the underlying ADO connection object. Using this reference it
is possible to access properties and call methods of the underlying ADO Connection object.

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.

3.2.3.1.3 Accessing the Connection's Datasets


Like other database connection components, you can access the datasets associated with the connection ( see page 1505)
using the DataSets and DataSetCount properties. However, dbGo also includes TADOCommand objects, which are not
datasets, but which maintain a similar relationship to the connection component.
3
You can use the Commands and CommandCount properties of TADOConnection to access the associated ADO command
objects in the same way you use the DataSets and DataSetCount properties to access the associated datasets. Unlike DataSets
and DataSetCount, which only list active datasets, Commands and CommandCount provide references to all TADOCommand
components associated with the connection component.

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

connection component, as illustrated in the following code:


var
i: Integer
begin
for i := 0 to (ADOConnection1.CommandCount - 1) do
ADOConnection1.Commands[i].Execute;
end;
for (int i = 0; i < ADOConnection2->CommandCount; i++)
ADOConnection2->Commands[i]->Execute();
See Also
Connecting to Databases ( see page 1506)

Connecting to a Data Store Using TADOConnection ( see page 1478)

Connecting to a Data Store Using TADOConnection ( see page 1478)

ADO Connection Events ( see page 1474)

3.2.3.1.4 Applying the Batch Updates to Base Tables


Apply pending data changes that have not yet been applied or canceled by calling the UpdateBatch method. Rows that have
been changed and are applied have their changes put into the base tables on which the recordset is based. A cached row
marked for deletion causes the corresponding base table row to be deleted. A record insertion (exists in the cache but not the
base table) is added to the base table. Modified rows cause the columns in the corresponding rows in the base tables to be
changed to the new column values in the cache.

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)

Inspecting the Update Status of Individual Rows ( see page 1485)

Filtering Multiple Rows Based On Update Status ( see page 1481)

Canceling Batch Updates ( see page 1476)

3.2.3.1.5 Canceling Batch Updates


Cancel pending data changes that have not yet been canceled or applied by calling the CancelBatch method. When you cancel
pending batch updates, field values on rows that have been changed revert to the values that existed prior to the last call to
3 CancelBatch or UpdateBatch, if either has been called, or prior to the current pending batch of changes.

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)

Inspecting the Update Status of Individual Rows ( see page 1485)

Filtering Multiple Rows Based On Update Status ( see page 1481)

Applying the Batch Updates to Base Tables ( see page 1476)

3.2.3.1.6 Canceling Commands


If you are executing the command asynchronously, then after calling Execute you can abort the execution by calling the Cancel
method:
procedure TDataForm.ExecuteButtonClick(Sender: TObject);
begin
ADOCommand1.Execute;
end;
procedure TDataForm.CancelButtonClick(Sender: TObject);
begin
ADOCommand1.Cancel;
end;
void __fastcall TDataForm::ExecuteButtonClick(TObject *Sender)
{
ADOCommand1->Execute();
}
void __fastcall TDataForm::CancelButtonClick(TObject *Sender)
{
ADOCommand1->Cancel();
}
The Cancel method only has an effect if there is a command pending and it was executed asynchronously (eoAsynchExecute is
in the ExecuteOptions parameter of the Execute method). A command is said to be pending if the Execute method has been
called but the command has not yet been completed or timed out.

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)

Using the Execute Method ( see page 1493)

Retrieving Result Sets with Commands ( see page 1488)

Handling Command Parameters ( see page 1484)

3.2.3.1.7 Connecting to ADO Data Stores


dbGo applications use Microsoft ActiveX Data Objects (ADO) 2.1 to interact with an OLE DB provider that connects to a data
store and accesses its data. One of the items a data store can represent is a database. An ADO-based application requires that 3
ADO 2.1 be installed on the client computer. ADO and OLE DB is supplied by Microsoft and installed with Windows.

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

• 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)
In addition to these features that are common to all database connection components, TADOConnection provides its own
support for
• A wide range of options you can use to fine-tune the connection ( see page 1483).
• The ability to list the command objects that use the connection ( see page 1475).
• Additional events ( see page 1474) when performing common tasks.
See Also
TADOConnection

Using TADODataSet ( see page 1492)

Using Command Objects ( see page 1492)

3.2.3.1.8 Connecting to a Data Store Using TADOConnection


One or more ADO dataset and command components can share a single connection to a data store by using TADOConnection.
To do so, associated dataset and command components with the connection component through their Connection properties. At
design-time, select the desired connection component from the drop-down list for the Connection property in the Object
Inspector. At runtime, assign the reference to the Connection property. For example, the following line associates a
TADODataSet component with a TADOConnection component.
ADODataSet1.Connection := ADOConnection1;
ADODataSet1->Connection = ADOConnection1;
The connection component represents an ADO connection object ( see page 1475). Before you can use the connection object
to establish a connection, you must identify the data store to which you want to connect. Typically, you provide information using
the ConnectionString property. ConnectionString is a semicolon delimited string that lists one or more named connection
parameters. These parameters identify the data store by specifying either the name of a file that contains the connection
information or the name of an ADO provider and a reference identifying the data store. Use the following, predefined parameter
names to supply this information:
3
Connection parameters

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.

Thus, a typical value of ConnectionString has the form


Provider=MSDASQL.1;Data Source=MQIS
Note: The connection parameters in ConnectionString do not need to include the Provider or Remote Provider parameter if you
specify an ADO provider using the Provider property. Similarly, you do not need to specify the Data Source parameter if you use
the DefaultDatabase property.

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

Connecting to Databases ( see page 1506)

Fine-tuning a Connection ( see page 1483)

Accessing the Connection's Datasets ( see page 1475)

ADO Connection Events ( see page 1474)

3.2.3.1.9 Connecting an ADO Dataset to a Data Store 3


ADO datasets can connect to an ADO data store either collectively or individually.

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:

• The datasets share the connection object's attributes.


• Only one connection need be set up: that of the TADOConnection.
• The datasets can participate in transactions.
For more information on using TADOConnection see Connecting to ADO data stores ( see page 1477).
When connecting datasets individually, set the ConnectionString property of each dataset. Each dataset that uses
ConnectionString establishes its own connection to the data store, independent of any other dataset connection in the
application.
The ConnectionString property of ADO datasets works the same way as the ConnectionString property of TADOConnection: it is
a set of semicolon-delimited connection parameters such as the following:
ADODataSet1.ConnectionString := "Provider=YourProvider;Password=SecretWord;" +
"User ID=JaneDoe;SERVER=PURGATORY;UID=JaneDoe;PWD=SecretWord;" +
"Initial Catalog=Employee";
ADODataSet1->ConnectionString = "Provider=YourProvider;Password=SecretWord;";
ADODataSet1->ConnectionString += "User ID=JaneDoe;SERVER=PURGATORY";
ADODataSet1->ConnectionString += "UID=JaneDoe;PWD=SecretWord;"
ADODataSet1->ConnectionString += "Initial Catalog=Employee";
At design time you can use the Connection String Editor to help you build the connection string. For more information about
connection strings, see Connecting to a data store using TADOConnection ( see page 1478).

See Also
Filtering Records Based On Bookmarks ( see page 1482)

Working with Record Sets ( see page 1494)

Using Batch Updates ( see page 1491)

Loading Data from and Saving Data to Files ( see page 1486)

Fetching Records Asynchronously ( see page 1481)

3.2.3.1.10 Controlling Timeouts


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:
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)

3.2.3.1.11 Fetching Records Asynchronously


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 a set that includes zero or more of the following values:

Execution options for ADO datasets

Execute Option Meaning


eoAsyncExecute The command or data fetch operation is executed asynchronously.
eoAsyncFetch The dataset first fetches the number of records specified by the CacheSize property
synchronously, then fetches any remaining rows asynchronously.
eoAsyncFetchNonBlocking Asynchronous data fetches or command execution do not block the current thread of execution.
eoExecuteNoRecords A command or stored procedure that does not return data. If any rows are retrieved, they are
discarded and not returned.

See Also
Connecting an ADO Dataset to a Data Store ( see page 1479)

Working with Record Sets ( see page 1494)

Using Batch Updates ( see page 1491)

Loading Data from and Saving Data to Files ( see page 1486)

Filtering Records Based On Bookmarks ( see page 1482)

3.2.3.1.12 Filtering Multiple Rows Based On Update Status


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 3
(except rows marked for deletion). The example below causes only pending batch update rows to be visible.
FilterGroup := fgPendingRecords;
Filtered := True;
FilterGroup = fgPendingRecords;
Filtered = true;
Note: For the FilterGroup property to have an effect, the ADO dataset component's Filtered property must be set to True.

1481
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

See Also
Opening the Dataset in Batch Update Mode ( see page 1487)

Inspecting the Update Status of Individual Rows ( see page 1485)

Applying the Batch Updates to Base Tables ( see page 1476)

Canceling Batch Updates ( see page 1476)

3.2.3.1.13 Filtering Records Based On Bookmarks


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.

To filter on a set of bookmarks


1. Use the Bookmark method to mark the records you want to include in the filtered dataset.
2. Call the FilterOnBookmarks method to filter the dataset so that only the bookmarked records appear.
This process is illustrated below:
procedure TForm1.Button1Click(Sender: TObject);
var
BM1, BM2: TBookmarkStr;
begin
with ADODataSet1 do begin
BM1 := Bookmark;
BMList.Add(Pointer(BM1));
MoveBy(3);
BM2 := Bookmark;
BMList.Add(Pointer(BM2));
FilterOnBookmarks([BM1, BM2]);
end;
end;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TBookmarkStr BM1;
TBookmarkStr BM2;
BM1 = ADODataSet1->Bookmark;
BMList->Add(BM1);
ADODataSet1->MoveBy(3);
BM2 = ADODataSet1->Bookmark;
BMList->Add(BM2);
ADODataSet1->FilterOnBookmarks(ARRAYOFCONST((BM1,BM2)));
}
Note that the example above also adds the bookmarks to a list object named BMList. This is necessary so that the application
can later free the bookmarks when they are no longer needed.

See Also
3
Connecting an ADO Dataset to a Data Store ( see page 1479)

Working with Record Sets ( see page 1494)

Using Batch Updates ( see page 1491)

Loading Data from and Saving Data to Files ( see page 1486)

Fetching Records Asynchronously ( see page 1481)

1482
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications

3.2.3.1.14 Fine-tuning a Connection


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:

• Forcing asynchronous connections ( see page 1483)


• Controlling time-outs ( see page 1480)
• Indicating the types of operations the connection supports ( see page 1485)
• Specifying whether the connection automatically initiates transactions ( see page 1489)
See Also
Connecting to Databases ( see page 1506)

Connecting to a Data Store Using TADOConnection ( see page 1478)

Accessing the Connection's Datasets ( see page 1475)

ADO Connection Events ( see page 1474)

3.2.3.1.15 Forcing Asynchronous Connections


Use the ConnectOptions property to force the connection to be asynchronous. Asynchronous connections allow your application
to continue processing without waiting for the connection to be completely opened.

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)

3.2.3.1.16 Handling Command Parameters


There are two ways in which a TADOCommand object may use parameters:

• 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)

Using the Execute Method ( see page 1493)

Canceling Commands ( see page 1477)

Retrieving Result Sets with Commands ( see page 1488)

1484
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications

3.2.3.1.17 Indicating the Types of Operations the Connection Supports


ADO connections are established using a specific mode, similar to the mode you use when opening a file. The connection mode
determines the permissions available to the connection, and hence the types of operations (such as reading and writing) that can
be performed using that connection.

Use the Mode property to indicate the connection mode. The possible values are listed in the following table:

ADO connection modes

Connect Mode Meaning


cmUnknown Permissions are not yet set for the connection or cannot be determined.
cmRead Read-only permissions are available to the connection.
cmWrite Write-only permissions are available to the connection.
cmReadWrite Read/write permissions are available to the connection.
cmShareDenyRead Prevents others from opening connections with read permissions.
cmShareDenyWrite Prevents others from opening connection with write permissions.
cmShareExclusive Prevents others from opening connection.
cmShareDenyNone Prevents others from opening connection with any permissions.

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)

Controlling Timeouts ( see page 1480)

3.2.3.1.18 Inspecting the Update Status of Individual Rows


Determine the update status of a given row by making it current and then inspecting the RecordStatus property of the ADO data
component. RecordStatus reflects the update status of the current row and only that row.
if (rsNew in ADOQuery1.RecordStatus) then
begin
...
end;
else
if (rsDeleted in ADOQuery1.RecordStatus) then
begin
...
else
switch (ADOQuery->RecordStatus)
{
case rsUnmodified: 3
StatusBar1->Panels->Items[0]->Text = "Unchanged record";
break;
case rsModified:
StatusBar1->Panels->Items[0]->Text = "Changed record";
break;
case rsDeleted:
StatusBar1->Panels->Items[0]->Text = "Deleted record";
break;
case rsNew:
StatusBar1->Panels->Items[0]->Text = "New record";

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)

Filtering Multiple Rows Based On Update Status ( see page 1481)

Applying the Batch Updates to Base Tables ( see page 1476)

Canceling Batch Updates ( see page 1476)

3.2.3.1.19 Loading Data from and Saving Data to Files


The data retrieved via an ADO dataset component can be saved to a file for later retrieval on the same or a different computer.
The data is saved in one of two proprietary formats: ADTG or XML. These two file formats are the only formats supported by
ADO. However, both formats are not necessarily supported in all versions of ADO. Consult the ADO documentation for the
version you are using to determine what save file formats are supported.

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

Statusbar1->Panels->Items[0]->Text = "Save file does not exist!";


}
The datasets that save and load the data need not be on the same form as above, in the same application, or even on the same
computer. This allows for the briefcase-style transfer of data from one computer to another.

See Also
Connecting an ADO Dataset to a Data Store ( see page 1479)

Working with Record Sets ( see page 1494)

Fetching Records Asynchronously ( see page 1481)

Using Batch Updates ( see page 1491)

Filtering Records Based On Bookmarks ( see page 1482)

3.2.3.1.20 Opening the Dataset in Batch Update Mode


To open an ADO dataset in batch update mode, it must meet these criteria:

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)

Filtering Multiple Rows Based On Update Status ( see page 1481)


3
Applying the Batch Updates to Base Tables ( see page 1476)

Canceling Batch Updates ( see page 1476)

3.2.3.1.21 Overview of ADO Components


The ADO page 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. They require ADO 2.1 (or higher) to

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.

The following table lists the ADO components.

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.

3.2.3.1.22 Retrieving Result Sets with Commands


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 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)

Using the Execute Method ( see page 1493)

Canceling Commands ( see page 1477)

Handling Command Parameters ( see page 1484)

3.2.3.1.23 Specifying the Command


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.
with ADOCommand1 do begin
CommandText := "AddEmployee";
CommandType := cmdStoredProc;
...
end;
ADOCommand1->CommandText = "AddEmployee";
ADOCommand1->CommandType = cmdStoredProc;
...
If no specific type is specified, the server is left to decide as best it can based on the command in CommandText.

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)

Canceling Commands ( see page 1477)

Retrieving Result Sets with Commands ( see page 1488)

Handling Command Parameters ( see page 1484)

3.2.3.1.24 Specifying Whether the Connection Automatically Initiates


Transactions
Use the Attributes property to control the connection component's use of 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
3
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 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

procedure TForm1.RetainingCommitsOnButtonClick(Sender: TObject);


begin
with ADOConnection1 do begin
Close;
if not (xaCommitRetaining in Attributes) then
Attributes := (Attributes + [xaCommitRetaining])
Open;
end;
end;
procedure TForm1.RetainingCommitsOffButtonClick(Sender: TObject);
begin
with ADOConnection1 do begin
Close;
if (xaCommitRetaining in Attributes) then
Attributes := (Attributes - [xaCommitRetaining]);
Open;
end;
end;
void __fastcall TForm1::RetainingCommitsOnButtonClick(TObject *Sender)
{
ADOConnection1->Close()
if (!ADOConnection1->Attributes.Contains(xaCommitRetaining))
ADOConnection1->Attributes = TXactAttributes() << xaCommitRetaining;
ADOConnection1->Open()
}
void __fastcall TForm1::RetainingCommitsOffButtonClick(TObject *Sender)
{
ADOConnection1->Close()
if (ADOConnection1->Attributes.Contains(xaCommitRetaining))
ADOConnection1->Attributes = TXactAttributes() >> xaCommitRetaining;
ADOConnection1->Open()
}
See Also
Controlling Timeouts ( see page 1480)

Indicating the Types of Operations the Connection Supports ( see page 1485)

Indicating the Types of Operations the Connection Supports ( see page 1485)

3.2.3.1.25 Using ADO datasets


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:

• Connecting to an ADO datastore ( see page 1479)


• Accessing the underlying Recordset object ( see page 1494)
• Filtering records based on bookmarks ( see page 1482)
3 • Fetching records asynchronously ( see page 1481)
• Performing batch updates (caching updates) ( see page 1491)
• Using files on disk to store data ( see page 1486)
There are four ADO datasets:
• TADOTable, a table-type dataset ( see page 1620) that represents all of the rows and columns of a single database table.
• TADOQuery, a query-type dataset ( see page 1618) that encapsulates an SQL statement and enables applications to
access the resulting records, if any.

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)

Connecting to ADO Data Stores ( see page 1477)

3.2.3.1.26 Using Batch Updates


One approach for caching updates is to connect the ADO dataset to a client dataset using a dataset provider. This approach is
discussed in Using a client dataset to cache updates ( see page 1731).

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:

Comparison of ADO and client dataset cached updates

ADO dataset TClientDataSet Description

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:

• Opening the dataset in batch update mode ( see page 1487)


• Inspecting the update status of individual rows ( see page 1485)
3
• Filtering multiple rows based on update status ( see page 1481)
• Applying the batch updates to base tables ( see page 1476)
• Canceling batch updates ( see page 1476)
See Also
Connecting an ADO Dataset to a Data Store ( see page 1479)

Working with Record Sets ( see page 1494)

1491
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

Fetching Records Asynchronously ( see page 1481)

Loading Data from and Saving Data to Files ( see page 1486)

Filtering Records Based On Bookmarks ( see page 1482)

3.2.3.1.27 Using Command Objects


In the ADO environment, commands are textual representations of provider-specific action requests. Typically, they are Data
Definition Language (DDL) and Data Manipulation Language (DML) SQL statements. The language used in commands is
provider-specific, but usually compliant with the SQL-92 standard for the SQL language.

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:

• Specifying the command ( see page 1489)


• Using Command objects ( see page 1493)
• Canceling commands ( see page 1477)
• Retrieving result sets with commands ( see page 1488)
• Handling command parameters ( see page 1484)
See Also
Using TADODataSet ( see page 1492)

Connecting to ADO Data Stores ( see page 1477)

Using the Execute Method ( see page 1493)

3.2.3.1.28 Using TADODataSet


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:

• 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

3.2.3.1.29 Using the Execute Method


Before TADOCommand can execute its command, it must have a valid connection to a data store. This is established just as
with an ADO dataset. See Connecting an ADO dataset to a data store ( see page 1479) for details.

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)

Canceling Commands ( see page 1477)

Retrieving Result Sets with Commands ( see page 1488)

1493
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

Handling Command Parameters ( see page 1484)

3.2.3.1.30 Working with ADO Components


The dbGo components provide data access through the ADO framework. ADO, (Microsoft ActiveX Data Objects) is a set of COM
objects that access data through an OLE DB provider. The dbGo components encapsulate these ADO objects in the Delphi
database architecture.

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:

• Overview of ADO components ( see page 1487)


• Connecting to ADO data stores ( see page 1477)
• Using TADODataSet ( see page 1492)
• Using Command Objects ( see page 1492)
See Also
Understanding Datasets ( see page 1632)

Connecting to Databases ( see page 1506)

Working With ADO Components

Designing Database Applications ( see page 1566)

Using Data Controls ( see page 1778)

Working with Field Components ( see page 1877)

Creating and Using a Client Dataset ( see page 1740)

Using Unidirectional Datasets ( see page 1823)

Using the Borland Database Engine ( see page 1643)

Using Provider Components ( see page 1819)

Creating Multi-tiered Applications: Overview ( see page 1518)


3
Using Decision Support Components ( see page 1800)

Using XML in Database Applications ( see page 1847)

3.2.3.1.31 Working with Record Sets


The Recordset property provides direct access to the ADO recordset object underlying the dataset component. Using this object,
it is possible to access properties and call methods of the recordset object from an application. Use of Recordset to directly

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)

Filtering Records Based On Bookmarks ( see page 1482)

Using Batch Updates ( see page 1491)

Loading Data from and Saving Data to Files ( see page 1486)

Fetching Records Asynchronously ( see page 1481)

3.2.3.2 Connecting to databases


Topics
Name Description
Controlling Connections ( see page 1497) Before you can establish a connection to a database server, your application
must provide certain key pieces of information that describe the desired server.
Each type of connection component surfaces a different set of properties to let
you identify the server. In general, however, they all provide a way for you to
name the server you want and supply a set of connection parameters that control
how the connection is formed. Connection parameters vary from server to server.
They can include information such as user name and password, the maximum
size of BLOB fields, SQL roles, and so on.
Once... more ( see page 1497)
Disconnecting from a Database Server ( see page 1497) There are two ways to disconnect a server using a connection component:

• Set the Connected property to False.


• Call the Close method.
Calling Close sets Connected to False.
When Connected is set to False, the connection component
generates a BeforeDisconnect event, where you can
perform any cleanup before the connection closes. For
example, you can use this event to cache information
about all open datasets before they are closed.
3
After the BeforeConnect event, the connection component
closes all open datasets and disconnects from the server.
Finally, the connection component generates an
AfterDisconnect event, where you can respond... more (
see page 1497)

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:

• 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...
more ( see page 1504)
Using Implicit Connections ( see page 1505) No matter what data access mechanism you are using, you can always create
the connection component explicitly and use it to manage the connection to and
communication with a database server. For BDE-enabled and ADO-based
datasets, you also have the option of describing the database connection through
properties of the dataset and letting the dataset generate an implicit connection.
For BDE-enabled datasets, you specify an implicit connection using the
DatabaseName property. For ADO-based datasets, you use the
ConnectionString property.
When using an implicit connection, you do not need to explicitly create a
connection component. This can simplify your application development,... more
( see page 1505)
Working with Associated Datasets ( see page 1505) All database connection components maintain a list of all datasets that use them
to connect to a database. A connection component uses this list, for example, to
close all of the datasets when it closes the database connection.
You can use this list as well, to perform actions on all the datasets that use a
specific connection component to connect to a particular database.
Connecting to Databases: Overview ( see page 1506) Most dataset components can connect directly to a database server ( see page
1560). Once connected, the dataset communicates with the server automatically.
When you open the dataset, it populates itself with data from the server, and
3 when you post records, they are sent back the server and applied. A single
connection component can be shared by multiple datasets, or each dataset can
use its own connection.
Each type of dataset connects to the database server using its own type of
connection component, which is designed to work with a single data access
mechanism. The following table lists these data access mechanisms and... more
( see page 1506)

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:

• Call the Open method.


• Set the Connected property to True.
Calling the Open method sets Connected to True.
Note: When a connection component is not connected to
a server and an application attempts to open one of its
associated datasets, the dataset automatically calls the
connection component's Open method.
When you set Connected to True, the connection
component first generates a BeforeConnect event, where
you can perform any initialization. For example, you can
use this event to alter connection parameters.
After the BeforeConnect... more ( see page 1509)

3.2.3.2.1 Controlling Connections


Before you can establish a connection to a database server, your application must provide certain key pieces of information that
describe the desired server. Each type of connection component surfaces a different set of properties to let you identify the
server. In general, however, they all provide a way for you to name the server you want and supply a set of connection
parameters that control how the connection is formed. Connection parameters vary from server to server. They can include
information such as user name and password, the maximum size of BLOB fields, SQL roles, and so on.

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:

• Connecting to a Database Server ( see page 1509)


• Disconnecting From a Database Server ( see page 1497)
See Also
Using Implicit Connections ( see page 1505)

Controlling Server Login ( see page 1507)

Managing Transactions ( see page 1498)


3
Working with Associated Datasets ( see page 1505)

Sending Commands to the Server ( see page 1502)

3.2.3.2.2 Disconnecting from a Database Server


There are two ways to disconnect a server using a connection component:

1497
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

• Set the Connected property to False.


• Call the Close method.
Calling Close sets Connected to False.
When Connected is set to False, the connection component generates a BeforeDisconnect event, where you can perform any
cleanup before the connection closes. For example, you can use this event to cache information about all open datasets
before they are closed.
After the BeforeConnect event, the connection component closes all open datasets and disconnects from the server.
Finally, the connection component generates an AfterDisconnect event, where you can respond to the change in connection
status, such as enabling a Connect button in your user interface.
Note: Calling Close or setting Connected to False disconnects from a database server even if the connection component has
a KeepConnection property that is True.
See Also
Connecting to a Database Server ( see page 1509)

3.2.3.2.3 Managing Transactions


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 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).

For TADOConnection, start a transaction by calling the BeginTrans method:


Level := ADOConnection1.BeginTrans;
Level = ADOConnection1->BeginTrans();

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

the transaction descriptor you gave to the StartTransaction method:


MyOracleConnection.Commit(TD);
MyOracleConnection->Commit(TD);
For TIBDatabase, you commit a transaction object using its Commit method:
IBDatabase1.DefaultTransaction.Commit;
IBDatabase1->DefaultTransaction->Commit();
For TADOConnection, you commit a transaction using the CommitTrans method:
ADOConnection1.CommitTrans;
ADOConnection1->CommitTrans();
Note: It is possible for a nested transaction to be committed, only to have the changes rolled back later if the parent transaction
is rolled back.

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.

A call to roll back the current transaction usually occurs in

• 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)

Controlling Connections ( see page 1497)

Using Implicit Connections ( see page 1505)

Working with Associated Datasets ( see page 1505)

Sending Commands to the Server ( see page 1502)

1500
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications

Transactions ( see page 1570)

Obtaining Metadata ( see page 1501)

3.2.3.2.4 Obtaining Metadata


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 at
runtime.

Listing available tables


The GetTableNames method copies a list of table names to an already-existing string list object. This can be used, for example,
to fill a list box with table names that the user can then use to choose a table to open. The following line fills a listbox with the
names of all tables on the database:
MyDBConnection.GetTableNames(ListBox1.Items, False);
MyDBConnection->GetTableNames(ListBox1->Items, false);
GetTableNames has two parameters: the string list to fill with table names, and a boolean that indicates whether the list should
include system tables, or ordinary tables. Note that not all servers use system tables to store metadata, so asking for system
tables may result in an empty list.

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.

Listing the fields in a table


The GetFieldNames method fills an existing string list with the names of all fields (columns) in a specified table. GetFieldNames
takes two parameters, the name of the table for which you want to list the fields, and an existing string list to be filled with field
names:
MyDBConnection.GetFieldNames('Employee', ListBox1.Items);
MyDBConnection->GetTableNames("Employee", ListBox1->Items);
Listing available stored procedures
To get a listing of all of the stored procedures contained in the database, use the GetProcedureNames method. This method
takes a single parameter: an already-existing string list to fill:
MyDBConnection.GetProcedureNames(ListBox1.Items);
MyDBConnection->GetProcedureNames(ListBox1->Items);
Note: GetProcedureNames is only available for TADOConnection and TSQLConnection.

Listing available indexes 3


To get a listing of all indexes defined for a specific table, use the GetIndexNames method. This method takes two parameters:
the table whose indexes you want, and an already-existing string list to fill:
SQLConnection1.GetIndexNames('Employee', ListBox1.Items);
MyDBConnection1->GetIndexNames("Employee", ListBox1->Items);
Note: GetIndexNames is only available for TSQLConnection, although most table-type datasets have an equivalent method.

1501
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

Listing stored procedure parameters


To get a list of all parameters defined for a specific stored procedure, use the GetProcedureParams method.
GetProcedureParams fills a TList object with pointers to parameter description records, where each record describes a
parameter of a specified stored procedure, including its name, index, parameter type, field type, and so on.

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.

Note: GetProcedureParams is only available for TSQLConnection.

See Also
Controlling Server Login ( see page 1507)

Controlling Connections ( see page 1497)

Using Implicit Connections ( see page 1505)

Sending Commands to the Server ( see page 1502)

Managing Transactions ( see page 1498)

Understanding Datasets ( see page 1632)

Working with Associated Datasets ( see page 1505)

3.2.3.2.5 Sending Commands to the Server


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 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)

Controlling Connections ( see page 1497)

Using Implicit Connections ( see page 1505)

Working with Associated Datasets ( see page 1505)

Managing Transactions ( see page 1498)

3.2.3.2.6 Specifying the Transaction Isolation Level


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:

• 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)

3.2.3.2.7 Using Implicit Connections


No matter what data access mechanism you are using, you can always create the connection component explicitly and use it to
manage the connection to and communication with a database server. For BDE-enabled and ADO-based datasets, you also
have the option of describing the database connection through properties of the dataset and letting the dataset generate an
implicit connection. For BDE-enabled datasets, you specify an implicit connection using the DatabaseName property. For
ADO-based datasets, you use the ConnectionString property.

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)

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)

3.2.3.2.8 Working with Associated Datasets


All database connection components maintain a list of all datasets that use them to connect to a database. A connection
component uses this list, for example, to close all of the datasets when it closes the database connection.

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.

Closing all datasets without disconnecting from the server


The connection component automatically closes all datasets when you close its connection. There may be times, however, when
you want to close all datasets without disconnecting from the database server.

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

TSQLConnection, you must also set the KeepConnection property to True.

Iterating through the associated datasets


To perform any actions (other than closing them all) on all the datasets that use a connection component, use the DataSets and
DataSetCount properties. DataSets is an indexed array of all datasets that are linked to the connection component. For all
connection components except TADOConnection, this list includes only the active datasets. TADOConnection lists the inactive
datasets as well. DataSetCount is the number of datasets in this array.

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)

Controlling Connections ( see page 1497)

Using Implicit Connections ( see page 1505)

Sending Commands to the Server ( see page 1502)

Managing Transactions ( see page 1498)

Understanding Datasets ( see page 1632)

Obtaining Metadata ( see page 1501)

3.2.3.2.9 Connecting to Databases: Overview


Most dataset components can connect directly to a database server ( see page 1560). Once connected, the dataset
communicates with the server automatically. When you open the dataset, it populates itself with data from the server, and when
you post records, they are sent back the server and applied. A single connection component can be shared by multiple datasets,
or each dataset can use its own connection.
3 Each type of dataset connects to the database server using its own type of connection component, which is designed to work
with a single data access mechanism. The following table lists these data access mechanisms and the associated connection
components:

Database connection components

Data Access Mechanism Connection Component


Borland Database Engine (BDE) TDatabase

1506
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications

ActiveX Data Objects (ADO) TADOConnection


dbExpress TSQLConnection
InterBase Express TIBDatabase

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)

Understanding Datasets ( see page 1632)

Using Data Controls ( see page 1778)

Working with Field Components ( see page 1877)

Creating and Using a Client Dataset ( see page 1740)

Working With ADO Components ( see page 1494)

Using Unidirectional Datasets ( see page 1823)

Using the Borland Database Engine ( see page 1643)

Using Provider Components ( see page 1819)

Creating Multi-tiered Applications: Overview ( see page 1518) 3


Using Decision Support Components ( see page 1800)

Using XML in Database Applications ( see page 1847)

3.2.3.2.10 Controlling Server Login


Most remote database servers include security features to prohibit unauthorized access. Usually, the server requires a user

1507
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

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 (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)

Controlling Connections ( see page 1497)

Managing Transactions ( see page 1498)

Working with Associated Datasets ( see page 1505)

Sending Commands to the Server ( see page 1502)

3.2.3.2.11 Connecting to a Database Server


There are two ways to connect to a database server using a connection component:

• Call the Open method.


• Set the Connected property to True.
Calling the Open method sets Connected to True.
Note: When a connection component is not connected to a server and an application attempts to open one of its associated
datasets, the dataset automatically calls the connection component's Open method.
When you set Connected to True, the connection component first generates a BeforeConnect event, where you can perform
any initialization. For example, you can use this event to alter connection parameters.
After the BeforeConnect event, the connection component may display a default login dialog, depending on how you choose
to control server login ( see page 1507). It then passes the user name and password to the driver, opening a connection.
Once the connection is open, the connection component generates an AfterConnect event, where you can perform any tasks
that require an open connection.
Note: Some connection components generate additional events as well when establishing a connection.
Once a connection is established, it is maintained as long as there is at least one active dataset using it. When there are no
more active datasets, the connection component drops the connection. Some connection components surface a
KeepConnection property that allows the connection to remain open even if all the datasets that use it are closed. If 3
KeepConnection is True, the connection is maintained. For connections to remote database servers, or for applications that
frequently open and close datasets, setting KeepConnection to True reduces network traffic and speeds up the application. If
KeepConnection is False, the connection is dropped when there are no active datasets using the database. If a dataset that
uses the database is later opened, the connection must be reestablished and initialized.
See Also
Disconnecting from a Database Server ( see page 1497)

1509
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

3.2.3.3 Creating multi-tiered applications


Topics
Name Description
Connecting to the Application Server ( see page 1517) To establish and maintain a connection to an application server, a client
application uses one or more connection components. You can find these
components on the DataSnap or WebServices category of the Tool Palette.
Use a connection component to

• 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 ( see page 1537)... more ( see page 1517)
Creating Multi-tiered Applications: Overview ( see page 1518) 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 ( see page 1519), such as centralized
business logic and thin client applications.
In its simplest form, sometimes called the "three-tiered model," a multi-tiered
application is partitioned into thirds:

• Client application: provides a user interface on the


user's machine.
• Application server: resides in a central networking
location accessible to all clients and provides common
data services.
• Remote database server: provides the relational
database... more ( see page 1518)
Connecting to the Server ( see page 1519) To locate and connect to the application server, you must first set the properties
of the connection component to identify the application server. This process is
described in Connecting to the application server ( see page 1517). Before
opening the connection, any client datasets that use the connection component
to communicate with the application server should indicate this by setting their
RemoteServer property to specify the connection component.
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... more (
see page 1519)
Advantages of the Multi-tiered Database Model ( see page 1519) The multi-tiered database model breaks a database application into logical
pieces. The client application can focus on data display and user interactions.
Ideally, it knows nothing about how the data is stored or maintained. The
application server (middle tier) coordinates and processes requests and updates
from multiple clients. It handles all the details of defining datasets and interacting
with the database server.
3 The advantages of this multi-tiered model include the following:

• 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)... more ( see page 1519)

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:

• Using DCOM Connections ( see page 1546)


• Using Socket Connections ( see page 1548)
• Using Web Connections ( see page 1550)
• Using SOAP Connections ( see page 1548)
Configuring TMTSDataModule ( see page 1524) To add a TMTSDataModule component to your application, choose
File New Other and select Transactional Data Module from the Multitier
page of the new items dialog. You will see the Transactional Data Module wizard.
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... more ( see page 1524)
Configuring TRemoteDataModule ( see page 1525) To add a TRemoteDataModule component to your application, choose
File New Other and select Remote Data Module from the ActiveX page of
the new items dialog. You will see the Remote Data Module wizard.
3
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... more ( see page 1525)

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

• set the Connected property to False.


• free the connection component. A connection object is
automatically freed when a user closes the client
application.

3 • change any of the properties that identify the application


server (ServerName, ServerGUID, ComputerName, and
so on). Changing these properties allows you to switch
among available application servers at runtime. The
connection component drops the current connection and
establishes a new one.
Note: Instead of using a single connection component to
switch among available application servers, a client
application can instead... more ( see page 1531)

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

• Choose the Add to Interface command from the Edit menu


in the IDE. Indicate whether you... more ( see page 1531)
Granting Permission to Access and Launch the Application Server ( see page Requests from the InternetExpress application appear to the application server
1532) as originating from a guest account with the name IUSR_computername, where
computername is the name of the system running the Web application. By
default, this account does not have access or launch permission for the
application server. If you try to use the Web application without granting these
permissions, when the Web browser tries to load the requested page it times out
with EOLE_ACCESS_ERROR.
Note: Because the application server runs under this guest account, it can't be
shut down by other accounts.
To grant the Web application access and launch... more ( see page 1532)
Managing Server Connections ( see page 1533) The main purpose of connection components is to locate and connect to the
application server. Because they manage server connections, you can also use
connection components to call the methods of the application server's interface.
The following topics describe how to use a connection component for

• Connecting to the Server ( see page 1519).


• Dropping or Changing a Server Connection ( see page
1531).
• Calling Server Interfaces ( see page 1522).
• Connecting to an Application Server that Uses Multiple
Data Modules ( see page 1526).
Managing Transactions in Multi-tiered Applications ( see page 1533) When client applications apply updates to the application server, the provider
component automatically wraps the process of applying updates and resolving
errors in a transaction. This transaction is committed if the number of problem
records does not exceed the MaxErrors value specified as an argument to the
ApplyUpdates method. Otherwise, it is rolled back.
In addition, you can add transaction support to your server application by adding
a database connection component or managing the transaction directly by
sending SQL to the database server. This works the same way that you would
manage transactions in a two-tiered application. For more information... more (
see page 1533)
Overview of a Three-tiered Application ( see page 1534) The following numbered steps illustrate a normal sequence of events for a
provider-based three-tiered application:

1. A user starts the client application. The client connects to


the application server (which can be specified at design
time or runtime). If the application server is not already
running, it starts. The client receives an IAppServer
interface for communicating with the application server.
2. The client requests data from the application server. A
client may request all data at once, or may request chunks
of data throughout the session (fetch on demand).
3. The application server retrieves the data (first establishing 3
a database connection, if necessary),... more ( see page
1534)

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.

• If the application server uses DCOM, HTTP, or sockets as


a communication protocol, it acts as an Automation server
and must be registered like any other COM server. For
information about registering a COM server, see
Registering a COM Object ( see page 1440).
• If you are using a transactional data module, you do not
register the application server. Instead, you install it with
COM+ or MTS. .
• When the application server uses SOAP, the application
must be a Web Service application. As such, it must be...
more ( see page 1535)
Setting Up the Remote Data Module ( see page 1536) When you create the remote data module, you must provide certain information
that indicates how it responds to client requests. This information varies,
depending on the type of remote data module. See The Structure of the
Application Server ( see page 1542) for information on what type of remote
data module you need.
The following topics describe how to configure each type of remote data module:

• Configuring TRemoteDataModule ( see page 1525)


• Configuring TMTSDataModule ( see page 1524)
• Configuring TSoapDataModule ( see page 1525)
Setting Web Item Properties ( see page 1536) The Web items that you add using the Web page editor are specialized
components that generate HTML. Each Web item class is designed to produce a
specific control or section of the final HTML document, but a common set of
properties influences the appearance of the final HTML.
When a Web item represents information from the XML data packet (for example,
when it generates a set of field or parameter display controls or a button that
manipulates the data), the XMLBroker property associates the Web item with the
XML broker that manages the data packet. You can further specify a... more (
see page 1536)
Specifying a Connection Using HTTP ( see page 1537) You can establish a connection to the application server using HTTP from any
machine that has a TCP/IP address. Unlike sockets, however, HTTP allows you
to take advantage of SSL security and to communicate with a server that is
protected behind a firewall. When using HTTP, include a TWebConnection
component for connecting to the application server.
The Web connection component establishes a connection to the Web server
application (httpsrvr.dll), which in turn communicates with the application server.
TWebConnection locates httpsrvr.dll using a Uniform Resource Locator (URL).
The URL specifies the protocol (http or, if you are using SSL security, https),...
more ( see page 1537)
Specifying a Connection Using DCOM ( see page 1537) When using DCOM to communicate with the application server, client
applications include a TDCOMConnection component for connecting to the
3 application server. TDCOMConnection uses the ComputerName property to
identify the machine on which the server resides.
When ComputerName is blank, the DCOM connection component assumes that
the application server resides on the client machine or that the application server
has a system registry entry. If you do not provide a system registry entry for the
application server on the client when using DCOM, and the server resides on a
different machine from the client, you must supply ComputerName.
Note: Even... more ( see page 1537)

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:

• It fetches XML data packets from the application server


and makes them available to the Web Items that generate
HTML for the InternetExpress application.
• It receives updates in the form of XML delta packets from
browsers and applies them to the application server.
Using DCOM Connections ( see page 1546) DCOM provides the most direct approach to communication, requiring no
additional runtime applications on the server.
DCOM provides the only approach that lets you use security services when
writing a transactional data module. These security services are based on
assigning roles to the callers of transactional objects. When using DCOM, DCOM
identifies the caller to the system that calls your application server (COM+ or
MTS). Therefore, it is possible to accurately determine the role of the caller.
When using other protocols, however, there is a runtime executable, separate
from the application server, that receives client calls. This runtime executable
makes... more ( see page 1546)
Using Transactional Data Modules ( see page 1546) You can write an application server that takes advantage of special services for
distributed applications that are supplied by COM+ (under Windows 2000 and
later) or MTS (before Windows 2000). To do so, create a transactional data
module instead of an ordinary remote data module.
When you use a transactional data module, your application can take advantage
of the following special services:

• Security. COM+ (or MTS) provides role-based security


for your application server. Clients are assigned roles,
which determine how they can access the MTS data
module's interface. The MTS data module implements the
IsCallerInRole method, which you lets you... more ( see
page 1546)
Using Multiple Remote Data Modules ( see page 1547) You may want to structure your application server so that it uses multiple remote
data modules. Using multiple remote data modules lets you partition your code,
organizing a large application server into multiple units, where each unit is
relatively self-contained.
Although you can always create multiple remote data modules on the application
server that function independently, a special connection component on the
DataSnap category of the Tool palette provides support for a model where you
have one main "parent" remote data module that dispatches connections from
clients to other "child" remote data modules. This model requires that you use a...
more ( see page 1547)
Using SOAP Connections ( see page 1548) SOAP is the protocol that underlies the built-in support for Web Service
applications. SOAP marshals method calls using an XML encoding. SOAP
connections use HTTP as a transport protocol.
SOAP connections have the advantage that they work in cross-platform
applications because they are supported on both the Windows and Linux.
Because SOAP connections use HTTP, they have the same advantages as Web
connections: HTTP provides a lowest common denominator that you know is
available on all clients, and clients can communicate with an application server
3 that is protected by a "firewall." For more information about using SOAP to
distribute applications,... more ( see page 1548)
Using Socket Connections ( see page 1548) TCP/IP Sockets let you create lightweight clients. For example, if you are writing
a Web-based client application ( see page 1551), you can't be sure that client
systems support DCOM. Sockets provide a lowest common denominator that you
know will be available for connecting to the application server. For more
information about sockets, see Working with Sockets. ( see page 2337)
Instead of instantiating the remote data module directly from the client (as
happens with DCOM), sockets use a separate application on the server
(ScktSrvr.exe), which accepts client requests and instantiates the remote data
module using COM. The connection component on the client and ScktSrvr.exe...
more ( see page 1548)

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:

• You can combine the multi-tiered database architecture


with an ActiveX form to distribute the client application as
an ActiveX control ( see page 1530). This allows any
browser that supports ActiveX to... more ( see page
1551)

3.2.3.3.1 Connecting to the Application Server


To establish and maintain a connection to an application server, a client application uses one or more connection components.
You can find these components on the DataSnap or WebServices category of the Tool Palette.

Use a connection component to

• 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)

Managing Server Connections ( see page 1533)

Using a Client Dataset with a Data Provider ( see page 1732)

Calling Server Interfaces ( see page 1522)

3.2.3.3.2 Creating Multi-tiered Applications: Overview


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 ( see page 1519), such as centralized business logic and thin client applications.

In its simplest form, sometimes called the "three-tiered model," a multi-tiered application is partitioned into thirds:

• Client application: provides a user interface on the user's machine.


• Application server: resides in a central networking location accessible to all clients and provides common data services.
• Remote database server: provides the relational database management system (RDBMS).
In this three-tiered model, the application server manages the flow of data between clients and the remote database server, so it
is sometimes called a "data broker." You usually only create the application server and its clients, although, if you are really
ambitious, you could create your own database back end as well.
In more complex multi-tiered applications, additional services reside between a client and a remote database server. For
example, there might be a security services broker to handle secure Internet transactions, or bridge services to handle sharing
of data with databases on other platforms.
Support for developing multi-tiered applications is an extension of the way client datasets communicate with a provider
component using transportable data packets. See Understanding multi-tiered database applications ( see page 1544) for an
overview of this technology and the architecture of a typical three-tiered application. Once you understand how to create and
manage a three-tiered application, you can create and add additional service layers based on your needs.
Building a multi-tiered application ( see page 1520) provides details on how to apply this architecture to build a three-tiered
application. Writing Web-based client applications ( see page 1551) describes how to combine this architecture with other
3 technologies to create a Web-based multi-tiered application.
See Also
Designing Database Applications ( see page 1566)

Understanding Datasets ( see page 1632)

Using Data Controls ( see page 1778)

Working with Field Components ( see page 1877)

1518
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications

Creating and Using a Client Dataset ( see page 1740)

Connecting to Databases ( see page 1506)

Working With ADO Components ( see page 1494)

Using Unidirectional Datasets ( see page 1823)

Using the Borland Database Engine ( see page 1643)

Using Provider Components ( see page 1819)

Using XML in Database Applications ( see page 1847)

3.2.3.3.3 Connecting to the Server


To locate and connect to the application server, you must first set the properties of the connection component to identify the
application server. This process is described in Connecting to the application server ( see page 1517). Before opening the
connection, any client datasets that use the connection component to communicate with the application server should indicate
this by setting their RemoteServer property to specify the connection component.

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)

Calling Server Interfaces ( see page 1522)

Connecting to an Application Server That Uses Multiple Data Modules ( see page 1526)

3.2.3.3.4 Advantages of the Multi-tiered Database Model


The multi-tiered database model breaks a database application into logical pieces. The client application can focus on data
display and user interactions. Ideally, it knows nothing about how the data is stored or maintained. The application server (middle
tier) coordinates and processes requests and updates from multiple clients. It handles all the details of defining datasets and
interacting with the database server.

The advantages of this multi-tiered model include the following:

• 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)

Building a Multi-tiered Application ( see page 1520)

Writing Web-based Client Applications ( see page 1551)

3.2.3.3.5 Brokering Connections


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 on, until a connection is
formed.

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)

Specifying a Connection Using Sockets ( see page 1538)

3.2.3.3.6 Building a Multi-tiered Application


To create a multi-tiered database application
1. Create the application server ( see page 1527).
2. Register or install the application server ( see page 1535).
3. Create a client application ( see page 1528).
The order of creation is important. You should create and run the application server before you create a client. At design time,
you can then connect to the application server to test your client. You can, of course, create a client without specifying the
application server at design time, and only supply the server name at runtime. However, doing so prevents you from seeing if
your application works as expected when you code at design time, and you will not be able to choose servers and providers
3 using the Object Inspector.
Note: If you are not creating the client application on the same system as the server, and you are using a DCOM connection,
you may want to register the application server on the client system. This makes the connection component aware of the
application server at design time so that you can choose server names and provider names from a drop-down list in the
Object Inspector
. (If you are using a Web connection, SOAP connection, or socket connection, the connection component fetches the names
of registered providers from the server machine.)

1520
3.2 Win32 Developer's Guide RAD Studio Developing Database Applications

See Also
Understanding MIDAS Technology ( see page 1544)

Advantages of the Multi-tiered Database Model ( see page 1519)

Writing Web-based client applications ( see page 1551)

3.2.3.3.7 Building an InternetExpress Application


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).

To build a Web application using InternetExpress


1. Choose File New Other to display the New Items dialog box, and on the New page select Web Server application. This
process is described in Creating Web server applications with Web Broker.
2. From the DataSnap category of the Tool palette, add a connection component to the Web Module that appears when you
create a new Web server application. The type of connection component you add depends on the communication protocol
you want to use. See Choosing a connection protocol ( see page 1523) for details.
3. Set properties on your connection component to specify the application server with which it should establish a connection. To
learn more about setting up the connection component, see Connecting to the application server ( see page 1517).
4. Instead of a client dataset, add an TXMLBroker from the InternetExpress category of the Tool palette to the Web module.
Like TClientDataSet, TXMLBroker represents the data from a provider on the application server and interacts with the
application server through an IAppServer interface. However, unlike client datasets, XML brokers request data packets as
XML instead of as OleVariants and interact with InternetExpress components instead of data controls.
5. Set the RemoteServer property of the XML broker to point to the connection component you added in step 2. Set the
ProviderName property to indicate the provider on the application server that provides data and applies updates. For more
information about setting up the XML broker, see Using an XML broker ( see page 1544).
6. Add an InternetExpress page producer (TInetXPageProducer) to the Web module for each separate page that users will see
in their browsers. For each page producer, you must set the IncludePathURL property to indicate where it can find the
javascript libraries ( see page 1549) that augment its generated HTML controls with data management capabilities.
7. Right-click a Web page and choose Action Editor to display the Action editor. Add action items for every message you want to
handle from browsers. Associate the page producers you added in step 6 with these actions by setting their Producer property
or writing code in an OnAction event handler. For more information on adding action items using the Action editor, see Adding
actions to the dispatcher ( see page 2277).
8. Double-click each Web page to display the Web Page editor. (You can also display this editor by clicking the ellipsis button in
the Object Inspector next to the WebPageItems property.) In this editor you can add Web Items to design the pages that
users see in their browsers. For more information about designing Web pages for your InternetExpress application, see
Creating Web pages with an InternetExpress page producer ( see page 1529).
9. Build your Web application. Once you install this application with your Web server, browsers can call it by specifying the name
of the application as the script name portion of the URL ( see page 2253) and the name of the Web Page component as the
pathinfo portion.
3
See Also
Granting Permission to Access and Launch the Application Server ( see page 1532)

Creating the Application Server ( see page 1527)

Using the Javascript Libraries ( see page 1549)

1521
Developing Database Applications RAD Studio 3.2 Win32 Developer's Guide

3.2.3.3.8 Building Web Applications Using InternetExpress


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 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)

Distributing a Client Application as an ActiveX Control ( see page 1530)

3.2.3.3.9 Calling Server Interfaces


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 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

which ships with Delphi to register the type library.

Note: See the TRegSvr demo (which provides the source for TRegsvr.exe) for an example of how to register the type library
programmatically.

Using dispatch interfaces with TCP/IP or HTTP


When you are using TCP/IP or HTTP, you can't use true early binding, but because the remote data module uses a dual
interface, you can use the application server's dispinterface to improve performance over simple late binding. The dispinterface
has the same name as the remote data module's interface, with the string 'Disp' appended. You can assign the AppServer
property to a variable of this type to obtain the dispinterface. Thus:
var
TempInterface: IMyAppServerDisp;
begin
TempInterface :=IMyAppServerDisp(IDispatch(MyConnection.AppServer));
...
TempInterface.SpecialMethod(x,y);
...
end;
Note: To use the dispinterface, you must add the _TLB unit that is generated when you save the type library to the uses clause
of your client module.

Calling the interface of a SOAP-based server


If you are using SOAP, you can't use the AppServer property. Instead, you must obtain the server's interface by calling the
GetSOAPServer method. Before you call GetSOAPServer, however, you must take the following steps:

• 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)

3.2.3.3.10 Choosing a Connection Protocol


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

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:

• Using DCOM Connections ( see page 1546)


• Using Socket Connections ( see page 1548)
• Using Web Connections ( see page 1550)
• Using SOAP Connections ( see page 1548)
See Also
Overview of AMIDAS Based MultiTiered Applications ( see page 1542)

The Structure of the Client Application ( see page 1543)

The Structure of the Application Server ( see page 1542)

Pooling Application Servers ( see page 1535)

3.2.3.3.11 Configuring TMTSDataModule


To add a TMTSDataModule component to your application, choose File New Other and select Transactional Data Module
from the Multitier page of the new items dialog. You will see the Transactional Data Module wizard.

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

3.2.3.3.12 Configuring TRemoteDataModule


To add a TRemoteDataModule component to your application, choose File New Other and select Remote Data Module from
the ActiveX page of the new items dialog. You will see the Remote Data Module wizard.

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)

3.2.3.3.13 Configuring TSOAPDataModule


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.
3
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 IAppServerSOAP.

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)

3.2.3.3.14 Connecting to an Application Server That Uses Multiple Data


Modules
If a COM-based application server uses a main "parent" remote data module and 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

You might also like