home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
VSCPPv4.zip
/
VACPP
/
IBMCPP
/
HELP
/
CPPFAQ.INF
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
1995-05-02
|
286KB
|
8,579 lines
ΓòÉΓòÉΓòÉ 1. About this FAQ ΓòÉΓòÉΓòÉ
This FAQ provides answers to the questions that VisualAge C++ customers ask
most often about the product, how it works, and how to use it.
When you encounter a problem using VisualAge C++, look here first for the
solution. You can search for the information you need based on the symptoms of
your problem, or on the type of task you were trying to do when the problem
occurred. For a list of other information that you might also find helpful,
see Other Information You Might Find Helpful.
If the questions included here do not describe your problem, or if the answers
do not solve it, refer to What If I Still Have Questions?. Before you begin to
use this information, it would be helpful to understand how to navigate through
it. You can use the Table of Contents and Index facility to locate topics and
the Search facility to search the text of this document. You can use hypertext
links to acquire related information on the current topic. Hypertext links
appear in a different color (which you can customize using the OS/2 Scheme
Palette). For example, here is a link to another panel: Communicating Your
Comments to IBM. By double-clicking on the text of the link or by pressing
Enter on a highlighted link, you will open a panel of related information. When
you open a panel, the first link has the focus; to shift the focus to other
links, use the Tab key.
You should also understand:
How to Use the Contents
How to Obtain Additional Information
How to Use Action Bar Choices
How to Cut and Paste Examples
ΓòÉΓòÉΓòÉ 1.1. Notices ΓòÉΓòÉΓòÉ
Copyright International Business Machines Corporation, 1995. All rights
reserved.
Note to U.S. Government Users - Documentation related to restricted rights -
Use, duplication, or disclosure is subject to restrictions set forth in GSA ADP
Schedule Contract with IBM Corp.
First Edition, May 1995.
This edition applies to Version 3.0 of IBM VisualAge C++ for OS/2 (30H1664,
30H1665, 30H1666) and to all subsequent releases and modifications until
otherwise indicated in new editions. Make sure you are using the correct
edition for the level of the product.
This publication could include technical inaccuracies or typographical errors.
Changes are periodically made to the information herein; any such changes will
be reported in subsequent revisions.
Requests for publications and for technical information about IBM products
should be made to your IBM Authorized Dealer or your IBM Marketing
Representative.
When you send information to IBM, you grant IBM a nonexclusive right to use or
distribute the information in any ways it believes appropriate without
incurring any obligation to you.
Any reference to an IBM licensed program in this publication is not intended to
state or imply that only IBM's licensed program may be used. Any functionally
equivalent product, program, or service that does not infringe any of IBM's
intellectual property rights may be used instead of the IBM product, program,
or service. Evaluation and verification of operation in conjunction with other
products, except those expressly designated by IBM, is the user's
responsibility.
IBM may have patents or pending patent applications covering subject matter in
this document. The furnishing of this document does not give you any license
to these patents. You can send license inquiries, in writing, to the IBM
Director of Licensing. IBM Corporation, 500 Columbus Avenue, Thornwood, NY,
10594, USA.
This publication contains examples of data and reports used in daily business
operations. To illustrate them as completely as possible, the examples include
the names of individuals, companies, brands, and products. All of these names
are fictitious and any similarity to the names and addresses used by an actual
business enterprise is entirely coincidental.
ΓòÉΓòÉΓòÉ 1.2. Trademarks and Service Marks ΓòÉΓòÉΓòÉ
The following terms used in this publication are trademarks or service marks of
IBM Corporation in the United States or other countries:
AIX
C/2
C Set/2
C Set ++
IBM
Open Class
OS/2
OS/2 Warp
Presentation Manager
VisualAge
WorkFrame
Workplace Shell
Windows is a trademark of Microsoft Corporation.
Other company, product, and service names, which may be denoted by a double
asterisk(**), may be trademarks or service marks of others.
ΓòÉΓòÉΓòÉ 1.3. How to Use the Contents ΓòÉΓòÉΓòÉ
When the Contents window first appears, some topics have a plus (+) sign beside
them. The plus sign indicates that additional topics are available.
To expand the Contents if you are using a mouse, click on the plus sign. If
you are using the keyboard, use the Up or Down Arrow key to highlight the
topic, and press the plus (+) key. For example, How to Use the Contents has a
plus sign beside it. To see additional topics for that heading, click on the
plus sign or highlight that topic and press the plus (+) key.
To view a topic, double-click on the topic (or press the Up or Down Arrow key
to highlight the topic, and then press the Enter key).
ΓòÉΓòÉΓòÉ 1.4. How to Obtain Additional Information ΓòÉΓòÉΓòÉ
After you select a topic, the information for that topic appears in a window.
Highlighted words or phrases indicate that additional information is available.
Certain words and phrases are highlighted in a different color from the
surrounding text. These are called hypertext terms.
If you are using a mouse, double-click on the highlighted word. If you are
using a keyboard, press the Tab key to move to the highlighted word, and then
press the Enter key. Additional information then appears in a window.
ΓòÉΓòÉΓòÉ 1.5. How to Use Action Bar Choices ΓòÉΓòÉΓòÉ
Several choices are available for managing the information presented in this
document. There are three menus on the action bar: the Services menu, the
Options menu, and the Help menu.
The actions that are selectable from the Services menu operate on the active
window currently displayed on the screen. These actions include the following:
Placing Bookmarks
You can set a placeholder so you can retrieve information of interest to
you.
Searching for Information
You can find occurrences of a word or phrase in the current topic,
selected topics, or all topics.
Printing Information
You can print one or more topics. You can also print a set of topics by
first marking the topics in the Contents list.
Copying Information to a File
You can copy a topic that you are viewing to the System Clipboard or to a
file that you can edit. This method is particularly useful for copying
syntax definitions and program samples into the application that you are
developing.
Using the actions that are selectable from the Options menu, you can change
the way your Contents list is displayed. To expand the Contents and show all
levels for all topics, choose Expand all from the Options pull-down. You can
also press the Ctrl and * keys together.
The actions that are selectable from the Help menu allow you to select
different types of help information.
For information about any of the menu choices, highlight the choice in the
menu and press F1.
ΓòÉΓòÉΓòÉ 1.5.1. Placing Bookmarks ΓòÉΓòÉΓòÉ
When you place a bookmark on a topic, it is added to a list of bookmarks you
have previously set. You can view the list, and you can remove one or all
bookmarks from the list. If you have not set any bookmarks, the list is empty.
To set a bookmark, do the following:
1. Select a topic from the Contents.
2. When that topic appears, select the Bookmark option from the Services
menu.
3. If you want to change the name used for the bookmark, type the new name
in the field.
4. Click on the Place radio button (or press the Up or Down Arrow key to
select it).
5. Click on OK (or select it and press Enter). The bookmark is then added to
the bookmark list.
ΓòÉΓòÉΓòÉ 1.5.2. Searching for Information ΓòÉΓòÉΓòÉ
You can specify a word or phrase to be searched. You can also limit the search
to a set of topics by first marking the topics in the Contents list.
To search for a word or phrase in all topics, do the following:
1. Select the Search option from the Services menu.
2. Type the word or words to be searched for.
3. Click on All sections (or press the Up or Down Arrow keys to select it).
4. Click on Search (or select it and press Enter) to begin the search.
5. The list of topics where the word or phrase appears is displayed.
ΓòÉΓòÉΓòÉ 1.5.3. Printing Information ΓòÉΓòÉΓòÉ
You can print one or more topics, the index, or the table of contents. Make
sure that your printer is connected to the serial port, configured correctly,
and ready for input. To print:
1. Select Print from the Services pull-down.
2. Select what you want to print. Note that the This section and Marked
sections choices are only available if you are viewing a topic or if you
have marked topics, respectively. To mark topics in the table of
contents, press the Ctrl key and click on the topics, or use the arrow
keys.
3. Select Print to print what you've chosen on your printer.
ΓòÉΓòÉΓòÉ 1.5.4. Copying Information to a File ΓòÉΓòÉΓòÉ
You can copy a topic that you are viewing in two ways:
Copy copies the topic that you are viewing into the System Clipboard. If
you are using a Presentation Manager (PM) editor (for example, the
Enhanced Editor) that copies or cuts (or both) to the System Clipboard,
and pastes to the System Clipboard, you can easily add the copied
information to your program source module.
Copy to file copies the topic that you are viewing into a temporary file
named TEXT.TMP. You can later edit that file by using any editor.
TEXT.TMP is placed in the directory where your viewable document resides.
To copy a topic, do the following:
1. Expand the Contents list and select a topic.
2. When the topic appears, select Copy to file from the Services menu.
3. The system puts the text pertaining to that topic into the temporary file
TEXT.TMP.
ΓòÉΓòÉΓòÉ 1.6. How to Cut and Paste Examples ΓòÉΓòÉΓòÉ
You can copy examples (or information) from this FAQ to compile, link, and run
them, or to paste them into your own code.
To copy an example or information:
1. Make the topic you want to copy the active window.
2. From the Services menu, select Copy to file. The text in that topic is
placed in the temporary file TEXT.TMP, in the same directory as this
reference.
3. You can then modify or use TEXT.TMP as you want.
ΓòÉΓòÉΓòÉ 1.7. Other Information You Might Find Helpful ΓòÉΓòÉΓòÉ
This product provides a number of online guides and references that we hope
you'll find helpful as you develop applications. This information includes
User's Guides, References, and How Do I help that gives you specific
instructions for performing common tasks. You can get to this online
information from the Information folder inside the main product folder. You
can also get to it from the Help menu in any of the components of the product.
ΓòÉΓòÉΓòÉ 1.8. Communicating Your Comments to IBM ΓòÉΓòÉΓòÉ
If there is something you like, or dislike, about this book, please let us
know. You can use one of the methods listed below to send your comments to
IBM. Please be sure to include the complete title of the publication that you
are commenting on.
The comments you send should only pertain to the information in this document
and its presentation. To request additional publications or to ask questions
or make comments about the functions of IBM products or systems, you should
talk to your IBM representative or you authorized IBM remarketer.
When you send comments to IBM, you grant IBM a nonexclusive right to use or
distribute your comments in any way it believes appropriate without incurring
any obligation to you.
You can send your comments to IBM in the following ways:
By mail to the following address:
IBM Canada Ltd. Laboratory
Information Development
2G/345/1150/TOR
1150 EGLINTON AVENUE EAST
NORTH YORK, ONTARIO
CANADA M3C 1H7
By FAX to the following number:
- United States and Canada: (416) 448-6161
- Other countries (+1) 416-448-6161
By electronic mail to one of the following IDs. Be sure to include your
entire network address if you wish to get a reply.
- Internet: torrcf@vnet.ibm.com
- IBMLink: toribm(torrcf)
- IBM/PROFS: torolab4(torrcf)
- IBMMAIL: ibmmail(caibmwt9)
ΓòÉΓòÉΓòÉ 2. General Questions about VisualAge C++ ΓòÉΓòÉΓòÉ
This section answers some general questions about VisualAge C++.
How Do I Get Code Fixes for VisualAge C++?
What Operating Systems Does It Support?
What Are the Minimum Hardware Requirements?
How Do I Rebuild My VisualAge C++ Desktop Folders?
Can I Get the Class Library Source Code?
What Documentation Exists for the User Interface Classes?
Can I Mix Object Files from Different Compilers?
What Are the Library Naming Conventions?
What Does Mangling Mean?
ΓòÉΓòÉΓòÉ 2.1. How Do I Get Code Fixes for VisualAge C++? ΓòÉΓòÉΓòÉ
Question:
I think I have found a problem with the compiler or one of the tools. How do I
get a fix for this problem?
Answer:
Fixes for problems with VisualAge C++ components are provided in corrective
service diskettes (CSDs).
Note: CSDs are not really diskettes. However, you can create diskettes from
them. You can also apply the fixes in other ways.
CSDs are available from CompuServe (GO OS2DF1), from the IBM PC Company
Bulletin Board System (919-517-0001), and from
ftp://software.watson.ibm.com/pub/cset. CSDs are cumulative; you only need to
apply the most recent one to get all the updates that have been made.
If you apply the CSDs and your problem persists, report your problem to
VisualAge C++ Service and Support. For instructions on how to report problems,
see What If I Still Have Questions?.
ΓòÉΓòÉΓòÉ 2.2. What Operating Systems Does It Support? ΓòÉΓòÉΓòÉ
Question:
Can VisualAge C++ generate code for DOS or Windows? What other operating
systems does it support?
Answer:
VisualAge C++ generates only 32-bit code for OS/2 2.11 and higher, including
the OS/2 Warp family. It does not generate DOS, Windows, or 16-bit code.
VisualAge C++ runs only under OS/2 2.11 and higher.
C Set ++ and its class libraries are also available for the AIX and Solaris**
operating systems.
ΓòÉΓòÉΓòÉ 2.3. What Are the Minimum Hardware Requirements? ΓòÉΓòÉΓòÉ
Question:
What are the minimum hardware requirements for VisualAge C++?
Answer:
The minimum requirements are:
Processor
386; 486 is recommended. If you have a 386 processor, a 387 math
coprocessor is also recommended.
Memory (RAM)
8M for C development (12M recommended)
12M for C++ development (16M recommended)
16M for visual C++ development (24M recommended)
Note: In some cases, you may be able to run VisualAge C++ with less RAM
than stated, but the performance will suffer.
Disk Space
Approximately 170MB for a complete installation (110MB for the tools,
60MB for sample programs and documentation). When you install
VisualAge C++, the installation program tells you how much space is
required for individual components.
Swap Space
10MB for C development
30MB for C++ development
ΓòÉΓòÉΓòÉ 2.4. How Do I Rebuild My VisualAge C++ Desktop Folders? ΓòÉΓòÉΓòÉ
Question:
How can I rebuild my desktop icons for VisualAge C++ without reinstalling?
Answer:
Run the CPPDESK command from the main VisualAge C++ directory (IBMCPP, if you
used the defaults).
ΓòÉΓòÉΓòÉ 2.5. Can I Get the Class Library Source Code? ΓòÉΓòÉΓòÉ
Question:
Can I get the source code for the class libraries? How?
Answer:
The source code for the IBM Open Class Library is available as a separate
product. You can order it the same way you ordered VisualAge C++. Its part
number (order number) is 30H1667. Corrective service is available for the
source code as well as for VisualAge C++, so you can maintain the source and
executable files at the same level. (For information on getting corrective
service, see How Do I Get Code Fixes for VisualAge C++?.)
ΓòÉΓòÉΓòÉ 2.6. What Documentation Exists for the User Interface Classes? ΓòÉΓòÉΓòÉ
Question:
What documentation is there for the User Interface classes?
Answer:
The Open Class Library User's Guide and Open Class Library Reference that ship
with VisualAge C++ document the entire IBM Open Class Library, including the
User Interface classes. You can find these books in the VisualAge C++
Information folder.
The most complete separate publication is OS/2 C++ Class Library: Power GUI
Programming with C Set ++, by Kevin Leong, William Law, Robert Love, Hiroshi
Tsuji, and Bruce Olson. The publisher is John Wiley and Sons, Inc., and the
ISBN number is 0-471-13117-2. (Note that until recently, the publisher was Van
Nostrand Reinhold and the ISBN number 0-442-01795-2.) The book comes with a
diskette full of samples. The authors are architects and leading developers of
the User Interface class library.
Note: This book was written based on Version 2.1 of the class library. It does
not include information about new classes and features that have been added to
VisualAge C++ Version 3.0.
Some technical articles have also been published in "OS/2 Developer", including
an article on INoteBook in the January/February 1994 edition, and two articles
that discuss creating new control classes in the September/October 1994
edition. These articles are also based on Version 2.1.
IBM also offers educational courses for VisualAge C++ and the User Interface
class library. For more information about current course offerings, in North
America, contact IBM Education and Training at 1-800-IBM-TEAC (1-800-426-8322).
Outside of North America, contact your local IBM office or supplier.
Note: The 1-800 number for Canada is being changed to 1-800-IBM-TEAC. If you
call from Canada and this number is not yet in service, call the previous
number, 1-800-661-2131.
ΓòÉΓòÉΓòÉ 2.7. Can I Mix Object Files from Different Compilers? ΓòÉΓòÉΓòÉ
Question:
Can I mix object (.OBJ) files compiled with an earlier version of C Set ++ with
VisualAge C++ .OBJ files? What about .OBJ files from other compilers, such as
Borland?
Answer:
You can link .OBJ files created with C Set ++ Version 2.0 or 2.1 with
VisualAge C++ .OBJ files. (Note that this does not apply to .OBJ files created
with a beta version of VisualAge C++.)
You cannot link .OBJ files created using different compilers. You must
recompile your source files using the same compiler.
However, you can call between executable modules (EXEs and DLLs) compiled with
different compilers or different versions of a compiler, providing:
The modules do not share a runtime environment.
The calling conventions match.
Only C or extern "C" functions are called.
For example, if you have a VisualAge C++ executable and a Borland DLL, and the
above conditions are met, you can then call code from the Borland DLL, import
and export data from it, and so on.
You cannot directly call C++ functions compiled with a different compiler
because each compiler makes different assumptions about runtime environment
and uses different algorithms for mangling C++ names. To call a C++ function,
you must declare it as extern "C".
If you are linking with C Set ++ V2.x object files that use templates, you
must compile your VisualAge C++ source files using the /Gk option and link
using the /OLDCPP option to ensure the templates resolve correctly. (If you
use icc to invoke the linker, specify /Gk /Tdp to pass the /OLDCPP linker
option.) You must specify these options because template resolution methods
changed for VisualAge C++.
Note: You can mix C and C++ object modules from the same compiler and use a
common runtime DLL.
ΓòÉΓòÉΓòÉ 2.8. What Are the Library Naming Conventions? ΓòÉΓòÉΓòÉ
Question:
What are the naming conventions used for the static and dynamic runtime and
class libraries?
Answer:
The naming conventions for the libraries have changed for VisualAge C++ Version
3.0. They now indicate the product version and platform, as well as a new
product prefix.
You do not have to specify libraries at link time. The compiler imbeds
information in your .OBJ files about the runtime and class libraries to link
with, based on the compiler options you specify and the #pragma library
directives in the header files you include.
The new convention for the C runtime libraries (which also include the I/O
Stream class library) is:
CPPpivvt
where:
p Is the platform or operating system.
i Is the library identifier.
vv Is the version number.
t Is the type of library
The resulting library names are:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Character Significance
Position
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
1-3 4 5 6-7 8
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
CPP Product prefix
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
O OS/2 platform
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
S Single-thread environment
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
M Multithread environment
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
N No runtime environment (subsystem)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
30 Version number (3.0)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
I Import library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
O Object library (contains initialization routines)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Statically bound library (no eighth letter)
The new convention for the class libraries, as well as for the Performance
Analyzer libraries, .OBJ, and device driver, is:
CPPpiivt
where:
p Is the platform or operating system.
ii Is the library identifier.
v Is the version number.
t Is the type of library.
The resulting library, .OBJ, and device driver names are:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Character Significance
Position
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
1-3 4 5-6 7 8
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
CPP Product prefix
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
O OS/2 platform
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
DI Data Access IDL library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
DS Data Access static SQL library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OB Open Class Base library (Collection, Data Types)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OC Open Class library (single import library)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OD Open Class DDE library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OM Open Class Multimedia library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OR Open Class resource DLLs
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OU Open Class User Interface base library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OV Open Class Visual library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OX Complex library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OY Complex multithread library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
PA Performance Analyzer
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
SQ Data Access resource DLLs
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
TR Integration DLL
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Vn Open Class Visual sample library n
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
3 Version number 3.0
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
I Import library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
O Object library (for building import libraries)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Statically bound library (no eighth letter)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
U U.S. English version of resource library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
J Japanese version of resource library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
K Korean version of resource library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
T Taiwanese version of resource library
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
P Simplified Chinese version of resource library
ΓòÉΓòÉΓòÉ 2.9. What Does Mangling Mean? ΓòÉΓòÉΓòÉ
Question:
I have seen a number of references to mangling in the C++ information. What
does it mean?
Answer:
When a C++ compiler compiles a program, it encodes all class, member, and
function names, as well as certain other identifiers, to include type and
scoping information. This is called mangling. Different compilers use different
mangling schemes.
The linker uses the encoded or mangled name to ensure type-safe linkage. These
mangled names are used in the object files and in the final executable file.
Tools or code that references identifiers in these files must use the mangled
names, not the original names used in the source code. To decode or demangle
the names for VisualAge C++, you can use the functions defined in <demangle.h>
or the CPPFILT utility. For more information about demangling, see "Demangling
(Decoding) C++ Function Names" in the Programming Guide. For information about
CPPFILT, see the User's Guide.
ΓòÉΓòÉΓòÉ 3. Using Documentation and Help ΓòÉΓòÉΓòÉ
This section answers questions about the online and hardcopy information and
the online help:
How Do I Close the How Do I Panel?
Where Is the Chapter on Compiler Options?
ΓòÉΓòÉΓòÉ 3.1. How Do I Close the How Do I Panel? ΓòÉΓòÉΓòÉ
Question:
How do I close the How Do I panel? When I click on the system icon, there is
no Close choice.
Answer:
To close the How Do I panel, press F3.
You can also click mouse button 2 on the window to bring up a context menu for
it. From the context menu, select Exit.
The other help functions (such as Search and Print) are also available from
this menu.
ΓòÉΓòÉΓòÉ 3.2. Where Is the Chapter on Compiler Options? ΓòÉΓòÉΓòÉ
Question:
There used to be a chapter on compiler options in the Programming Guide, but I
can't find it now. Where is it?
Answer:
This chapter has been moved to the User's Guide, along with other information
about how to use the compiler and VisualAge C++ tools.
ΓòÉΓòÉΓòÉ 4. Using WorkFrame ΓòÉΓòÉΓòÉ
This section provides answers to commonly-asked questions about the
VisualAge C++ integrated development environment, WorkFrame.
How Do I Create a WorkFrame Project?
How Do I Create a New Source File in a Project?
How Do I Change What a Double-Click Does in My Project?
How Can I Share Projects over a LAN?
How Do I Copy a Project or Profile to Diskette?
How Do I Set the Default Action for a Class?
Why Doesn't Double-Clicking on Error Messages Work?
Can I Inherit Environments from Multiple Projects?
Why Is My Project's Inherited Environment Not What I Expect?
Where Are Options for Inherited Actions Stored?
Where Are My Migrated Profiles?
ΓòÉΓòÉΓòÉ 4.1. How Do I Create a WorkFrame Project? ΓòÉΓòÉΓòÉ
Question:
How do I create a WorkFrame project?
Answer:
The easiest way to create a project is to use Project Smarts or the WorkFrame
Project template in the OS/2 Templates folder.
If you already have files that you want to put in a project, or if you are
familiar with WorkFrame and want to build a project from scratch, use the
WorkFrame Project template. Open the Templates folder, select the WorkFrame
Project template, and drag it onto your desktop.
If you are not familiar with WorkFrame, or if you're unsure how to set up a
certain type of project (a PM application, for example), use Project Smarts.
Project Smarts is a catalog of project skeletons for common types of
applications. Double-click on the Project Smarts object in the VisualAge C++
folder to display the catalog. Select the type of project you want to create,
then select the Create button.
ΓòÉΓòÉΓòÉ 4.2. How Do I Create a New Source File in a Project? ΓòÉΓòÉΓòÉ
Question:
I have a project, but I want to add a new source file to it. How do I do that?
Answer:
Drag a data file template (from the Templates folder) onto the project. You
can also create a project-scoped EDIT action in the Actions Profile with no
options, so that it brings up the editor with no file loaded.
You can also use the command line to copy a file or invoke the editor on a new
file in the directory pointed to by the project.
ΓòÉΓòÉΓòÉ 4.3. How Do I Change What a Double-Click Does in My Project? ΓòÉΓòÉΓòÉ
Question:
How do I change the default action associated with double-clicking on files in
my project?
Answer:
To change the default double-click action, you need to change the priority of
the project's actions in the Tools Setup.
The priority is a numeric value from 0 to 99, with 99 being the highest
priority, specified on the Support page of the action's Settings notebook.
Actions in the list of actions are sorted in order of priority; the higher it
appears in the list, the higher its priority.
When you double-click on a file, WorkFrame identifies all actions that match
that file name, and performs the action with the highest priority. Only actions
that are valid for that type of source file are considered. For example, if
you set the VisualAge C++ Compiler action so that the only valid source files
are .cpp files, the Compiler will never be invoked by double-clicking on any
other type of file, regardless of the Compiler action's priority.
A file's default action is always listed first on its pop-up menu. (Pop-up
menu items are sorted by priority.)
To change the default action for a file, select Change from the action's pop-up
menu to display its Settings notebook, and then change the priority value on
the Support page. Make sure the action you want to use is valid for the type of
file.
Note: If a file or object has no WorkFrame actions associated with it, or if
it a WorkFrame project, double-clicking on it performs the default Workplace
Shell Open action.
ΓòÉΓòÉΓòÉ 4.4. How Can I Share Projects over a LAN? ΓòÉΓòÉΓòÉ
Question:
How can I share my WorkFrame projects with others over a LAN?
Answer:
You can easily share projects over a LAN by locating the project file itself on
the LAN, and then shadowing it to the client desktops.
Your project source files can reside on the LAN, and you can copy project
WorkPlace Shell objects over the LAN (by dragging the project onto a remote
Drives folder and then dragging it out again onto the target machine). Ensure
that your target machine is set up similar to your original machine (for
example, your source is in the same location; inherited projects, if any, also
exist; the executable files are present; and so on). If you are sharing code
over the LAN, you may find a source-control product such as CMVC for OS/2
helpful.
ΓòÉΓòÉΓòÉ 4.5. How Do I Copy a Project or Profile to Diskette? ΓòÉΓòÉΓòÉ
Question:
I want to move my projects and profiles to a second machine that is not
connected to the LAN. How do I copy my projects and profiles to a diskette,
and then to the new machine?
Answer:
There are two methods for copying projects and profiles to diskette:
1. Drag the project or profile icon from your desktop and drop in onto the
icon for your diskette drive (make sure you have a diskette in the
drive). On the target machine, insert the diskette, double-click on the
icon for the diskette drive, and drag the project or profile icon to the
desktop.
2. Compress the project or profile file using a compression program that
preserves extended file attributes (such as the public domain zip and
unzip programs). Project files and profiles are found in the \DESKTOP
directory on your boot drive. Copy the compressed files onto the
diskette, and then uncompress the files under the \DESKTOP directory on
the target machine.
ΓòÉΓòÉΓòÉ 4.6. How Do I Set the Default Action for a Class? ΓòÉΓòÉΓòÉ
Question:
How do I set the default action for a class (such as COMPILE)?
Answer:
The default action for a class is simply the action that has the highest
priority within that class.
The priority is a numeric value from 0 to 99, with 99 being the highest
priority, specified on the Support page of the action's Settings notebook.
Actions in the list of actions are sorted in order of priority; the higher it
appears in the list, the higher its priority.
To make an action the default, change the priority value in its Settings
notebook so that the value is higher than the other actions in that class. (To
display the Settings notebook, select Change from the action's pop-up menu.)
Note that the default action for a class also depends on the type of file that
it is invoked on. For example, suppose the Resource Compile action has the
highest priority among COMPILE actions. Resource Compile is only valid for .rc
files. If you invoke COMPILE on a .cpp file, WorkFrame skips the Resource
Compile action because it is not valid for the type of file. WorkFrame
performs the action with the highest priority that is valid for a .cpp file.
In most cases, the default action for a class is not important. However, it is
important for the EDIT class. When you double-click on error messages in the
monitor box, or invoke the editor from one of the other tools, the default Edit
action (and default editor) is used.
ΓòÉΓòÉΓòÉ 4.7. Why Doesn't Double-Clicking on Error Messages Work? ΓòÉΓòÉΓòÉ
Question:
I thought that double-clicking on an error in the monitor window was supposed
to launch the editor and load the source file that has the error. Why doesn't
this work for me?
Answer:
Make sure the error message was generated for a source file. For error
messages generated by tools like the linker, double-clicking on the
message does not work because you cannot edit the object file for which
the message was generated.
If you added or changed the action that generated the message, and it
uses the WorkFrame default action support DLL, ensure the error template
is specified correctly.
If the error message uses unqualified file names, the editor may not be
able to load the file. If this is the case, go to your Project view and
edit the file from there.
If the messages were generated by the Make action, and the make file you
used was not generated by WorkFrame (or you edited the file), the make
file may not contain information the WorkFrame needs to determine what
tool should parse the errors. WorkFrame puts special tags before each
OS/2 command in the make file to indicate the tool to call.
If you use the Build action instead of Make, this problem does not occur.
If you don't want to use Build, either regenerate your make file using
WorkFrame, or add the tags to your own make file. The tags have the
format:
@echo WF::class::action
where class is the action class (such as COMPILE), and action is the
action name (such as VisualAge C++).
ΓòÉΓòÉΓòÉ 4.8. Can I Inherit Environments from Multiple Projects? ΓòÉΓòÉΓòÉ
Question:
Can I inherit environments from multiple projects?
Answer:
Yes. Specify the list of projects in the Inheritance page of the project's
Settings notebook.
ΓòÉΓòÉΓòÉ 4.9. Why Is My Project's Inherited Environment Not What I Expect? ΓòÉΓòÉΓòÉ
Question:
My project inherits from more than one project. One of the actions, variables,
or types is not what I expected. Why?
Answer:
When you inherit from multiple projects, conflicts can occur between the
different environments. The rules that WorkFrame uses to resolve these
conflicts are described in the WorkFrame section of the User's Guide.
ΓòÉΓòÉΓòÉ 4.10. Where Are Options for Inherited Actions Stored? ΓòÉΓòÉΓòÉ
Question:
When I inherit an action from another project's environment, are the options
copied from the base action stored locally with my new project? Or do they
remain with the project where the action was originally defined?
Answer:
You have a choice. By default, the options remain with the base project, but
you can also copy the options and store them locally. You can change the
options of an inherited action, but then you will be changing the options for
other projects that also inherit the action. If the options are stored
locally, you can decide to use the inherited options instead by deleting the
local options. (Select Options->Delete from the action's pop-up menu.)
ΓòÉΓòÉΓòÉ 4.11. Where Are My Migrated Profiles? ΓòÉΓòÉΓòÉ
Question:
I just migrated my projects and profiles from WorkFrame/2 V2.1. I found the new
projects, but I cannot find the profiles. Did the migration for the profiles
fail?
Answer:
In VisualAge C++ V3.0, WorkFrame projects and profiles are merged. Your
migrated profiles have been merged into your migrated projects.
ΓòÉΓòÉΓòÉ 5. Creating Applications with the Visual Builder ΓòÉΓòÉΓòÉ
This section answers questions you may have about using the Visual Builder to
construct parts and applications.
How Can I Determine Which Connections Are Executed?
How Can I Tell What Parameters an Action Can Take?
How Do I Support Different Display Resolutions?
Do I Have to Hardcode Limits for Fields?
Why Are My Container Columns Invisible?
Why Can't I Select Parts in the Group Box?
How Should I Update a Composite Part?
Why Can't I Tear Off a Nonvisual Part's Attribute?
Why Doesn't My Drop-Down Combo Box Drop Down?
Why Does My Part Get Compiler Errors?
Why Does My Part Get Unresolved External Link Errors?
ΓòÉΓòÉΓòÉ 5.1. How Can I Determine Which Connections Are Executed? ΓòÉΓòÉΓòÉ
Question:
My application doesn't run as I expected. Is there a way to determine which
connections are being executed?
Answer:
Yes. The Visual Builder generates trace macros in its connection classes to
indicate when a connection has been triggered. To view this information:
1. When you compile the generated source code for your parts, define the
IC_TRACE_DEVELOP macro.
2. Enable tracing for the class libraries by entering
SET ICLUI TRACE=ON
(You could also set this variable in your CONFIG.SYS file.)
3. Indicate where the trace information should be sent by setting the ICLUI
TRACETO environment variable. For example:
SET ICLUI TRACETO=STDERR
sends the information to stderr, which you can then redirect to a file.
For more details on tracing, see the ITrace class information in the Open
Class Library Reference.
Once you have enabled tracing, look for the following possible problems:
Initializing attribute-to-attribute connections can execute other
connections that are dependent on the target attribute.
A connection involving an attribute as the source might not have been
executed because the attribute does not have an event identification
defined for it.
A connection involving an attribute might not have been executed because
the attribute-changed event happens only when the attribute's value
changes. For example, setting the value of a Boolean attribute to true
when the current value is already true might not execute the
attribute-changed event. Another example is when the attribute is a
pointer to an object and the pointer does not change but the contents of
the object does. If your application must execute an event when the
attribute's set member function is called, add a notification event.
If your application is getting an old attribute value instead of a new
one, the attribute's set member function might be executing its
attribute-changed event before the value actually changes. Make sure you
update the attribute's value before you signal the attribute-changed
event.
Whenever an action executes an event, the event happens before the
actionResult value is set for the action. For example, Object Factory
parts have a new action that instantiates an object of the type defined
for the factory part. The new action starts an event called newEvent
before the result of new is returned, so actionResult still contains the
old value.
ΓòÉΓòÉΓòÉ 5.2. How Can I Tell What Parameters an Action Can Take? ΓòÉΓòÉΓòÉ
Question:
I have an incomplete connection. How can I tell what parameters an action
takes and what default values the parameters can be initialized to?
Answer:
Select the target part that the action is defined for. From its context menu,
select Browse feature implementations. The Browse feature implementation window
shows the full signature of the action, including its return type. You can then
see what parameters an action supports, the type of each parameter, and any
default values.
ΓòÉΓòÉΓòÉ 5.3. How Do I Support Different Display Resolutions? ΓòÉΓòÉΓòÉ
Question:
How should I build my application views to ensure they display correctly on
different display resolutions and monitors (VGA, SVGA, and so on)?
Answer:
Build your views using a multicell canvas (IMultiCellCanvas) as the client
instead of a canvas (ICanvas).
ΓòÉΓòÉΓòÉ 5.4. Do I Have to Hardcode Limits for Fields? ΓòÉΓòÉΓòÉ
Question:
I initialize many parts in my views through the parts' settings editors. How
can I avoid hardcoding values for fields, such as the limit field for the entry
field part?
Answer:
Create a separate file for your application and use #define directives to
define macros for your field lengths. For example, for an entry field for
names, you might define a macro NAME_LENGTH to 50. You would then specify
#NAME_LENGTH for the entry field's Limit field.
To ensure that your view will compile, add the name of the file that contains
the #define directives to the Required include files field in the Class Editor.
ΓòÉΓòÉΓòÉ 5.5. Why Are My Container Columns Invisible? ΓòÉΓòÉΓòÉ
Question:
Some of the container columns that I dropped on a container aren't visible.
Why?
Answer:
When you build a container using the Composition Editor, the Visual Builder
shows only those columns that fit within the container. To access the rest of
the columns, either resize the container to a larger size, or select Tabbing
and Depth Order from the context menu of the container. From the Tabbing and
Depth Order window, you can open the settings notebook of any of the container
columns listed by double-clicking on their names. You can delete a column by
selecting Delete from the context menu of a column.
Also, if you define several container columns and then change the view type to
something other than showDetailsView, your columns may become invisible. You
can always enable your users to switch the view type of a container at run time
(for example, from a menu bar).
ΓòÉΓòÉΓòÉ 5.6. Why Can't I Select Parts in the Group Box? ΓòÉΓòÉΓòÉ
Question:
I dropped a group box or outline box and sized it so that it contains other
visual parts that I added to my view. Now I can't select the visual parts that
the group box or outline box contains. Why?
Answer:
The visual parts inside the group or outline box are siblings of the box, not
children of it. Because you created the box after the visual parts it contains,
the depth order of the box is lower than those of the contained visual parts.
To change the depth order, select Tabbing and Depth Order from the context menu
of the parent of these parts (that is, the canvas that contains them). Then
select and drag the group box or outline box and drop it so that it appears
before all of the visual parts you want it to contain.
To avoid this problem, create the group box or outline box first and then place
the other parts on top of it.
ΓòÉΓòÉΓòÉ 5.7. How Should I Update a Composite Part? ΓòÉΓòÉΓòÉ
Question
I am editing a visual part, and need to update one of the composite parts it
contains. What is the easiest way to update the composite part?
Answer:
1. Edit the part you want to change. (You can leave the first edit session
open.)
2. Update the composite part, save it, and close the second edit session.
Note that the changes will not appear in your first edit session until
you close and reopen the session.
ΓòÉΓòÉΓòÉ 5.8. Why Can't I Tear Off a Nonvisual Part's Attribute? ΓòÉΓòÉΓòÉ
Question:
I created a nonvisual part with an attribute that is a pointer to a collection
object. I want to tear off this attribute to make connections to some of its
actions, but I can't. Why not?
Answer:
Collections are implemented using C++ template classes. When you tear off an
attribute, Visual Builder creates a variable part and sets it to the type of
the torn-off attribute. However, variables that represent template-based
classes are not currently supported.
To avoid the need to tear off attributes, implement actions to work with the
collection attribute directly in your nonvisual part.
ΓòÉΓòÉΓòÉ 5.9. Why Doesn't My Drop-Down Combo Box Drop Down? ΓòÉΓòÉΓòÉ
Question:
Why doesn't my drop-down combo box drop down?
Answer:
Make sure a default height is specified on the Size/Position settings page.
You must set the height to a value higher than 0.
ΓòÉΓòÉΓòÉ 5.10. Why Does My Part Get Compiler Errors? ΓòÉΓòÉΓòÉ
Question:
I constructed my application using the Composition Editor, but when I try to
compile it, the compiler generates errors. Shouldn't any constructed part
compile without error?
Answer:
The Composition Editor does not prevent you from making connections that will
not compile correctly. You must ensure you match types correctly on
attribute-to-attribute connections and parameter connections. The easiest way
to avoid incompatible-type errors is to browse feature implementations using
the Composition Editor's contextual menu.
ΓòÉΓòÉΓòÉ 5.11. Why Does My Part Get Unresolved External Link Errors? ΓòÉΓòÉΓòÉ
Question:
When I compile and link my part, the linker generates unresolved external
errors. Why?
Answer:
This could be caused by one of the following:
Visual Builder uses template classes to implement variable parts,
collections, collection-view list boxes, and collection-view combo boxes.
When you compile, information required to resolve the templates is put
into the TEMPINC subdirectory (under the directory where your part code
resides). If you made changes to any template-based parts, delete the
contents of TEMPINC before you recompile to ensure that you are not using
the old template information.
If you compiled your nonvisual parts separately to create a DLL, you must
link the .LIB file for that DLL into your application to resolve
references to the nonvisual parts. You can either:
- In the Class Editor, add the .LIB file name for each nonvisual part
contained in the DLL.
- Put a #pragma library directive in the header file for your
nonvisual parts. This directive tells the compiler and linker to
link in the library specified. #pragma library is described in the
Language Reference.
ΓòÉΓòÉΓòÉ 6. Editing with the VisualAge C++ Editor ΓòÉΓòÉΓòÉ
This section answers questions about how to use the VisualAge C++ Editor.
How Can I Make the Editor Behave Like My Favorite Editor?
What Is the Gray Area Shown at the Top of My File?
Why Do I Have Multiple Copies of the Error Log?
Can I Extract the Text in a Marked Block?
How Do I Put the Contents of a Line in a Macro?
How Do I Issue an OS/2 Command from a Macro?
How Do I Debug a REXX Macro?
How Do I Unload the Editor from Memory?
How Can I Get File or Quit to Invoke My Macro?
ΓòÉΓòÉΓòÉ 6.1. How Can I Make the Editor Behave Like My Favorite Editor? ΓòÉΓòÉΓòÉ
Question:
How can I make the Editor behave like my favourite editor and other editors on
the market (such as Brief)?.
Answer:
In the Options menu, the Key behavior choice cascades to a menu of commonly
used editors. Select from this menu to make the Editor behave like the selected
editor. This affects only the current document in the current edit session.
To save the behavior for all documents across sessions, select Save key
behavior from the Key behavior cascade. To customize the behavior of any subset
of keys, use the Customize choice from the Options menu.
ΓòÉΓòÉΓòÉ 6.2. What Is the Gray Area Shown at the Top of My File? ΓòÉΓòÉΓòÉ
Question:
What is the gray area shown at the top of my file, and why is it a different
size for different files?
Answer:
An edit window is created based on the size and position of the last window
size and position (even from another session). The area in which the file is
displayed is fixed until you change it. If the file loaded into the window is
not large enough to fill the edit area, the gray area fills the remaining
space. As the file size increases, the gray area diminishes. When the file
fills the window and scrolling is required, the gray area disappears.
ΓòÉΓòÉΓòÉ 6.3. Why Do I Have Multiple Copies of the Error Log? ΓòÉΓòÉΓòÉ
Question:
I start the editor from the command line. In every directory where I start it,
it creates a new error log file. Why? How do I specify one location for this
file?
Answer:
The editor uses the environment variable TMPDIR to determine where to create
the error log. Make sure you have specified a valid drive and directory for
this variable. If you want to specify only a drive, you must follow it with a
backslash, for example:
SET TMPDIR=f:/
ΓòÉΓòÉΓòÉ 6.4. Can I Extract the Text in a Marked Block? ΓòÉΓòÉΓòÉ
Question:
I have a block of marked text. Can I extract or query the text in the block?
Answer:
There is no direct way to extract or query the text marked by the current
block. However, you can write a macro to extract the text. You need to:
1. Determine what document has the selected block of text (BLOCKDOC).
2. Determine the BLOCKTYPE.
3. Determine what you need to extract, based on the BLOCKTYPE. For example,
for a RECTANGLE:
a. Find the columns spanned by the rectangle (BLOCKSTART and BLOCKEND).
b. Determine how many elements the block crosses (BLOCKLENGTH).
4. Position the cursor on the first included element (BLOCK FIND).
5. Extract the content of the element.
6. Throw away the characters not included.
7. Move to the next element and extract its content.
8. Repeat the above two steps (6 and 7) until finished.
Your macro might contain the following statements:
QUERY BLOCKTYPE
QUERY BLOCKDOC
BLOCK FIND
BLOCK FIND END
QUERY BLOCKSTART
QUERY BLOCKLENGTH
QUERY BLOCKEND
EXTRACT CONTENT
ΓòÉΓòÉΓòÉ 6.5. How Do I Put the Contents of a Line in a Macro? ΓòÉΓòÉΓòÉ
Question:
How do I put the contents of a line or editor variable in a macro?
Answer:
Use the extract command. The command extract content puts the content of the
current line into the REXX variable content. You can also use the command
extract content into x to extract the line's content into the variable x.
ΓòÉΓòÉΓòÉ 6.6. How Do I Issue an OS/2 Command from a Macro? ΓòÉΓòÉΓòÉ
Question:
How do I issue an OS/2 command from a REXX macro?
Answer:
Use the REXX ADDRESS command. For details on how to use this command, see the
REXX Information in the OS/2 Information folder.
ΓòÉΓòÉΓòÉ 6.7. How Do I Debug a REXX Macro? ΓòÉΓòÉΓòÉ
Question:
One of my editor macros fails with an error code. How can I debug it to find
out what's wrong?
Answer:
To debug a REXX macro, use the REXX trace utility and the editor's Macro Log
(from the Window menu). If you put TRACE ALL as the first statement in your
REXX macro, the Macro Log displays every REXX statement executed. If you put
TRACE ?ALL as the first statement, the editor prompts you with the REXX Trace
Read dialog for each statement, in addition to displaying them in the Macro
Log.
ΓòÉΓòÉΓòÉ 6.8. How Do I Unload the Editor from Memory? ΓòÉΓòÉΓòÉ
Question:
I noticed that after I close my editor session, the editor remains loaded in
memory for some time afterwards. Why does this happen, and how can I unload it
from memory?
Answer:
The editor remains in memory so that startup is faster when you edit your next
file. Closing the editor from the OS/2 Window list only closes the document
being edited. To close the editor itself and unload it from memory, use the
command:
lxpm /cm exit
or select Close editor from the Windows menu.
There is also an editor parameter, TIMOUT, that you can query and set from the
command line, from an editor macro, or from a program.
The default setting is five minutes; five minutes after the last edit window is
closed, the editor closes itself. If you set it to 0, the editor closes
immediately after the last edit window is closed, regardless of whether you
select Close Editor or not.
See the Editor Command Reference for more details on setting and querying
parameters.
ΓòÉΓòÉΓòÉ 6.9. How Can I Get File or Quit to Invoke My Macro? ΓòÉΓòÉΓòÉ
Question:
When I save a file or quit out of the editor, I want my own macro to be invoked
first before the editor saves the file or exits. Can I do this?
Answer:
Yes. The easiest way is to define a synonym for these functions. For example,
if your macro is called mymacro.lx:
SYNONYM.QUIT mymacro quit
SYNONUM.QQUIT mymacro qquit
SYNONYM.SAVE mymacro save
(Note that the File action is the Save and Quit actions put together.)
Then in your mymacro.lx, issue the command
'LXN' parm
at the end of your processing.
Alternatively, you could define the following synonym:
SYNONYM.QUIT MULT; mymacro quit ; LXN QUIT
which does not require you to add the extra command to mymacro.lx.
ΓòÉΓòÉΓòÉ 7. Coding in C/C++ ΓòÉΓòÉΓòÉ
This section addresses questions you may have in creating your source files,
including the correct use of operators, functions, and programming techniques.
How Does malloc Allocate Memory?
How Do Signal and Exception Handling Work in DLLs?
How Do I Export C++ Members from a DLL?
Can I Export an Empty Class?
How Do I Use C Objects in C++ Programs?
How Do I Call C++ Functions from C Code?
How Can I Share a Data Segment?
Should I Use Automatic Local Variables or new?
Can I Throw an Exception in One Thread and Catch It in Another?
What Are the Equivalent Calling Conventions in C++?
What Calling Convention Should I Use for Multiple Languages?
Can I Use Library Extensions at the ANSI/ISO Language Level?
Should I Use DosCreateThread or _beginthread?
Can I Use C Functions on a File Opened with DosOpen?
Can I Change the Parent's Environment from a Child Process?
How Can I Perform Port Input/Output?
Can Signals Be Raised Across Processes?
What Should I Call in _DLL_InitTerm?
ΓòÉΓòÉΓòÉ 7.1. How Does malloc Allocate Memory? ΓòÉΓòÉΓòÉ
Question:
How does malloc allocate memory internally, and how much overhead does it
require? Should I use malloc or DosAllocMem?
Answer:
malloc adds 8 bytes to the requested size (16 bytes if you are using debug
memory management), and then rounds the resulting size to the next multiple of
16 bytes. Of this, at most 16 bytes is used by malloc and the other memory
management functions for internal information.
Note: Do not code your program to rely on the underlying implementation of any
function. The implementation could change, which would then cause your program
to fail.
In most cases, there is no benefit to calling DosAllocMem over malloc. In
previous releases of C Set ++, we recommended you call DosAllocMem for large
blocks of memory; however, with the changes to runtime memory management in
this release, malloc is equally efficient with large blocks.
ΓòÉΓòÉΓòÉ 7.2. How Do Signal and Exception Handling Work in DLLs? ΓòÉΓòÉΓòÉ
Question:
How do signal handling and exception handling work in DLLs?
Answer:
You must clearly differentiate between OS/2 exception handlers and C signal
handlers. In VisualAge C++, the #pragma handler directive registers the OS/2
exception handler. The signal function registers a C signal handler. To
correctly generate signals from OS/2 exceptions, VisualAge C++ must have its
own OS/2 exception handler registered.
To automatically register C signal handlers, use the signal function. The
default C exception handler _Exception converts OS/2 exceptions into C signals,
and calls C signal handlers that are registered by signal. _Exception is
automatically registered for the main function; you must explicitly register it
for every DLL entry point using #pragma handler.
You can also use #pragma handler to register your own exception handler for a
function. For example, to register handler as the exception handler for
blivet, specify #pragma(blivet, handler).
Note:
For more information on signal and exception handling, see the Programming
Guide.
ΓòÉΓòÉΓòÉ 7.3. How Do I Export C++ Members from a DLL? ΓòÉΓòÉΓòÉ
Question:
How do I export C++ member functions from a DLL? The _Export keyword is not
valid in the function prototype.
Answer:
Specify the _Export keyword in either the class definition or the function
definition, as in the following example:
class A {
void _Export fun1();
};
void _Export A::fun1() {
return;
}
ΓòÉΓòÉΓòÉ 7.4. Can I Export an Empty Class? ΓòÉΓòÉΓòÉ
Question:
Can I export an empty class and use it somewhere else?
Answer:
You can only export member functions, static data members, and instances of
classes.
ΓòÉΓòÉΓòÉ 7.5. How Do I Use C Objects in C++ Programs? ΓòÉΓòÉΓòÉ
Question:
I am having a problem linking my C++ code with C objects. Why does the linker
say that there is an unresolved external reference to the C objects?
Answer:
You must tell the C++ compiler that an external name uses C naming conventions
by using extern "C" when you declare the function. Otherwise, the C++ compiler
mangles the name. (For an explanation of what "mangles" means, see What Does
Mangling Mean?.) Note that using the keywords for calling conventions (_System,
_Optlink, and so on) in your function definition is equivalent to defining the
function as extern "C".
ΓòÉΓòÉΓòÉ 7.6. How Do I Call C++ Functions from C Code? ΓòÉΓòÉΓòÉ
Question:
I know that I can call C functions from a C++ file using extern "C"
declarations, but how do I call a C++ routine in a .CPP file from a C file?
Answer:
Define the C++ function as extern "C" in your C++ code, and call it from the C
code. Note that C functions compiled with the C compiler cannot directly call
C++ member functions. To get around this, add an extern "C" function in your
C++ code that calls your C++ member function. Then call that extra function
from your C code.
ΓòÉΓòÉΓòÉ 7.7. How Can I Share a Data Segment? ΓòÉΓòÉΓòÉ
Question:
I want multiple copies of my DLL to share a single data segment. How do I do
that?
Answer:
To share a data segment:
1. Use #pragma data_seg to name the data segment you want to share.
2. Specify DATA MULTIPLE NONSHARED in the .DEF file for your DLL.
3. Put a SEGMENTS statement in the .DEF file specifying that the named
segment is SINGLE SHARED.
4. If you need to initialize data structures in the shared segment, you will
need to add to your DLL initialization routine. Remember that this
routine is run for each instance of your DLL, so you will need to ensure
your data structures are only initialized once. For more information
about DLL initialization, see "Building DLLs" in the Programming Guide.
ΓòÉΓòÉΓòÉ 7.8. Should I Use Automatic Local Variables or new? ΓòÉΓòÉΓòÉ
Question:
When should I use automatic local variables, and when should I use the new
operator to create variables?
Answer:
When you can, use automatic variables. Because they are automatically
destroyed when the block in which they were declared ends, you do not have to
delete them and the stack space is returned. For example, a loop counter would
typically be an automatic variable.
However, if you need the variable to remain in existence outside that block,
use new. (Alternatively, you could declare the variable as static or extern.)
Remember that automatic variables use stack space. If you are limited to a
small stack, which is common when you write threads, you may need to use new
and delete for large variables that would typically be automatic.
ΓòÉΓòÉΓòÉ 7.9. Can I Throw an Exception in One Thread and Catch It in Another? ΓòÉΓòÉΓòÉ
Question:
Can I throw an exception in one thread and catch it in another?
Answer:
No. You can only catch exceptions that are thrown from your own thread of
execution. If you try to throw an exception from one thread to another, the
exception will not be caught, and your application will end.
ΓòÉΓòÉΓòÉ 7.10. What Are the Equivalent Calling Conventions in C++? ΓòÉΓòÉΓòÉ
Question:
I know about the VisualAge C++ calling conventions and keywords for C programs.
Are the conventions the same in C++? How do I use them?
Answer:
The calling conventions in C++ are almost the same as in C. The difference is
in the default convention.
By default, C functions have _Optlink linkage; C++ functions have C++ linkage.
C++ linkage behaves like _Optlink, but the two conventions are not equivalent;
C++ linkage also includes name mangling and overloading.
Using the C linkage keywords declares that function as a C function. Be
careful that you don't use linkage keywords for member functions.
You can also use the following qualifiers in your function declarations, listed
with their equivalent keywords:
C++ Qualifier Corresponding C Calling Convention
extern "C" Default C linkage (_Optlink unless you change it to
_System)
extern "C++" _Optlink with name mangling, overloading
extern "SYSTEM" _System
extern "OPTLINK" _Optlink
extern "PASCAL" _Pascal
extern "FAR16 CDECL" _Far16 _Cdecl
extern "FAR16 PASCAL" _Far16 _Pascal
extern "FAR16 FASTCALL" _Far16 _Fastcall
ΓòÉΓòÉΓòÉ 7.11. What Calling Convention Should I Use for Multiple Languages? ΓòÉΓòÉΓòÉ
Question:
I have some functions in a DLL that I want to call from applications written in
other languages like Pascal and COBOL. What calling convention should I use for
these functions?
Answer:
All compilers on OS/2 have to support system linkage (usually referred to in
VisualAge C++ as _System) so they can call OS/2 APIs. If you are creating a
general-purpose DLL, you should code all 32-bit entry points with the _System
calling convention. Other compilers do not support VisualAge C++'s _Optlink
convention.
If you have any 16-bit entry points, you should use the _Far16 _Pascal calling
convention for them.
ΓòÉΓòÉΓòÉ 7.12. Can I Use Library Extensions at the ANSI/ISO Language Level? ΓòÉΓòÉΓòÉ
Question:
I have to compile my program with the language level set to ANSI to set the
__STDC__ macro and ensure ANSI/ISO conformance. However, I also want to use
some of the VisualAge C++ library functions that are not part of the ANSI/ISO
standard, like _beginthread. Can I do this?
Answer:
You cannot use the VisualAge C++ library extensions and the ANSI/ISO language
level together. However, you can define the __EXTENDED__ macro on the compiler
invocation command to include the definitions for the library extensions when
you have the language level set to ANSI/ISO. The compiler will generate a
warning, but should work correctly. Defining the macro this way still provides
ANSI/ISO conformance checking (type checking, for example), but allows your
program to use non-standard library functions.
ΓòÉΓòÉΓòÉ 7.13. Should I Use DosCreateThread or _beginthread? ΓòÉΓòÉΓòÉ
Question:
Can I use VisualAge C++ runtime functions from a thread created by
DosCreateThread rather than by _beginthread?
Answer:
Yes, but there are extra steps you need to take to use DosCreateThread that you
do not need to use _beginthread. To use DosCreateThread to create threads that
can use the VisualAge C++ runtime:
1. Put a #pragma handler directive in your code for the thread function so
that the VisualAge C++ exception handler is registered for the thread.
2. If you are using floating-point math, call _fpreset at the beginning of
the thread function. This call ensures that the floating-point chip is
in the correct state for the thread.
3. Terminate the thread with _endthread so that the thread-specific storage
is freed correctly. VisualAge C++ does not create thread-specific storage
until the first function that requires it is called.
Note: Do not use DosExit to end your threads; it does not correctly
terminate the runtime, which can cause problems when you start another
thread.
When you use _beginthread, you do not have to follow these steps. It performs
the required initialization and termination actions for you.
If you are writing C++ code, you can also use the IThread class from the User
Interface Class Library. See How Do I Start A Thread? for more details.
Note: If you are using the subsystem library (with the /Rn compiler option),
the functions _beginthread, _endthread, and _fpreset are not available. You
must use DosCreateThread to create a new thread, and you must write your own
initialization, termination, and exception handling code.
ΓòÉΓòÉΓòÉ 7.14. Can I Use C Functions on a File Opened with DosOpen? ΓòÉΓòÉΓòÉ
Question:
I want to use DosOpen to open files so I can specify file inheritance
information, but can I then use C library functions (like fread) on those
files?
Answer:
After you open the file with DosOpen, use _fdopen to convert your OS/2 file
handle to a C stream pointer. You can then use the C stream library functions
on that file. Note that you must then close that file with fclose.
You can also accomplish the same thing by opening the file with a C function
(like fopen), and then setting the inheritance bit with
DosSetFHState(fileno(file)). However, this does not work if you have other
requirements, like sharing or caching, the DosSetFHState cannot handle.
ΓòÉΓòÉΓòÉ 7.15. Can I Change the Parent's Environment from a Child Process? ΓòÉΓòÉΓòÉ
Question:
Can my child process change the environment settings for its parent process and
have them remain in effect?
Answer:
No. However, you can code the child process to write out a .CMD file, and then
call that file from the invoking process to pick up the environment changes.
ΓòÉΓòÉΓòÉ 7.16. How Can I Perform Port Input/Output? ΓòÉΓòÉΓòÉ
Question:
I want to perform port input and output. Are there functions that can read to
and write from ports?
Answer:
VisualAge C++ includes the functions inp, inpd, inpw, outp, outpd, and outpw
that you can use to do port input and output. However, you can only use these
functions in code that runs at ring zero (namely, device drivers). 32-bit
application code cannot perform direct I/O.
If your 32-bit application requires direct port I/O, you need to create a
16-bit input/output parameter list (IOPL) segment. (IOPL does not apply to
32-bit segments.) The functions that perform the direct I/O must reside in this
segment. One way to create the segment is include the port I/O functions from
C/2 in a 16-bit DLL. However, it may be more efficient to link them directly to
your 32-bit code or even to write the functions directly in assembler.
ΓòÉΓòÉΓòÉ 7.17. Can Signals Be Raised Across Processes? ΓòÉΓòÉΓòÉ
Question:
Can signals be raised asynchronously (process to process)?
Answer:
The only signals that can be raised in another process are the following:
Signal OS/2 API to use
SIGTERM DosKillProcess
SIGINT DosSendSignalException
SIGBREAK DosSendSignalException
This is a limitation of 32-bit OS/2.
ΓòÉΓòÉΓòÉ 7.18. What Should I Call in _DLL_InitTerm? ΓòÉΓòÉΓòÉ
Question:
I am writing my own _DLL_InitTerm function. What should I call in it to
correctly initialize and terminate the runtime environment?
Answer:
What you need to call depends on the runtime library you use, and on how you
link to it (statically or dynamically).
If you use the single- or multithread library:
If your DLL statically links to the runtime library, you must call the
following functions in the order shown:
_CRT_init Initializes runtime environment.
__ctordtorInit Initializes static C++ objects.
__ctordtorTerm Terminates static C++ objects.
_CRT_term Terminates the runtime environment.
If your DLL dynamically links to the runtime, you don't need to (and
shouldn't) call _CRT_init and _CRT_term. The runtime library DLL initializes
and terminates itself.
If you use the subsystem library
If your DLL statically links to the subsystem runtime, call the following
functions in the order shown:
_rmem_init
Initializes the runtime memory allocation functions.
Note: If your DLL uses tiled memory, call _tmem_init instead of
_rmem_init to initialize the functions for tiled memory.
__ctordtorInit
Initializes static C++ objects.
__ctordtorTerm
Terminates static C++ objects.
_rmem_term
Terminates the runtime memory allocation functions.
Note: If your DLL uses tiled memory, call _tmem_term instead of
_rmem_term to terminate the functions for tiled memory.
If your DLL dynamically links to the runtime library, you don't need to (and
shouldn't) call _rmem_init and _rmem_term (or _tmem_init and _tmem_term). The
runtime library DLL initializes and terminates the functions itself.
ΓòÉΓòÉΓòÉ 8. Coding with the Data Type Classes ΓòÉΓòÉΓòÉ
This section discusses questions you might have about the IString, IDate, and
ITime classes.
What Is the Maximum Length of an IString?
How Do I Convert an IString to char* ?
Can an IString Contain Null Characters?
How Should I Handle Date and Time in a Container?
ΓòÉΓòÉΓòÉ 8.1. What Is the Maximum Length of an IString? ΓòÉΓòÉΓòÉ
Question:
Is there a limit on the size of an IString? What is the maximum length?
Answer:
The theoretical maximum size of an IString object is UINT_MAX - 1 (UINT_MAX is
defined in <limits.h>). In practical terms, the limit of IString size is the
size of the largest memory block that can be allocated on your system.
ΓòÉΓòÉΓòÉ 8.2. How Do I Convert an IString to char* ? ΓòÉΓòÉΓòÉ
Question:
How do you access the actual string contained in an object of type IString, and
how do you convert between an IString and a regular char* string?
Answer:
IString provides an operator char*, so you can cast an IString to a char*
either implicitly or explicitly. IString also provides a constructor that
accepts a char* argument, so you could code something like:
IString foo("testing");
foo = "this is a test";
You should treat the char* value as const char*, because changes you make using
char* can corrupt the IString object. IString does not convert to a const char*
for backwards compatibility.
ΓòÉΓòÉΓòÉ 8.3. Can an IString Contain Null Characters? ΓòÉΓòÉΓòÉ
Question:
Can an IString contain a null character other than the terminating null
character?
Answer:
Yes, it can. For example, you can set an IString to "Static text\0More text
after NULL". If you cast that IString to a char*:
char* pChar = (char*)nullString; // nullString is the IString object
pChar will also point to "Static text\0More text after NULL". However, if you
pass pChar to functions that expect a terminating null character, such as the C
library string functions, those functions will interpret the null as the
terminating null character for the string and stop reading after "Static text".
You can use the indexOf and subString functions of IString to extract the
null-terminated strings:
int nullIndex;
IString str("This is a string\0Hi there\0Last One\0", 35);
int startPos = 1;
while ( nullIndex = str.indexOf('\0', startPos) ) {
cout << str.subString(startPos, nullIndex - startPos) << endl;
startPos = nullIndex + 1;
}
ΓòÉΓòÉΓòÉ 9. Coding with the Collection Classes ΓòÉΓòÉΓòÉ
This section answers questions you may have about using the Collection class
library.
Why Does elementAt Not Work Correctly for My Cursor?
Why Do I Get Errors in <istdops.h>?
Why Do I Get an Error Returning the Key Element?
Why Do I Get Unexpected Results When I Add a Key?
Why Do I Get Linker Errors about Undefined Key Functions?
Why Is My Exception Output Traced When the Exception Is Caught?
Why Do I Get an Error about Undeclared Element Types?
Why Do I Get Compiler Errors about Multiply-Defined Symbols?
Why Do I Get Linker Errors for Multiply-Defined Symbols?
Why Do I Get Messages about Needing Constructors?
Why Do I Get Unresolved External References for Symbols I Don't Use?
ΓòÉΓòÉΓòÉ 9.1. Why Does elementAt Not Work Correctly for My Cursor? ΓòÉΓòÉΓòÉ
Question:
When I use cursors, I get unexpected results. For example, elementAt sometimes
fails for the cursor or returns an unexpected element.
Answer:
You have used an undefined cursor. Cursors become undefined when an element is
added to or removed from the collection.
You must rebuild your cursor with an appropriate operation (for example,
locate()) before you use it again. Rebuilding is especially important for
removing all elements with a given property from a collection. Elements cannot
be removed by coding a cursor iteration. Use the removeAll() function that
takes a predicate function as its argument.
For more information about cursors, see the Open Class Library User's Guide.
ΓòÉΓòÉΓòÉ 9.2. Why Do I Get Errors in <istdops.h>? ΓòÉΓòÉΓòÉ
Question:
I get several different compiler error messages about undefined keys, unmatched
hash types, and operators that aren't allowed. All the errors point to
<istdops.h>. Why do I get these errors?
Answer:
Compiler error messages indicating a problem in <istdops.h> are related to the
element and key-type functions that you must define for your elements. These
functions depend on the collection and implementation variant you are using.
The compilation errors you describe occur when the key() function, the hash()
function, operator==, or operator< are required for your elements, but are
defined with the wrong interface or not defined at all. Whether arguments are
defined as const is significant. Compiler messages do not always point
directly to the incorrect function. For example, a compare function with
non-const arguments results in the compilation error:
The "<" operator is not allowed between "const ..".
Verify which element and key-type functions are required for the implementation
variant of the collection you are using. You can find this information for each
collection in the Open Class Library Reference in the section pertaining to the
collection under the heading "Template Arguments and Required Functions".
For more information about element and key-type functions, see the Open Class
Library User's Guide.
Note that the same problem may be produced if function declarations and
definitions are not correctly separated between .h files and .cpp files. This
situation is described in detail in Why Do I Get an Error about Undeclared
Element Types?.
ΓòÉΓòÉΓòÉ 9.3. Why Do I Get an Error Returning the Key Element? ΓòÉΓòÉΓòÉ
Question:
When I try to return the key value, I get a compiler message warning about the
use of a local variable or temporary in a return expression. Why?
Answer:
Your global-name-space function key() returns the key by value instead of by
reference. A temporary variable is created for the key within the
operator-class function key. The operator class function key returns the key by
reference. Returning a reference to a temporary variable causes unpredictable
results.
The key function must return a reference and must also take a reference
argument. If the key function calls other functions to access the key, it must
call those functions with a reference to the object as an argument, and those
functions must return a reference to the key.
Verify that the global name-space function key correctly returns a key const&
instead of key.
For more information on element and key-type functions, see the Open Class
Library User's Guide.
ΓòÉΓòÉΓòÉ 9.4. Why Do I Get Unexpected Results When I Add a Key? ΓòÉΓòÉΓòÉ
Question:
I am trying to add an element into a unique key collection (a key set or map).
I am sure that the collection does not already contain an element with this
key. However, I either get the IKeyAlreadyExistsException, or the element is
not added and the cursor is positioned to a different element. Why?
Answer:
Your global-name-space function key() returns the key by value instead of by
reference. If you compile with a higher warning level, you will get compiler
error messages about this as described in Why Do I Get an Error Returning the
Key Element?. A temporary variable is created for the key within the
operator-class function key. The operator class function key returns the key by
reference. Returning a reference to a temporary variable causes unpredictable
results.
The key function must return a reference and must also take a reference
argument. If the key function calls other functions to access the key, it must
call those functions with a reference to the object as an argument, and those
functions must return a reference to the key.
Verify that the global name-space function key correctly returns a key const&
instead of key.
For more information on element and key-type functions, see the Open Class
Library User's Guide.
ΓòÉΓòÉΓòÉ 9.5. Why Do I Get Linker Errors about Undefined Key Functions? ΓòÉΓòÉΓòÉ
Question:
When I link my object files, I get an error message that a key function is
undefined. Why?
Answer:
You are using a collection class that requires the element class to provide a
key, and you chose to use the method of using a global key() function. You are
using collection class methods in a .CPP file, but the .H file with the same
name as the .CPP file does not contain a declaration (prototype) of the global
key function.
While compiling the .CPP file, which uses methods of the collection class, the
compiler has created or modified a temporary .CPP file in the TEMPINC
directory. During the link step, this .CPP file is compiled to resolve
references to template code. The error message you encounter refers to this
compilation.
The .CPP file in the TEMPINC directory contains include directives for the
collection class template code. It also contains include directives for a .H
file of the same name as the .CPP file that uses the collection class methods.
The template code in <istdops.h> requires that the global key() function be
known at compilation time. The only file that is included at this time is the
.H file with the same name as your .CPP file. The problem is that the .CPP
file is not included at this time, so a definition or declaration of the global
key() function in this file is not recognized by the compiler.
You must declare the global key() function in the .H file with the same name as
the .CPP file that uses the collection class methods. The definition of the
global key() function should be in the .CPP file. If you are not sure which .H
file is meant by the message, look in the .CPP file found in the TEMPINC
directory.
ΓòÉΓòÉΓòÉ 9.6. Why Is My Exception Output Traced When the Exception Is Caught? ΓòÉΓòÉΓòÉ
Question:
Why is my exception tracing output printed to stderr when the exception has
already been caught?
Answer:
For each exception raised, the trace function write() of class
IException::TraceFn is called and writes information about the raised exception
to standard error. This trace function write() is called whether the related
exception is caught or not.
To suppress the trace output, provide your own IException::TraceFn::write()
tracing function by subclassing IException::TraceFn and register the subclass
with setTraceFunction(). For more information about exception tracing, see the
Open Class Library User's Guide.
ΓòÉΓòÉΓòÉ 9.7. Why Do I Get an Error about Undeclared Element Types? ΓòÉΓòÉΓòÉ
Question:
I am compiling a file that uses templates and I am getting a compiler error
that an element or one of its required element functions is not declared. Why?
Answer:
The element type or element function is defined locally to the .cpp file that
contains the template instantiation with the element type as its argument. The
prelink phase is executed only by using the header files. Therefore, your
declaration local to a .cpp file is not recognized and causes these compilation
errors.
Move the corresponding declarations to a separate header file and include the
header file from the .cpp file.
ΓòÉΓòÉΓòÉ 9.8. Why Do I Get Compiler Errors about Multiply-Defined Symbols? ΓòÉΓòÉΓòÉ
Question:
Why do I get compiler errors about symbols being defined multiple times?
Answer:
The template instantiation needs to include the type declarations it received
as arguments. Your header files containing type declarations used in template
classes may automatically be included several times.
Protect your header files against multiple inclusion by using the following
preprocessor macros at the beginning and end of your header files:
#ifndef _MYHEADER_H_
#define _MYHEADER_H_ 1
.
.
.
#endif
Where _MYHEADER_H_ is an identifier unique to each header file and representing
the header file's name.
ΓòÉΓòÉΓòÉ 9.9. Why Do I Get Linker Errors for Multiply-Defined Symbols? ΓòÉΓòÉΓòÉ
Question:
Why do I get linker errors about symbols being defined multiple times?
Answer:
The template instantiation needs to include the type declarations it received
as arguments. Your header files containing type declarations used in template
classes might automatically be included several times.
Verify that you did not define functions in the header files that declare types
used in templates. If you did, you must move them from the header file into a
separate .cpp file or make them inline.
ΓòÉΓòÉΓòÉ 9.10. Why Do I Get Messages about Needing Constructors? ΓòÉΓòÉΓòÉ
Question:
Why does the compiler say that I need a constructor for my template class?
Answer:
Compiler error messages indicating a problem with constructors for a collection
are typically related to the constructors defined for your element. Here the
default constructor for the element is missing.
Define the default constructor for the element class.
For more information about element and key-type functions, see the Open Class
Library User's Guide. The element and key-type functions required for each
collection are listed for each collection type in the sections entitled
"Template Arguments and Required Functions".
ΓòÉΓòÉΓòÉ 9.11. Why Do I Get Unresolved External References for Symbols I Don't Use? ΓòÉΓòÉΓòÉ
Question:
When I link my program, I get errors about unresolved external references for
symbols that I don't use or know about. Why?
Answer:
A possible reason for unresolved external references during linking is that
template code cannot be correctly resolved. To ensure templates resolve
correctly, invoke the linker using icc with the /Tdp option.
ΓòÉΓòÉΓòÉ 10. Coding with User Interface Classes ΓòÉΓòÉΓòÉ
This section answers questions about the User Interface class library and how
to use it. Because of the scope of the User Interface library, this section is
broken down into the following topics:
Base Window and Events
Handlers
Frame Windows
Canvas Classes
Container Control
Text and Button Controls
Listbox and Combobox Controls
Notebook Control
Other Controls
Menus
Creating Help with IHelpWindow
Application and Resources
Threads
Fonts and Colors
Font and File Dialogs
Direct Manipulation (Drag and Drop)
Dynamic Data Exchange (DDE)
Exceptions
Internationalization
Extending the User Interface Class Library
Graphics and Drawing
ΓòÉΓòÉΓòÉ 10.1. Base Window and Events ΓòÉΓòÉΓòÉ
This section discusses general window and event topics:
What Does IWindow::setAutoDeleteObject Do?
How Should I Number Window IDs?
What is the Difference between Sending and Posting Messages?
How Do I Access the Value of IHandle Objects?
How Do Owner and Parent Relationships Work?
ΓòÉΓòÉΓòÉ 10.1.1. What Does IWindow::setAutoDeleteObject Do? ΓòÉΓòÉΓòÉ
Question:
What does setAutoDeleteObject do, and when should I use it? Is it only for
IWindow instances created by operator new, or for all instances?
Answer:
The setAutoDeleteObject function is only for windows created with new. It
causes code in the User Interface dispatcher to call delete for the C++ object
some time after the underlying presentation system window has been destroyed.
In general, if you create something with the new operator, you must also delete
it. This is true of IWindow objects also. However, you can use
setAutoDeleteObject( true ) to have the User Interface class library delete the
object for you if it is difficult to keep track of the IWindow object you
created. One place where setAutoDeleteObject is useful is the creation of a
modeless secondary or child frame window.
When you use setAutoDeleteObject(true), do not call delete yourself for the
object.
ΓòÉΓòÉΓòÉ 10.1.2. How Should I Number Window IDs? ΓòÉΓòÉΓòÉ
Question:
What numbering scheme shoud I use for window IDs? Do they have to start from a
specific number? Is there an upper limit?
Answer:
The safest way to program is to use window IDs that are unique on a per-frame
window basis. You can then easily provide unique contextual help for all
windows and identify the window under the mouse from a WM_CONTROLPOINTER
message. If you don't use unique IDs, you'll need to know how you call
functions like IWindow::windowWithId and functions that call it (such as
IControlEvent::controlWindow). PM reserves some window IDs for windows that it
creates, making it more difficult to ensure that your window IDs are unique.
For client windows, you should always use a window ID of 0x8008 (preferably by
using either the constant FID_CLIENT from <pmwin.h> or IC_FRAME_CLIENT_ID from
<icconst.h>). If you don't, IFrameWindow::setClient changes the value of the ID
to this, meaning that any code that relied on the value you set will not work
correctly.
Avoid using all other FID_* window IDs from <pmwin.h> for child windows of a
frame.
Although window IDs in PM APIs are unsigned long types, PM only honors the low
word. Therefore, keep your window IDs below 65535.
ΓòÉΓòÉΓòÉ 10.1.3. What is the Difference between Sending and Posting Messages? ΓòÉΓòÉΓòÉ
Question:
What is the difference between sending a message and posting one?
Answer:
When a message is sent (sendEvent), the sender is blocked until the receiver
processes the message and returns. If the sender and receiver are on the same
thread, a direct function call is made to the receiver. If the sender and
receiver are on different threads, the message is placed on a private area of
the receiver's message queue. In either case, the sender is blocked until the
receiver processes the message and returns.
When a message is posted, the message is placed on the receiver's message
queue. The poster's thread then continues without waiting for a reply.
ΓòÉΓòÉΓòÉ 10.1.4. How Do I Access the Value of IHandle Objects? ΓòÉΓòÉΓòÉ
Question:
How do I use the Value operator from the IHandle class to get the handle value
from an IMessageQueueHandle object?
Answer:
In PM, Value is defined in a typedef to be an unsigned long value. Therefore,
operator Value is really operator unsigned long, so you can use an IHandle or
IMessageQueueHandle object as an unsigned long and not have to call any
functions.
In general, the IHandle-derived classes contain conversion operators that
define conversions to the underlying system object. Usually you can use the
IHandle objects in system calls where the corresponding system type is
expected.
In PM, the underlying type for HWND, HMQ, and most of the other handle objects
is unsigned long. In the Motif version, the underlying types are typically
pointers to an X or Motif structure (such as Widget, which is really a
_WidgetRec*).
ΓòÉΓòÉΓòÉ 10.1.5. How Do Owner and Parent Relationships Work? ΓòÉΓòÉΓòÉ
Question:
As a new programmer in the PM environment, I still don't understand the
concepts of parent and owner as they relate to window controls. Can you please
explain?
Answer:
The most important thing to remember is that parent and child relates to the
display hierarchy of the windows in your application, and owner and owned
relates to the control hierarchy. The display hierarchy deals with things like
clipping and Z-order control. The control hierarchy deals with messages going
between the owned and owner windows.
The parent window is normally used for window location. For example, most frame
windows have a parent of the desktop so that they can appear anywhere on the
desktop. If a window is a child of another winodw, then it is only visible
inside the parent window. (That is, a window is clipped to its parent.)
Many messages are passed up the owner chain for processing. In PM, changes to
presentation parameters (such as color or font) are passed down the owner
chain. When you move an owner window, all of the windows that it owns are
usually moved as well.
A window with the desktop as parent and owner is considered a primary window.
A window with the desktop as parent but with another window as owner is
considered a secondary window. A window whose parent and owner are another
window or windows is considered a child window.
ΓòÉΓòÉΓòÉ 10.2. Handlers ΓòÉΓòÉΓòÉ
This section discusses handlers, including common problems that can be solved
using a handler.
How Do I Change the Mouse Pointer?
How Do I Capture Mouse Movement?
How Do I Send and Handle User-Defined Messages?
Which Handler Should I Use?
How Do I Find the IWindow from a Handler?
How Do I Replace Events?
How Are Keystrokes Processed?
ΓòÉΓòÉΓòÉ 10.2.1. How Do I Change the Mouse Pointer? ΓòÉΓòÉΓòÉ
Question:
I want to change the pointer icon while the pointer is over my application
window. How do I do this?
Answer:
Use the IMouseHandler class or the IFrameWindow::setMousePointer function.
ΓòÉΓòÉΓòÉ 10.2.2. How Do I Capture Mouse Movement? ΓòÉΓòÉΓòÉ
Question:
I need to be aware of any mouse movement that occurs while the mouse pointer is
on top of my application window. Is there a way to be informed about mouse
movements?
Answer:
Yes. VisualAge C++ Open Class Library Version 3.0 includes a handler to
capture mouse movements. Derive from IMouseHandler and override the mouseMoved
function to be informed of mouse movements.
ΓòÉΓòÉΓòÉ 10.2.3. How Do I Send and Handle User-Defined Messages? ΓòÉΓòÉΓòÉ
Question:
How do I dispatch and capture my own user-defined messages to an event handler?
How do I create a handler to capture the message?
Answer:
When you create a handler and call its handleEventsFor function, all messages
dispatched to the handler's windows are sent to the handler's
dispatchHandlerEvent function. To handle messages differently, override this
function and capture whatever user or system messages you want to handle. You
must also return true or false to indicate whether other handlers should
receive the message, and call setResult on the event passed to
dispatchHandlerEvent if you need to pass information back to PM or to the
sender of the event.
To dispatch a message to a window:
Use the postEvent or sendEvent functions of IWindow or IWindowHandle to
post or send an event to a specific window.
Use IMessageQueueHandle::postEvent to post an event to a specific message
queue.
For example, if you have attached your handler to an IWindow window, send
messages to it with:
mywindow.sendEvent( USER_MESSAGE )
This sends USER_MESSAGE to mywindow, which then causes your handler to run.
Your dispatchHandlerEvent function should look for USER_MESSAGE and do
whatever it needs to with it.
One case where a user message handler is useful is to process the messages
sent to an object window (IObjectWindow). Object windows are useful in cases
where you have application-defined events that may take a long time to
process. Because object windows are invisible and never get the input focus,
you will not block user input going to other windows while you process these
events. To use an object window, create a separate thread using IThread and
in it:
1. Create an IObjectWindow,
2. Create a user message handler,
3. Attach this handler to the object window,
4. Call IThread::current().processMsgs().
Your main thread simply posts WM_USER events to the object window. You need
to somehow pass back a handle for the object window to your main thread and
possibly pass in a window handle to the object window so it can communicate
back. You can use a user handler on the main thread to accept communications
from the object window.
For an example of a WM_USER message handler, click below:
Example
For more details on handlers, see the Open Class Library User's Guide. The
HELLO6 sample program also has an example of a user-defined handler that
handles WM_TIMER messages.
ΓòÉΓòÉΓòÉ <hidden> Example of WM_USER Message Handler ΓòÉΓòÉΓòÉ
Here is an example of a WM_USER message handler that you could add to a frame
window. When you want to post a message to the frame window, you do something
like:
#define WM_DATA_IS_READY WM_USER + 100
myFrameWindow->postEvent(WM_DATA_IS_READY );
The handler would look like this:
----------------------------- iusrhdr.hpp -----------------------
#ifndef _IUSERHDR_
#define _IUSERHDR_
#include <ihandler.hpp>
#include <ievent.hpp>
#pragma pack(4)
class IUserHandler : public IHandler {
public:
IUserHandler ( );
virtual
~IUserHandler ( );
virtual Boolean
dispatchHandlerEvent ( IEvent& event );
protected:
virtual Boolean
user ( IEvent& event ) = 0;
};
#pragma pack()
#endif
--------------------------- iusrhdr.cpp ----------------------------
#define INCL_WINMESSAGEMGR
#include <os2.h>
#include <iuserhdr.hpp>
IUserHandler :: IUserHandler ( )
: IHandler ( )
{ }
IUserHandler :: ~IUserHandler ( )
{ }
Boolean IUserHandler :: dispatchHandlerEvent ( IEvent & evt )
{
Boolean bRc = false;
switch (evt.eventId())
{
case WM_DATA_IS_READY:
{
bRc = user(evt);
break;
}
default:
break;
} /* endswitch */
return bRc;
}
ΓòÉΓòÉΓòÉ 10.2.4. Which Handler Should I Use? ΓòÉΓòÉΓòÉ
Question:
How do I decide which handler class to use for a particular event? Is there a
cross reference of handler classes and the messages they process?
Answer:
There is a table in the Open Class Library User's Guide chapter on handlers and
events that lists some of the events and the handlers they are dispatched to.
The VisualAge C++ documentation does not include a cross-reference between the
handler classes and the system (PM) messages they process.
OS/2 C++ Class Library: Power GUI Programming with C Set ++ also contains a
listing of the handler classes and recommendations on where you might use them,
as well as a handler-to-PM-message cross-reference. (Note that this book does
not include information about additions to Version 3.0 of the library.)
If you have the Open Class Library Source Code product, you can determine the
messages processed by a handler by examining the dispatchHandlerEvents function
implementation. However, do not depend on this being constant; future library
enhancements may alter the message set handled by a handler class.
ΓòÉΓòÉΓòÉ 10.2.5. How Do I Find the IWindow from a Handler? ΓòÉΓòÉΓòÉ
Question:
If more than one control is attached to the the same event handler, how do I
find the IWindow object relating to the current event?
Answer:
When in a handler callback function, event.window() returns the window the
message was dispatched to.
If the event was not an IControlEvent, event.window() returns the window
itself.
For an IControlEvent, event.window() returns the owner of the control. You can
then call IControlEvent::controlWindow to get the control window pointer. Once
you have the window pointer, you can call IWindow::id to find the window's ID.
You can also get the ID of a control in an event derived from IControlEvent by
calling controlId.
ΓòÉΓòÉΓòÉ 10.2.6. How Do I Replace Events? ΓòÉΓòÉΓòÉ
Question:
How do I replace an event that comes to my application with a different event?
Answer:
Typically you would implement a handler to replace the event. Detect the
specific event you want to replace, and then send or post the replacement event
or message to the window. Return a value of true to indicate that the original
event should not be passed on to any more handlers or to any window procedures.
However, any time you do this, you need to ensure that you don't cause an
endless loop. You may need to add a check to your handler to detect that an
event is not to be replaced again or reposted.
Alternatively, when you detect the event to replace, you can build your
replacement event, then pass it to IWindow::defaultProcedure, and return a
value of true. The difference is that the replacement event won't come back
through your handler, although it will also bypass all previous and subsequent
handlers. Therefore, any other handlers attached to your window cannot process
the replacement event.
You can also call IWindow::dispatchRemainingHandlers to bypass handlers that
have already been called, so that only subsequent handlers (and optionally,
IWindow::defaultProcedure) are called.
ΓòÉΓòÉΓòÉ 10.2.7. How Are Keystrokes Processed? ΓòÉΓòÉΓòÉ
Question:
How are keystrokes processed?
Answer:
The normal processing for keystrokes is that the window (control) with the
input focus has the first opportunity to process the key. If that window
doesn't process it, then the key is passed up to its owner window. The owner
window can then process the key. If not processed, it again goes up the owner
chain. The cycle continues until the keystroke is processed or until no
windows are left in the owner chain.
You need to consider this behavior when using an IKeyboardHandler in your
application. For example, IMultiLineEdit processes PageUp and PageDown to
scroll the data. If you want the IMultiLineEdit to ignore these keys, create a
keyboard handler that provides an implementation for the virtualKeyPress
function. In the handler, look specifically for IKeyboardEvent::pageUp and
IKeyboardEvent::pageDown virtual keys. You can route these keystrokes to the
owner window of the MLE by calling:
event.window()->owner()->sendEvent( event );
Then return true to indicate that PageUp or PageDown should not be given to the
MLE to process. For all other cases, return false. This will have the effect
of disabling the MLE scrolling. You could use such a setup when the MLE's
owner is an IViewPort that will be handling the scrolling.
ΓòÉΓòÉΓòÉ 10.3. Frame Windows ΓòÉΓòÉΓòÉ
This section discusses frame windows, dialog templates, and related topics.
How Do I Set the Title of a Frame Window?
How Can I Intercept a Request to Close a Frame Window?
What Is the IFrameWindow Client Window?
Why Is the Client ID Changed?
How Do I Set Up an IFrameWindow within an IFrameWindow?
Can I Use a Frame as a Client Window?
Can I Have Automatic Resizing for Dialogs?
Why Doesn't My Control Defined in a DLG Resource Work?
Should I Use Canvas Classes or Dialog Templates?
Can I Set the Minimum Size of an IFrameWindow?
How Do I Access the Scroll Bars on an IFrameWindow?
Why Does My Dialog Overwrite the Parent Notebook?
Why Doesn't My Application End when the Frame is Closed?
How Do I Exit IApplication::current().run() ?
ΓòÉΓòÉΓòÉ 10.3.1. How Do I Set the Title of a Frame Window? ΓòÉΓòÉΓòÉ
Question:
How can my application read and set the titlebar text of an existing
IFrameWindow object?
Answer:
Use the ITitle class. Create an ITitle object from the IFrameWindow, and then
use objectText() and setObjectText(), or text() and setText(). to read and
change the frame window's title, respectively.
ΓòÉΓòÉΓòÉ 10.3.2. How Can I Intercept a Request to Close a Frame Window? ΓòÉΓòÉΓòÉ
Question:
When the user closes my application with the system menu, I need to intercept
the close request so I can display a confirmation message. How can I do this?
Answer:
The command you want to intercept is SC_CLOSE. You can use the PM constant
SC_CLOSE or the ISystemMenu::idClose constant. To use SC_CLOSE, derive a
handler from ICommandHandler and provide a systemCommand function similar to
this:
Boolean MyCommandHandler::systemCommand(ICommandEvent& cmdEvt)
{
if ( cmdEvt.commandId() == SC_CLOSE )
{
// ask for confirmation from user ...
if ( response != IMessageBox::yes )
return true; // let it close
}
return false; // don't close
}
Attach this command handler to your IFrameWindow.
Another way to do this is to attach your own IFrameHandler to your frame
window, providing your own implementation of the virtual closed() function.
This function will be called when the frame window is closed. (It keys off a
WM_CLOSE, WM_SYSCOMMAND, or SC_CLOSE command).
ΓòÉΓòÉΓòÉ 10.3.3. What Is the IFrameWindow Client Window? ΓòÉΓòÉΓòÉ
Question:
I want to create a window with a number of child controls in it. I thought of
using canvases, but don't know what to use for a client window. What should I
do?
Answer:
You can make almost any control the client of your frame. The client window is
just the window that fills up the client area (the portion of the frame not
occupied by frame controls). It can be any type of control; canvases are
especially useful if you want your child controls to behave like dialogs (with
Tab key support and so on).
ΓòÉΓòÉΓòÉ 10.3.4. Why Is the Client ID Changed? ΓòÉΓòÉΓòÉ
Question:
I have a dialog that I create specifying an ID of 0x11FE. My dialog has an
ISelectHandler attached to it. When my enter() method is called, the
controlId() method returns 0x8008. What is happening?
Answer:
The ID 0x8008 is the value of the constant FID_CLIENT (and IC_FRAME_CLIENT_ID).
The frame forces its client to have that ID so it knows the window is the
client window. If you use a different value, IFrameWindow::setClient changes
the window ID for you. The client window's ID must remain FID_CLIENT, or the
frame won't format correctly or correctly dispatch events to the client window.
You can obtain the FID_CLIENT definition from <pmwin.h>. IC_FRAME_CLIENT_ID is
defined in <icconst.h>.
ΓòÉΓòÉΓòÉ 10.3.5. How Do I Set Up an IFrameWindow within an IFrameWindow? ΓòÉΓòÉΓòÉ
Question:
I have created a primary window using IFrameWindow. I also created a second
IFrameWindow as a child of the primary window, using the primary window as both
its parent and owner. How do I prevent the child frame from being positioned
over the menu bar of my primary window?
Answer:
You need to add a client area window to the parent frame, and make the client
the parent of the child frame. This will also keep the child frame from
overwriting the borders of the parent frame.
ΓòÉΓòÉΓòÉ 10.3.6. Can I Use a Frame as a Client Window? ΓòÉΓòÉΓòÉ
Question:
Can I use a frame window as the client window of another frame? I tried to do
this, but saw strange results.
Answer:
A frame window does not work well as a client window because of certain aspects
of PM's frame-window procedure.
A PM frame window sends itself certain messages like WM_FORMATFRAME and
WM_UPDATEFRAME, and expects to receive these messages only from itself. It also
forwards these messages to its client window (as part of the frame-client
message protocol).
If the client window is a frame window, the client expects these messages to
come only from itself. When it receives them from the parent frame window
instead, the resulting processing can give unexpected results.
Accelerator keys and WM_HELP messages are also likely to be processed by the
client frame, rather than its parent, which might not be what you expect.
ΓòÉΓòÉΓòÉ 10.3.7. Can I Have Automatic Resizing for Dialogs? ΓòÉΓòÉΓòÉ
Question:
If I use the Dialog Editor to build my dialog and then create an IFrameWindow
from it, will the controls reflow when the main window is sized? Can I make the
dialog fill the whole client area in the main window?
Answer:
If you use a dialog template to lay out the controls, there is no "reflowing"
when you size the frame. The dialog will fill the whole frame. The dialog
controls will be sized and positioned as you specified in the dialog template.
Automatic sizing is only done on the client window of an IFrameWindow. You can
use the canvas classes to construct windows with dialog behavior that are also
resized when the frame is resized.
Typically there is no client window in dialogs that are generated using the
Dialog Editor. However, if your dialog template does happen to have a window
with an ID of FID_CLIENT (0x8008), IFrameWindow::client will return it
regardless of whether you've called setClient. You still have to use one of the
User Interface classes as a wrapper for your client window so that there is an
IWindow pointer to return to you. You can use IFrameWindow::clientHandle to get
back a window handle even if you haven't wrappered the client window with a
User Interface class.
ΓòÉΓòÉΓòÉ 10.3.8. Why Doesn't My Control Defined in a DLG Resource Work? ΓòÉΓòÉΓòÉ
Question:
I want to create a combo box that is read-only. I instantiated an
IComboBox::Style class, set it to dropDownListType, and passed it to the combo
box constructor, but the user can still change the entry field part of the
combo box without using the list box control. What should I do?
Answer:
The combo box is defined in a PM dialog template. The first constructor
creates a new combo box control, which is 0-sized, so you can't see it. Your
code is acting on this 0-sized combo box, not the visible one created by the
dialog template.
The second constructor correctly wraps the combo box created by the dialog box.
Because the type of the combo box can only be specified when the control is
created, you must change how the combo box is defined in the dialog template.
Both constructors create an IComboBox C++ object. The first also creates a
combo box control. The second requires an existing control that will be
represented by the IComboBox object.
ΓòÉΓòÉΓòÉ 10.3.9. Should I Use Canvas Classes or Dialog Templates? ΓòÉΓòÉΓòÉ
Question:
I am creating some PM dialogs. Should I use the Dialog Editor to create dialog
templates (.DLG files), or should I create them inline in code using the canvas
classes?
Answer:
If you are targeting your application only for OS/2 in a relatively homogeneous
environment, the Dialog Editor and Resource Compiler provide a quick way to
create the dialogs.
However, many applications written today require that you consider support for
portabilility, multiple monitor resolutions, fonts, and national language. When
these factors come into play, maintaining the dialog resources becomes a major
undertaking. Using the canvas classes may prove more effective in cases where
one or more of these factors are important.
The canvas classes provide layout support that can dynamically change based on
language, fonts, and so on. You lay your controls out on a canvas aligned
relative to one another in a row and column type gridding, and the class
handles the rest.
Take a look at the Hello World sample (HELLO6 in particular) for an example of
how this works. It shows an example of the same application using different
language resources. By bringing each one up, you can see how the same code
will handle the language changes. You can also drop fonts onto the canvas, and
you will see how it handles that as well.
The portability of dialog resources is also very limited. The canvas classes
are fully supported in the Motif version of the User Interface classes (shipped
with C Set ++ for AIX), but dialog templates are not supported at all.
Refer to the chapter on Creating Dialogs in the Open Class Library User's
Guide.
ΓòÉΓòÉΓòÉ 10.3.10. Can I Set the Minimum Size of an IFrameWindow? ΓòÉΓòÉΓòÉ
Question:
I have a frame window with a client window that is an instance of
IMultiCellCanvas. Thus it has a minimum size. When I resize the frame window
with the mouse, it is resized but the client does not become smaller than its
minimum size, so part of the client window is not visible.
Is there a way to force a frame window not to become smaller than the minimum
size of its client window?
Answer:
There is no direct support in the library for making the frame window behave in
this way. You may be able to control this behavior by creating a handler that
processes the WM_QUERYTRACKINFO message to limit resizing using the mouse.
If you are initially sizing the frame, you can query the minimum size of the
client window and use the size obtained to size the frame using the
IFrameWindow::moveSizeToClient function.
ΓòÉΓòÉΓòÉ 10.3.11. How Do I Access the Scroll Bars on an IFrameWindow? ΓòÉΓòÉΓòÉ
Question:
If I create a frame window with the IFrameWindow::horizontalScroll and
IFrameWindow::verticalScroll styles, are there any ways to access these
scrollbars?
Answer:
In PM, you can construct IScrollBar objects for them as follows:
IScrollBar* vert = new IScrollBar( FID_VERTSCROLL, &frameWindow );
IScrollBar* horz = new IScrollBar( FID_HORZSCROLL, &frameWindow );
(The window IDs, FID_VERTSCROLL and FID_HORZSCROLL are defined in <pmwin.h>.)
If you do the above, you have to provide the scrolling support yourself. You
can use the IScrollBar and IScrollHandler classes to provide this support.
Alternatively, you can use an IViewPort as your client window, in place of the
frame scroll bars. Generally IViewPort does not require you to provide any
code for it to scroll a window.
ΓòÉΓòÉΓòÉ 10.3.12. Why Does My Dialog Overwrite the Parent Notebook? ΓòÉΓòÉΓòÉ
Question:
I'm adding a dialog page to a notebook. When I run my code, the dialog pops up
on the screen overwriting parts of the notebook. When I turn to that notebook
page, the dialog appears normally. What am I doing wrong?
Answer:
Be sure that your dialog does not have a WS_VISIBLE style. If this style is
set, the dialog will be drawn over its parent (the notebook) when it is loaded.
ΓòÉΓòÉΓòÉ 10.3.13. Why Doesn't My Application End when the Frame is Closed? ΓòÉΓòÉΓòÉ
Question:
I used to end my application by calling IFrameWindow::close, but after I added
an IObjectWindow, it only closes my frame window and leaves the executable
still running. The last things I added were my frame window but leaves .EXE
still running. What is happening?
Answer:
The problem you are seeing is probably caused by the object window. When you
create an instance of IObjectWindow, the library flags this window as a primary
window (just like a frame window that is a child of the desktop).
IApplication::current().run() will not complete processing until all primary
windows have been closed. Try adding a call to setParent for the object
window; this should cause the library to remove the primary flag for the
window.
myObjectWindow->setParent(IWindow::objectWindow());
ΓòÉΓòÉΓòÉ 10.3.14. How Do I Exit IApplication::current().run() ? ΓòÉΓòÉΓòÉ
Question:
I have a simple application that calls IApplication::current().run(). I want to
override the command function of ICommandHandler so that when the user selects
an exit button, the application is terminated. What is the correct way to
terminate my main window if I want more actions to be executed when the user
chooses the exit button?
Answer:
Call IFrameWindow::close when the application is to be terminated. This
function closes the frame and, if it is the primary frame window, exits the
event loop. Exiting the event loop causes IApplication::current().run() to
return to the caller.
Note that this technique can also be applied to IFrameWindow objects that are
running on secondary threads.
When an IFrameWindow is not involved, such as when you are using an
IObjectWindow, you can call IThread::stopProcessingMsgs to exit the event loop.
ΓòÉΓòÉΓòÉ 10.4. Canvas Classes ΓòÉΓòÉΓòÉ
This section answers questions about the canvas classes: ICanvas, ISetCanvas,
IMultiCellCanvas, ISplitCanvas, and IViewPort.
Can I Resize an IViewPort Child Window?
How Do I Center a Control on a Canvas?
How Do Tabbing and Cursor Movement Work?
Why Does My Canvas Work with new But Not with Solid Objects?
How Do I Get a Fixed Column Size for an IMultiCellCanvas?
Does Changing the Minimum Size Affect Control Behavior?
How Do I Draw Separator Lines in an IMultiCellCanvas?
Why Doesn't removeFromCell Remove the Window Text?
How Many Windows Does IViewPort Have?
How Do I Align an IComboBox in an IMultiCellCanvas?
ΓòÉΓòÉΓòÉ 10.4.1. Can I Resize an IViewPort Child Window? ΓòÉΓòÉΓòÉ
Question:
I want to create an IViewPort that resizes the child window when the size of
the viewport is greater than the minimum size of the child. When one of the
dimensions for the viewport is greater than the corresponding dimensions of the
child window's minumum size, the scroll bar is removed and the child is resized
along that dimension. When the viewport's dimension is less than the child
window's minumum size, the scroll bar must reappear.
How can I do this?
Answer:
The following code creates a resize handler that you can attach to any viewport
to perform the function you describe. The code is for a viewport that scrolls a
multicell canvas, but you could also use it for other types of windows. Further
discussion of this and other canvas tricks be found in chapter 15 of OS/2 C++
Class Library: Power GUI Programming with C Set ++. A complete program using
code similar to that below is on the disk that comes with that book.
class SizeHandlerForViewPortWithMultiCell : public IResizeHandler {
public:
virtual SizeHandlerForViewPortWithMultiCell
&handleEventsFor ( IViewPort* viewport ),
&stopHandlingEventsFor ( IViewPort* viewport );
protected:
virtual Boolean
windowResize ( IResizeEvent& event );
private:
virtual IHandler
&handleEventsFor ( IWindow* window ),
&stopHandlingEventsFor ( IWindow* window );
};
Boolean SizeHandlerForViewPortWithMultiCell :: windowResize
( IResizeEvent& event )
{
IViewPort* viewport = (IViewPort*)event.window();
IMultiCellCanvas* canvas =
(IMultiCellCanvas*)IWindow::windowWithHandle
( viewport->viewWindow() );
if (canvas)
{
ISize newSize = event.newSize();
ISize minChildSize = canvas->minimumSize();
ISize childSize = canvas->size();
ISize newChildSize = newSize; // Grow to viewport size.
if (newSize.width() < minChildSize.width())
{ // Don't shrink child smaller than its minimum size.
newChildSize.setWidth( minChildSize.width() );
} // (Let the viewport scroll it.)
else if (newSize.height() < minChildSize.height())
{ // Allow room for vertical scroll bar if needed.
newChildSize.setWidth( newSize.width() -
viewport->verticalScrollBar()->size().width() );
if (newChildSize.width() < minChildSize.width())
{ // Don't shrink child smaller than its minimum size.
newChildSize.setWidth( minChildSize.width() );
} // (Let the viewport scroll it.)
}
if (newSize.height() < minChildSize.height())
{ // Don't shrink child smaller than its minimum size.
newChildSize.setHeight( minChildSize.height() );
} // (Let the viewport scroll it.)
else if (newSize.width() < minChildSize.width())
{ // Allow room for horizontal scroll bar if needed.
newChildSize.setHeight( newSize.height() -
viewport->horizontalScrollBar()->size().height() );
if (newChildSize.height() < minChildSize.height())
{ // Don't shrink child smaller than its minimum size.
newChildSize.setHeight( minChildSize.height() );
} // (Let the viewport scroll it.)
}
if (newChildSize != childSize)
{ // Need to resize the child multi-cell canvas.
canvas->sizeTo( newChildSize );
}
}
return false; // Let viewport also process this.
}
SizeHandlerForViewPortWithMultiCell&
SizeHandlerForViewPortWithMultiCell :: handleEventsFor
( IViewPort* viewport )
{
IASSERTPARM( viewport != 0 );
IResizeHandler::handleEventsFor( viewport );
IMultiCellCanvas* canvas =
(IMultiCellCanvas*)IWindow::windowWithHandle
( viewport->viewWindow() );
if (canvas) // Don't leave canvas with 0 size.
{ // Have viewport deal with real size.
canvas->sizeTo( ISize( 1, 1 ));
}
return *this;
}
SizeHandlerForViewPortWithMultiCell&
SizeHandlerForViewPortWithMultiCell :: stopHandlingEventsFor
( IViewPort* viewport )
{
IASSERTPARM( viewport != 0 );
IResizeHandler::stopHandlingEventsFor( viewport );
return *this;
}
IHandler&
SizeHandlerForViewPortWithMultiCell :: handleEventsFor
( IWindow* window )
{ // Private to hide version in IHandler.
window;
ITHROWLIBRARYERROR( IC_MEMBER_ACCESS_ERROR,
IErrorInfo::invalidRequest,
IException::recoverable );
return *this;
}
IHandler&
SizeHandlerForViewPortWithMultiCell :: stopHandlingEventsFor
( IWindow* window )
{ // Private to hide version in IHandler.
window;
ITHROWLIBRARYERROR( IC_MEMBER_ACCESS_ERROR,
IErrorInfo::invalidRequest,
IException::recoverable );
return *this;
}
ΓòÉΓòÉΓòÉ 10.4.2. How Do I Center a Control on a Canvas? ΓòÉΓòÉΓòÉ
Question:
I have a single push button on an ISetCanvas. I then put the ISetCanvas on an
IMultiCellCanvas. How do I center the button horizontally in the cell?
Answer:
You can use a multicell canvas to center a control. Add the control (for
example, a set canvas or single pushbutton) to cell 2, 2. Then mark rows 1 and
3, and columns 1 and 3 as expandable.
Because canvas objects can be nested, you can apply this technique to center a
small control in a row containing another large control.
ΓòÉΓòÉΓòÉ 10.4.3. How Do Tabbing and Cursor Movement Work? ΓòÉΓòÉΓòÉ
Question:
Can the enableTabStop and enableGroup functions work on buttons or entry fields
not owned by the same window? Do these functions effect how the tab key works
in moving the cursor between entry fields?
Answer:
Tabbing and cursor-arrowing work as they do in PM. You can only tab to windows
with the tabStop style. You can only use arrow keys to move around in a group.
A group is defined by giving the first window in the group the group style.
The group ends when the next group is found. All windows in a group must also
have the same parent window.
Tabbing and arrowing are supported by frame windows and canvases. The control
with the keyboard focus must be owned by a frame or canvas (so that frame or
canvas can get the tab or arrow key not processed by the control). The control
must also be a child window of the same frame or canvas (so the frame or canvas
can enumerate child windows to find where to move the input focus to). You can
also tab from a control in one canvas to a sibling window of the canvas or to a
child control of a sibling canvas.
ΓòÉΓòÉΓòÉ 10.4.4. Why Does My Canvas Work with new But Not with Solid Objects? ΓòÉΓòÉΓòÉ
Question:
I can construct children of canvas classes using new, but when I try to
construct them as solid objects as shown in the Open Class Library User's
Guide, I get a SYS3170 or SYS3175 error message. Why?
Answer:
A typical problem of using solid objects rather than pointers for data members
(child windows) of a class is getting the wrong order of construction. Parent
and owner windows must be constructed before their child windows and windows
they own. The order of their construction is dictated by their order in the
class declaration (.hpp file), rather than how they appear in the constructor's
initializer list (the .cpp file).
ΓòÉΓòÉΓòÉ 10.4.5. How Do I Get a Fixed Column Size for an IMultiCellCanvas? ΓòÉΓòÉΓòÉ
Question:
I have a 2-column IMultiCellCanvas that I dynamically build; the contents are
also created dynamically. The first column is an IStaticText with a style of
default and workbreak. I want this text to split to multiple lines if it is
longer than 20 characters. What should I do?
Answer:
IMultiCellCanvas uses the minimum size of the child window to determine the
size that a column or row can be decreased to. Using setColumnWidth will not
allow the column to be made smaller than that amount.
If no minimum size value exists for a window, IMultiCellCanvas calls
calcMinimumSize for that window to obtain the minimum size. For IStaticText,
calcMinimumSize returns the larger of the text length in pixels or the text
limit times the average character width.
To do what you want, you need to set the minimum size of the IStaticText window
yourself, before IMultiCellCanvas queries for the minimum size. For an example
that shows how to do this, click below:
Example
Debugging gridlines were also added to the example because they are useful for
altering window sizes.
ΓòÉΓòÉΓòÉ <hidden> Example of Fixed Column Size in IMultiCell Canvas ΓòÉΓòÉΓòÉ
/**********************************************************************/
/* Sample program */
/**********************************************************************/
//Include IBM UI class headers:
#include <iapp.hpp> //IApplication Class
#include <iframe.hpp> //Include IFrameWindow Class Header
#include <imcelcv.hpp>
#include <ientryfd.hpp>
#include <istattxt.hpp>
#define IDC_WINDOW 0x1000
#define IDC_TEST 0x1001
#define IDC_CONTROL1 0x1002
#define IDC_CONTROL2 0x1003
/**********************************************************************/
/* main - Application entry point */
/**********************************************************************/
void main()
{
/********************************************************************/
/* Create a main frame window on the desktop */
/********************************************************************/
IFrameWindow mainWindow( "Sample MCV", IDC_WINDOW );
/********************************************************************/
/* Create a multicell canvas with the frame as owner & parent */
/* */
/********************************************************************/
IMultiCellCanvas testMCV( IDC_TEST, &mainWindow, &mainWindow,
IRectangle(), IMultiCellCanvas::gridLines |
IMultiCellCanvas::dragLines |
IWindow::visible );
/********************************************************************/
/* Create 2 controls for placing into the multicell */
/********************************************************************/
IStaticText *stControl1 = new IStaticText ( IDC_CONTROL1,
&testMCV, &testMCV, IRectangle(),
IStaticText::left |
IStaticText::top |
IStaticText::wordBreak |
IStaticText::fillBackground |
IWindow::visible);
IEntryField *efControl2 = new IEntryField( IDC_CONTROL2,
&testMCV, &testMCV, IRectangle(),
IEntryField::defaultStyle() );
/********************************************************************/
/* Set the text of each of these controls after setting minimum */
/* size of the static text field */
/********************************************************************/
stControl1->setMinimumSize( ISize( 70, 20 ));
stControl1->setText("Control #1 test ... this one wraps");
efControl2->setText("Control 2");
/********************************************************************/
/* Now place them into the multi-cell and adjust columns */
/********************************************************************/
testMCV.addToCell( stControl1, 2,2, 1,1);
testMCV.addToCell( efControl2, 4,2, 1,1);
testMCV.setColumnWidth( 2, 20, false);
testMCV.setColumnWidth( 4, 80, true);
testMCV.setRowHeight( 2, 20, true);
testMCV.refresh();
/********************************************************************/
/* Make the created text field the client of the frame window, */
/* change focus to the frame and show it. */
/********************************************************************/
mainWindow.setClient(&testMCV);
mainWindow.setFocus();
mainWindow.show();
/********************************************************************/
/* Run the application as built */
/********************************************************************/
IApplication::current().run();
return;
}
ΓòÉΓòÉΓòÉ 10.4.6. Does Changing the Minimum Size Affect Control Behavior? ΓòÉΓòÉΓòÉ
Question:
If I use minimumSize to get the minimum size of a control, and then set the
minimum size of this same control to that value, is the control's behavior
affected?
Answer:
Yes. Querying the minimumSize and then setting this value as the minimum size
does change the behavior. Once the minimumSize has been set, that value is
always used; for example, if the font or text limit changes, the minimumSize
does not change. If the minimumSize is not set, changes to the control (such
as font or text limit) may cause the control to have a different minimum size.
You can call IWindow::resetMinimumSize to cause a window to discard the effects
of any previous calls to IWindow::setMinimumSize.
ΓòÉΓòÉΓòÉ 10.4.7. How Do I Draw Separator Lines in an IMultiCellCanvas? ΓòÉΓòÉΓòÉ
Question:
How do I draw a horizontal separator line between cells of a multicell canvas?
Is there a control that can be used across all the cells of the canvas?
Answer:
You could use an IStaticText and set it to the background color of the
separator you want and a small minimum size. The height of the minimum size
would be used as the thickness of a horizontal line. The minimum width would
not be important because the length of the line would be stretched by the
columns it occupies. This solution does require that you place IStaticText
objects in each of the cells of the IMultiCellCanvas where you want separators
to appear.
ΓòÉΓòÉΓòÉ 10.4.8. Why Doesn't removeFromCell Remove the Window Text? ΓòÉΓòÉΓòÉ
Question:
I am using IMultiCellCanvas::removeFromCell to remove windows from my multicell
canvas that were added using IMultiCellCanvas::addToCell. However, the window
text associated with the removed window remains visible in the multicell
canvas, even after I call IWindow::refresh. Why?
Answer:
The library does not delete the child window after you call removeFromCell. As
a result, the child window still exists, but is never resized or repositioned
when the layout of the canvas changes. For this reason, if you are not adding
the child window to a different cell, you should either delete it, hide it, or
change its parent to the object window so it does not remain in the canvas.
Note that keyboard navigation can also be affected by the child window.
ΓòÉΓòÉΓòÉ 10.4.9. How Many Windows Does IViewPort Have? ΓòÉΓòÉΓòÉ
Question:
Are there more windows to an IViewPort than just a canvas and some scroll bars?
Answer:
Yes. A viewport has an additional window that is not obvious. Basically, it is
an ICanvas that clips your view window so it does not overwrite the scrollbars.
(The viewport makes the parent window of your view window the view rectangle.)
The window IDs of these child windows are defined in <icconst.h>.
ΓòÉΓòÉΓòÉ 10.4.10. How Do I Align an IComboBox in an IMultiCellCanvas? ΓòÉΓòÉΓòÉ
Question:
I have a multicell canvas with a DropDownList combo box between two entry
fields, but the combo box does not align correctly. I want the combo box to
occupy a single line, and when I open it, to cover the second entry field.
Instead, it takes extra lines. How can I get the box to take less space until
it's opened?
Answer:
For a drop-down or read-only-drop-down combo box, you should have the combo box
only occupy one row. This is the row that its entry field and drop-down button
will appear in. The size of the drop-down list should be controlled with the
IComboBox::setMinimumRows function. The list box will appear over rows below
the combo box, and could even stretch below the bottom of the multi-cell
canvas.
ΓòÉΓòÉΓòÉ 10.5. Container Control ΓòÉΓòÉΓòÉ
This section discusses the IContainerControl class and related classes.
Why Aren't Objects Sorted in Icon View?
How Do I Insert a Container Object as the First Object?
What Does extendedSelection Mean?
What Happens to Child Objects when an Object is Removed?
How Many Objects Can I Have in a Container?
Can I Use Small Icons in an IContainerControl?
Why Doesn't My Pop-Up Menu Work?
How Can I Wrap Text in Columns or Column Headings?
How Should I Handle Date and Time in a Container?
How Do I Access Members of a Derived IContainerObject?
Why Doesn't My Container Display?
Can I Display Items in Tree View on User Request?
Why Are All Container Objects Deleted from a Tree View?
Can I Have Two Instances of the Same Object in a Container?
ΓòÉΓòÉΓòÉ 10.5.1. Why Aren't Objects Sorted in Icon View? ΓòÉΓòÉΓòÉ
Question:
I have a sort function for a container that works correctly when the container
is in tree or details view. However, when it is in icon view, the container is
not refreshed until arrangeIconView is called or the view type is changed. Do I
have to call arrangeIconView after sorting an icon view? If so, why?
Answer:
By default, the arrangement of the icon view is independent of the order of the
objects in the container. This is to preserve any user arrangement of the
objects through direct manipulation or any positioning that might have been
done on insertion. If you always want the icon view to be sorted, you can
either specify the IContainerControl::autoPosition style for the container or
call arrangeIconView after the sort.
ΓòÉΓòÉΓòÉ 10.5.2. How Do I Insert a Container Object as the First Object? ΓòÉΓòÉΓòÉ
Question:
I want to be able to add IContainerObjects to my container. I know I can use
addObject and addObjectAfter to add IContainerObjects to my container after a
specified object. How do I add an object as the first object in the container?
Answer:
To add an object at the beginning of the container, specify 0 as the second
argument to addObjectAfter or addObjectsAfter. For example:
addObjectAfter(newObject, 0);
ΓòÉΓòÉΓòÉ 10.5.3. What Does extendedSelection Mean? ΓòÉΓòÉΓòÉ
Question:
What does the IContainerControl::Style extendedSelection mean?
Answer:
Extended selection is an enhanced form of single selection you can use to
select discontinuous ranges of objects. For example, you use extended selection
when you select objects in an OS/2 Workplace Shell folder.
Extended selection works like single selection unless you use shift or control
keys. The control key allows discontinuous selection like multiple selection.
The shift key allows range selection as an editor would.
If the user of your container should only be able to select one object, use
single selection. If the user would typically select many objects, use multiple
selection. If the user would typically select one object, but could optionally
select more, use extended selection.
ΓòÉΓòÉΓòÉ 10.5.4. What Happens to Child Objects when an Object is Removed? ΓòÉΓòÉΓòÉ
Question:
In my tree view container, I have an object with two child objects. If I remove
the object, the two child objects are also removed. If I delete the object,
what happens to the child objects?
Answer:
When you remove or delete an object from a container in tree view, all of its
child objects are also removed or deleted.
ΓòÉΓòÉΓòÉ 10.5.5. How Many Objects Can I Have in a Container? ΓòÉΓòÉΓòÉ
Question:
Is there a limit on the number of container objects I can add to a container?
Answer:
IContainerControl imposes no limit other than that set by the underlying
container control.
In the OS/2 implementation, the maximum number of records is limited by the
amount of memory in the computer. The container control does not limit the
number of records that a container can have.
In the Motif implementation, there is a limit of approximately 1050 records
that can be displayed in a one-dimensional view such as details or tree. (The
reason is that position values in the X Intrinsics use a signed 16-bit value.)
To work around this limitation, limit the number of objects displayed at any
one time.
ΓòÉΓòÉΓòÉ 10.5.6. Can I Use Small Icons in an IContainerControl? ΓòÉΓòÉΓòÉ
Question:
For my container's tree icon view, can I use small icons like the small size
OS/2 desktop icons?
Answer:
Version 3.0 supports a new style, IContainerControl::miniIcons, that uses
mini-icons. These are similar to the Workplace Shell small icons. Also refer
to the function IContainerControl::showMiniIcons.
ΓòÉΓòÉΓòÉ 10.5.7. Why Doesn't My Pop-Up Menu Work? ΓòÉΓòÉΓòÉ
Question:
Why doesn't the pop-up menu for my container work correctly?
Answer:
Here are some tips on pop-up menus:
When you create a menu handler class for a container, derive it from
ICnrMenuHandler instead of IMenuHandler.
Remember that an object is not selected by the manipulation mouse button
(right mouse-button click). What is shown visually is source emphasis.
You must keep track of the pop-up menu object yourself. Store the pointer
to the object returned by popupMenuObject, and use this pointer to
process a pop-up menu event for that object.
In your command handler, make sure you differentiate between commands
invoked from the pop-up menu and those invoked from the menu bar. A
pop-up menu should use the popupMenuObject; a menu-bar menu should use
selected objects. You can use different command IDs for the pop-up and
menu bar.
You can also create a pop-up menu for the container itself if the pop-up
is requested when the pointer is not over an object. In this case,
popupMenuObject returns 0.
ΓòÉΓòÉΓòÉ 10.5.8. How Can I Wrap Text in Columns or Column Headings? ΓòÉΓòÉΓòÉ
Question:
Can I make the text in my container columns wrap to the next line? Can I create
container column headings that are more than one line?
Answer:
Yes to both questions. Insert new-line characters in the text where you want
line breaks.
For the column heading, you can use \x0a in a STRINGTABLE resource. For
example:
TXT_HEAD1 "Line1\x0aLine2"
Then when you build the container:
col->setHeadingText (TXT_HEAD1);
The following alternative also works:
col->setHeadingText ("Line1\nLine2");
To wrap the text in the column, put a new-line character (\n) in the string
where you want it to wrap to the next line. For example:
Column1 Column2 Column3 Textdata\n something\n
for this\n goes here\n
goes \n for test
here
The text string for the fourth column would be:
"Textdata\nfor this\ngoes \nhere"
ΓòÉΓòÉΓòÉ 10.5.9. How Should I Handle Date and Time in a Container? ΓòÉΓòÉΓòÉ
Question:
How should I use IDate and ITime to correctly handle date and time values in a
container?
Answer:
The natural data type for a date in a container is a CDATE, defined in
<pmstddlg.h>. Declare your date data member as a CDATE object. When you need to
perform arithmetic operations on the value, construct an IDate object from the
CDATE type. You can also convert from IDate to CDATE using the asCDATE
function.
For time, declare your member as a CTIME object, and construct an ITime object
when you need to perform operations on the value.
Alternatively, you can store the date and time information in the container as
strings, and then convert the values using the asString functions of IDate and
ITime.
ΓòÉΓòÉΓòÉ 10.5.10. How Do I Access Members of a Derived IContainerObject? ΓòÉΓòÉΓòÉ
Question:
The IContainerControl functions to access objects all return IContainerObject
pointers. How do I access functions defined in a class derived from
IContainerObject?
Answer:
Cast the IContainerObject pointer to a pointer to your object. For example:
MyObject* object = (MyObject*)container.objectAt(1);
object->myFunction();
ΓòÉΓòÉΓòÉ 10.5.11. Why Doesn't My Container Display? ΓòÉΓòÉΓòÉ
Question:
I'm trying to use a group box to provide a border for a container, but the
container is not being drawn. Why?
Answer:
Containers will not paint over a sibling window that overlaps and lies on top
of the container, even if the sibling window does not paint that portion of the
screen (such as group boxes and outline boxes, which do not paint their
interiors, and combination boxes, which do not paint where their drop-down list
boxes will be displayed).
Create the container first, and then the group box, so that the container lies
on top of the group box.
ΓòÉΓòÉΓòÉ 10.5.12. Can I Display Items in Tree View on User Request? ΓòÉΓòÉΓòÉ
Question:
I want to partially fill my tree view container and indicate that more items
exist, then display those items only when the user selects that branch of the
tree. How can I do this?
Answer:
You can get a list of the top-level objects in the tree and insert each one
into the container using
cnr->addObject(topLevelObject);
To provide a visual indication (such as a plus sign) that the tree can be
expanded, add a dummy child object to each of the expandable top-level objects.
For example:
cnr->addObject(dummy, topLevelObject);
To be able to expand the tree with real objects when the user selects it, add a
container handler (ICnrHandler) to the container and override the
IContainerObject::handleTreeExpanded member function in your container object
class. This member function is called by the ICnrHandler whenever an object is
expanded. In this function, delete the dummy object and add the real objects.
Once you have expanded the tree, set a flag so you don't expand it again.
Return FALSE and let the default action occur if the level is already expanded.
The object is really already expanded when handleTreeExpanded is called.
However, the technique above works because the container is repainted when you
add or remove objects.
ΓòÉΓòÉΓòÉ 10.5.13. Why Are All Container Objects Deleted from a Tree View? ΓòÉΓòÉΓòÉ
Question:
When I call deleteSelectedObjects for a tree view of a container, it deletes
all objects, not just the selected one. I also noticed that the Select All and
Deselect All menu choices for tree views are disabled. Why?
Answer:
The behavior you are seeing is a restriction on the PM container control. In a
tree view, only one object can be selected at any time and there must be one
object selected. That is the reason you can't select or deselect all objects in
a tree view.
The deleteSelectedObjects function deletes the currently selected object.
Because there must always be a selected object in a tree view, the next object
in the tree view gets selected. The deleteSelectedObjects function then detects
another selected object and deletes it, causing the next object to be selected.
The cycle continues until all objects are deleted.
ΓòÉΓòÉΓòÉ 10.5.14. Can I Have Two Instances of the Same Object in a Container? ΓòÉΓòÉΓòÉ
Question:
Can I add the same IContainerObject to an IContainerControl twice?
Answer:
No, you cannot add the same container object twice. PM maintains pointers to
place the record in the container relative to other records, and does not allow
the same record to be added twice.
Instead, use the IContainerObject copy constructor to create another instance
of your container object, and add that to the container.
ΓòÉΓòÉΓòÉ 10.6. Text and Button Controls ΓòÉΓòÉΓòÉ
This section discusses ITextControl and classes derived from it.
How Do I Limit the Character Type for an IEntryField?
How Do I Search for Text in an IMultiLineEdit Control?
Can I Append to a File using an IMultiLineEdit Control?
How Does IRadioButton::selectedIndex Work?
Why Can't I Disable Refreshing for an IMultiLineEdit Control?
ΓòÉΓòÉΓòÉ 10.6.1. How Do I Limit the Character Type for an IEntryField? ΓòÉΓòÉΓòÉ
Question:
I want to have a numeric-only entry field, a time-format entry field (hh:mm),
and a date format entry field (mm/dd/yy). How can I do this?
Answer:
For a numeric-only entry field, create an IKeyboardHandler. In
characterKeyPress, check for the characters 0 through 9. If the value is other
than those characters, return TRUE and the non-numeric input will be ignored.
Depending on how your user interface works, you may also want to override the
entry field's paste and setText functions so they cannot be used to enter
non-numeric text.
To create a formatted field such as time, date, or currency, you need an
IEditHandler in addition to the IKeyboardHandler. The IEditHandler is used to
format the string correctly each time an acceptable character is received.
An uppercase-only entry field is similar to the numeric entry field, except
that you want to change the lowercase keyboard events to uppercase ones. To do
this, discard the lowercase keyboard event by calling setResult(true) for the
event and returning TRUE from the characterKeyPress function. Then construct a
new keyboard event with the appropriate uppercase value and send the new event
to the entry field. Your keyboard handler will also be called for this new
event, so ensure it ignores valid values; otherwise you may enter a loop. For
example:
Boolean MyHandler :: characterKeyPress(IKeyboardEvent& keyEvt)
{
char cTest = keyEvt.character();
if ( islower(cTest) )
{
cTest &= '\xDF'; //make upper case
keyEvt.window()->postEvent(IWindow::character,
keyEvt.parameter1(),
cTest);
return true;
}
return false;
}
ΓòÉΓòÉΓòÉ 10.6.2. How Do I Search for Text in an IMultiLineEdit Control? ΓòÉΓòÉΓòÉ
Question:
Is there a find or search function for locating text in an IMultiLineEdit
control?
Answer:
For a forward text search, use the text function to copy the IMultiLineEdit
content, beginning at the line where the cursor is, to an IString object. Then
search the resulting IString to find the index where the string is found. Use
the index from the IString search to highlight the found string in the
IMultiLineEdit control.
ΓòÉΓòÉΓòÉ 10.6.3. Can I Append to a File using an IMultiLineEdit Control? ΓòÉΓòÉΓòÉ
Question:
Is there a way to append to an existing file using the exportToFile function or
some other function of the IMultiLineEdit control?
Answer:
The exportToFile function opens the file for writing and will overwrite your
existing file. Instead, try the following:
IString alltext = mle.selectRange().selectedText();
Then append alltext to the file yourself.
ΓòÉΓòÉΓòÉ 10.6.4. How Does IRadioButton::selectedIndex Work? ΓòÉΓòÉΓòÉ
Question:
The IRadioButton::selectedIndex function returns incorrect values when there
are controls other than radio buttons in the window. Why?
Answer:
The index includes all windows that are of the group, not just radio buttons.
The group should include only radio buttons to get the expected results.
ΓòÉΓòÉΓòÉ 10.6.5. Why Can't I Disable Refreshing for an IMultiLineEdit Control? ΓòÉΓòÉΓòÉ
Question:
I call disableRefresh to disable refreshing for my IMultiLineEdit control.
Then when I add lines, the refresh still occurs. Why?
Answer:
The User Interface classes use MLM_IMPORT to add text to the multiline edit
field (MLE). MLM_IMPORT requires that a null character be the last character
added, so the class library adds this extra character to the MLE along with
your text. The library then calls MLM_DELETE to delete the extra null
character, and MLM_DELETE sends an MLM_ENABLEREFRESH message to the MLE. As a
result, refresh is always enabled when you add text. Even if a handler prevents
MLM_ENABLEREFRSH from going to the MLE after a delete operation, the screen
text is updated.
To prevent the MLE from showing updates as they are made, call the IWindow
virtual function enableUpdate with the appropriate Boolean value. For example:
mle.IWindow::enableUpdate(false);
// add text to mle here
mle.IWindow::enableUpdate(true);
ΓòÉΓòÉΓòÉ 10.7. Listbox and Combobox Controls ΓòÉΓòÉΓòÉ
This section discusses topics related to the list controls IListBox and
IComboBox.
Why Don't I See Events from My IComboBox?
What Is the Limit on the Amount of Data in a Listbox?
Can I Determine the Height of a Listbox Item?
ΓòÉΓòÉΓòÉ 10.7.1. Why Don't I See Events from My IComboBox? ΓòÉΓòÉΓòÉ
Question:
I defined a class that inherits from IComboBox and IKeyboardHandler to
intercept keystrokes within the entry field of the combo box. It seems the
IKeyboardHandler is never invoked even though the constructor calls
handleEventsFor(this). What is the problem?
Answer:
The combo box is causing you problems because it is a composite control,
meaning that it is implemented with child controls: a child entry field and
listbox. The keystrokes you don't see are being processed by the child entry
field. To process these keystrokes, you need to construct an IEntryField for
this child entry field, and attach the keyboard handler to this window. For
example:
IComboBox comboBox( ... );
IEntryField childEF( CBID_EDIT, &comboBox ); //CBID_EDIT is in pmwin.h
MyKeyboardHandler keyhdr;
keyhdr.handleEventsFor( &childEF );
ΓòÉΓòÉΓòÉ 10.7.2. What Is the Limit on the Amount of Data in a Listbox? ΓòÉΓòÉΓòÉ
Question:
I have a listbox that could contain a large number of elements. Is there a
limit to how many elements I can add?
Answer:
In OS/2 2.x, there is a limit of 64K of heap space per frame window for all
controls. The list box data is allocated out of this space. The limitation is
really on the amount of data, not the number of elements.
In OS/2 Warp, the limit is 32K entries.
One possible solution is to use a container in details view instead of the
listbox.
ΓòÉΓòÉΓòÉ 10.7.3. Can I Determine the Height of a Listbox Item? ΓòÉΓòÉΓòÉ
Question:
Is there a way to determine the cell height or the number of displayable items
for a given listbox?
Answer:
No. PM does not make available either the height of a row or the number that
are currently visible in a listbox.
ΓòÉΓòÉΓòÉ 10.8. Notebook Control ΓòÉΓòÉΓòÉ
This section discusses topics related to the INoteBook class.
How Do I Change the Appearance of INotebook Tabs?
Why Isn't My IPageHandler::drawTab Function Called?
How Can I Display Page Numbers in a Notebook?
How Can I Get the Correct Size for a Notebook?
ΓòÉΓòÉΓòÉ 10.8.1. How Do I Change the Appearance of INotebook Tabs? ΓòÉΓòÉΓòÉ
Question:
What can I do to change the appearance of INotebook tabs?
Answer:
To change the size of the notebook tabs, use INotebook::setMajorTabSize and
INotebook::setMinorTabSize. Note, however, that all tabs in a notebook must be
the same size. You can control the location of the tabs with the
INotebook::setOrientation function and through INotebook styles. To change the
color of all the tabs in a notebook, use INotebook::setColor.
If you want to change the color of some but not all tabs (for example, as an
indicator that a page has been changed), you must draw the tabs yourself using
IPageHandler::drawTab. You also have to draw the tabs yourself if you want to
have multiline tab text.
ΓòÉΓòÉΓòÉ 10.8.2. Why Isn't My IPageHandler::drawTab Function Called? ΓòÉΓòÉΓòÉ
Question:
The drawTab function for my IPageHandler is not called. Why?
Answer:
If you call either setTabText or setTabBitmap for a page, the PM notebook
control draws the tab and does not call your drawTab function. This behavior is
determined by PM.
To ensure your drawTab function is called, do not call either setTabText or
setTabBitmap for the page.
ΓòÉΓòÉΓòÉ 10.8.3. How Can I Display Page Numbers in a Notebook? ΓòÉΓòÉΓòÉ
Question:
How can I display page numbers on my notebook pages, such as Page 1 of 3, Page
2 of 3, and so on?
Answer:
You can use INotebook::setStatusText to implement page numbers as status text
on the notebook page. If you want the page numbers aligned to one side, use
INotebook::setStatusTextAlignment as well.
You will need to specify the statusTextOn attribute when you construct the
IPageSettings object that you use to insert pages.
ΓòÉΓòÉΓòÉ 10.8.4. How Can I Get the Correct Size for a Notebook? ΓòÉΓòÉΓòÉ
Question:
I have a notebook that contains a multicell canvas with an expandable margin.
When I request the minimum notebook size after the pages are loaded, but before
the canvas is filled, I get unusual values from INotebook::pageSize and
INotebook::notebookSize.. A sizeTo of the frame window creates a 1x.75 inch
window. What am I doing wrong?
Answer:
When you call INotebook::pageSize, the size of the notebook is still (0, 0), so
the size needed by a page window to fit into a notebook would have to be even
smaller. When you call INotebook::notebookSize, the page window is still sized
to (0, 0), and that is the reason your notebook has such a small size.
After adding page windows to your notebook, you can size the frame based on the
size of the notebook client window:
frame.moveSizeToClient( IRectangle( IFrameWindow::nextShellRect()
.bottomLeft(),
notebook.minimumSize() );
ΓòÉΓòÉΓòÉ 10.9. Other Controls ΓòÉΓòÉΓòÉ
This section discusses topics related to the IMessageBox, ISpinButton, and
ISlider classes.
Why Don't I See Events from My ISpinButton?
Why Does My IProgressIndicator Not Display Correctly?
Can I Use IMessageBox without a Main Application Window?
What Is an IMessageBox Modal To?
ΓòÉΓòÉΓòÉ 10.9.1. Why Don't I See Events from My ISpinButton? ΓòÉΓòÉΓòÉ
Question:
I have a class that inherits from ISpinButton and IKeyboardHandler, and
overrides the key function to intercept characters other than 0-9 and '.'. But
when I enter a character, it appears in the entry field part of the control
before the key function runs. Also, the key event that I receive is not a
character (isCharacter returns FALSE). Why does this happen?
Answer:
The spin button is a composite control with an entry-field child window.
You need to attach the keyboard handler to the spin button's entry-field child
window. The spin button itself receives only the keystrokes that the entry
field doesn't process (like noncharacter keys and key releases).
To attach the keyboard handler to the entry field, you must first construct an
IEntryField for the entry field.
In OS/2 2.0 and above, you can take advantage of the fact that the spin button
creates its child entry field with the same window ID that it uses, for
example:
unsigned long ID = spinButton->id();
IEntryField* spinEntry = new IEntryField( id, spinButton );
ΓòÉΓòÉΓòÉ 10.9.2. Why Does My IProgressIndicator Not Display Correctly? ΓòÉΓòÉΓòÉ
Question:
When I add an IProgressIndicator to a multicell canvas and then size the window
to its minimum size, the tick text associated with the progress indicator scale
is clipped at both ends of the scale. Why?
Answer:
The calcMinimumSize for IProgressIndicator (and ISlider) returns (30,100) or
(100,30), depending on the shaft orientation. Depending on your application and
the styles you are using, you may need to call setMinimumSize to establish a
different size for the control.
ΓòÉΓòÉΓòÉ 10.9.3. Can I Use IMessageBox without a Main Application Window? ΓòÉΓòÉΓòÉ
Question:
I need to display a message box for my application before my main window is
created. How can I do that?
Answer:
You can use IMessageBox and pass 0 for the window owner. Note, however, that
without a window owner, you cannot provide help for the message box.
ΓòÉΓòÉΓòÉ 10.9.4. What Is an IMessageBox Modal To? ΓòÉΓòÉΓòÉ
Question:
I have an application with two frame windows. When I create an IMessageBox for
frame window 1 with the applicationModal style, the message box is not modal
with respect to frame window 2. Why?
Answer:
A message box is only application-modal to its owner. In your example, the
message box is modal relative to frame window 1, and your other frame windows
can receive input focus.
ΓòÉΓòÉΓòÉ 10.10. Menus ΓòÉΓòÉΓòÉ
This section discusses menus, including pop-up or context menus.
Why Don't the IMenuItem Functions Affect My Menu?
Where Should I Call setAutoDeleteObject for Pop-up Menus?
How Can I Change the Font of a Pop-up Menu?
ΓòÉΓòÉΓòÉ 10.10.1. Why Don't the IMenuItem Functions Affect My Menu? ΓòÉΓòÉΓòÉ
Question:
I can use IMenu::enableItem and IMenu::disableItem to enable and disable my
menu items, but IMenuItem::setDisabled and IMenuItem::setSelectable do not
work. Why?
Answer:
The key point to remember about the IMenuItem functions is that they do not
affect the menu unless the IMenu add or set functions are called with the
instance of the menu item.
To set the styles or attributes of an existing menu item, you must use the
IMenu functions such as enableItem and checkItem.
You can also manipulate an IMenuItem object that represents a menu item within
the existing menu, and then call IMenu::setItem to replace the styles or
attributes of that item with those you specify for the IMenuItem object.
ΓòÉΓòÉΓòÉ 10.10.2. Where Should I Call setAutoDeleteObject for Pop-up Menus? ΓòÉΓòÉΓòÉ
Question:
I create a pop-up menu with makePopUpMenu. To delete it correctly, can I call
setAutoDeleteObject from makePopUpMenu, or do I have to override menuEnded and
call setAutoDeleteObject from there?
Answer:
If you want the library to delete your pop-up menu, call setAutoDeleteObject in
makePopUpMenu. Note that to do this, you must have created the pop-up menu with
operator new.
ΓòÉΓòÉΓòÉ 10.10.3. How Can I Change the Font of a Pop-up Menu? ΓòÉΓòÉΓòÉ
Question:
When I change the font in a container, the pop-up menus for objects in the
container inherit the font change. How can I change the fonts of the pop-up
menus?
Answer:
Fonts are inherited from the owner chain. If you don't want the pop-up menu to
inherit from the container, change the owner of the pop-up menu from the
container to the frame window.
ΓòÉΓòÉΓòÉ 10.11. Creating Help with IHelpWindow ΓòÉΓòÉΓòÉ
This section discusses providing application help using IHelpWindow and other
classes.
How Do I Create Help for Child or Secondary Windows?
How Does IMessageBox Help Work?
How Do I Customize Help for IFileDialog?
ΓòÉΓòÉΓòÉ 10.11.1. How Do I Create Help for Child or Secondary Windows? ΓòÉΓòÉΓòÉ
Question:
I have two help subtables, one for my main window and one for a dialog. An
IHelpWindow is associated with the main window and an IHelpHandler is attached
to the main window. The help works for the main window, but not for the dialog.
How do I fix this?
Answer:
If your dialog is a secondary window (its parent window is the desktop), then
Help Manager should be able to locate the correct help subtable for its
contextual and/or general help. However, you should use
IHelpWindow::associateWindow to associate the IHelpWindow used by the main
window with your secondary dialog. Then when you dismiss the help window, focus
returns to the dialog instead of the primary window, and when you dismiss the
dialog, the help window is automatically dismissed. Once you add the
associateWindow, you will also need to add the same help handler to the dialog
because all help notification messages will be sent to the associated window.
If your dialog is a child window, use the IHelpWindow::setActiveWindow function
to identify the child frame window as the active help window. Without this
call, Help Manager will use the wrong frame window when searching the help
tables.
ΓòÉΓòÉΓòÉ 10.11.2. How Does IMessageBox Help Work? ΓòÉΓòÉΓòÉ
Question:
I am trying to display a message box with a help button on it. The IMessageBox
documentation says, if you have helpID, the help button will display, but it
does not say anything about the help file to load the help from. What does
IMessageBox do?
Answer:
IMessageBox uses the same IHelpWindow that its owner window uses and
consequently the same help library file.
ΓòÉΓòÉΓòÉ 10.12. Application and Resources ΓòÉΓòÉΓòÉ
This section discusses general application topics and how to use resources and
and resource libraries.
How Should I Use IResourceLock and ISemaphoreHandle?
What Does IDynamicLinkLibrary Do If the DLL Is Not Found?
How Do I Get the Anchor Block (HAB) of a Thread?
Which Classes Can I Use in a Non-GUI Application?
Can I Dynamically Load Resources from a DLL?
How Can I Specify a New-Line Character in a Resource File?
How Does the Library Choose between Multiple Icons?
Can I Dynamically Load Bitmaps and Icons That Aren't Resources?
How Do I Load a String Resource into an IString?
ΓòÉΓòÉΓòÉ 10.12.1. How Should I Use IResourceLock and ISemaphoreHandle? ΓòÉΓòÉΓòÉ
Question:
How should I use ISemaphoreHandle and IResourceLock?
Answer:
The easiest way to lock resources is to use the IResourceLock class. Create a
static instance of IPrivateResource or ISharedResource. When you need to lock
the resource, create a local instance of IResourceLock that exists during the
time you need the resource to be locked. For example:
static IPrivateResource collectionResource;
// ...
{
// set lock
IResourceLock reslock(collectionResource);
// ... do serialized tasks here
} // lock freed on scope exit and destruction of reslock object
In OS/2, IResourceLock uses mutex semaphores to implement the locking.
The User Interface class library does not support direct user of OS/2 event
semaphores, but you can use ISemaphoreHandle as an alias for the PM HEV and
HMTX types on the OS/2 API calls.
ΓòÉΓòÉΓòÉ 10.12.2. What Does IDynamicLinkLibrary Do If the DLL Is Not Found? ΓòÉΓòÉΓòÉ
Question:
What does the IDynamicLinkLibrary constructor do if the DLL specified in the
input character string cannot be found?
Answer:
The IDynamicLinkLibrary class will throw an IAccessError exception if it cannot
find and load the DLL specified.
ΓòÉΓòÉΓòÉ 10.12.3. How Do I Get the Anchor Block (HAB) of a Thread? ΓòÉΓòÉΓòÉ
Question:
How can I determine the anchor block handle (HAB) of the current thread?
Answer:
You can determine the anchor block handle with the following function call:
IAnchorBlockHandle hab = IThread::current().anchorBlock();
ΓòÉΓòÉΓòÉ 10.12.4. Which Classes Can I Use in a Non-GUI Application? ΓòÉΓòÉΓòÉ
Question:
Are there any User Interface classes that I can use in a non-GUI application?
Answer:
For applications that do not have a graphical interface, you can use the
following classes from the User Interface class library:
IBase
IVBase
ITrace
IErrorInfo and derived classes (except IGUIErrorInfo and IXLibErrorInfo)
IString, I0String and related classes
IDate
ITime
IBitFlag
IPoint and derived classes
IRectangle
IResource and IResourceLock
IProcedureAddress
IDynamicLinkLibrary
IApplication and ICurrentApplication (non-GUI functions only)
IThread and ICurrentThread (non-GUI functions only)
The other libraries in IBM Open Class (I/O Stream, Complex, Collection,
Database Access, and Data Type and Exception) are also available to all C++
applications.
ΓòÉΓòÉΓòÉ 10.12.5. Can I Dynamically Load Resources from a DLL? ΓòÉΓòÉΓòÉ
Question:
Is there a way I can load resources (like icons) and dialogs dynamically from a
DLL without having to use setUserResourceLibrary and setResourceLibary?
Answer:
Most of the functions in the library that use resource IDs accept them in the
form of an IResourceId. If you provide an unsigned long value for this
argument, the resource is loaded from the default resource library set by
ICurrentApplication::setUserResourceLibrary. However, you can explicitly create
the IResourceId to refer to a specific resource library. For example,
textctl.setText( IResourceId( 1000, IDynamicLinkLibrary("mydll") ) );
would set the text to the value of resource ID 1000 from mydll.dll.
ΓòÉΓòÉΓòÉ 10.12.6. How Can I Specify a New-Line Character in a Resource File? ΓòÉΓòÉΓòÉ
Question:
When I call myResLib.loadString for my message, it doesn't remove the new-line
(\n) characters from the message string in my string table. Should I specify
new-line characters a different way?
Answer:
This is the usual behavior of the PM WinLoadString function, which is used to
load the string. To get around it, use \x0d instead of \n in the string in the
resource file.
ΓòÉΓòÉΓòÉ 10.12.7. How Does the Library Choose between Multiple Icons? ΓòÉΓòÉΓòÉ
Question:
When there is more than one version or size of a bitmap or icon, what rules are
used to choose which one is displayed?
Answer:
PM chooses the icon or bitmap whose format most closely matches the target
display device. When you design your icons and bitmaps, you should provide and
test formats for each anticipated target display device.
ΓòÉΓòÉΓòÉ 10.12.8. Can I Dynamically Load Bitmaps and Icons That Aren't Resources? ΓòÉΓòÉΓòÉ
Question:
Can I dynamically load and display a bitmap or icon file dynamically without
binding it as a resource?
Answer:
You can use the PM function WinLoadFileIcon to load icons. In Version 3.0 of
the class library, you can also use the IGBitmap class to dynamically load
bitmaps and icons, as well as other image file types such as .GIF.
The DMSAMP.CPP file in the DRAG2 sample (shipped with VisualAge C++) contains
code that loads a bitmap from an icon.
ΓòÉΓòÉΓòÉ 10.12.9. How Do I Load a String Resource into an IString? ΓòÉΓòÉΓòÉ
Question:
How do I load a string resource into an IString object?
Answer:
Use the IApplication::current().userResourceLibrary().loadString function and
pass it the ID of the string resource. For example:
IString string;
string = IApplication::current().userResourceLibrary().loadString(id);
ΓòÉΓòÉΓòÉ 10.13. Threads ΓòÉΓòÉΓòÉ
This section discusses how to use the IThread class and related topics.
Is There an Example of Using IThread and IThreadFn?
How Do I Start A Thread?
When Is a PM Message Queue Allocated for a Thread?
How Do I Open a Window on a Secondary Thread?
Can I Create Child Windows in Another Thread?
ΓòÉΓòÉΓòÉ 10.13.1. Is There an Example of Using IThread and IThreadFn? ΓòÉΓòÉΓòÉ
Question:
Is there an example that shows how to use IThread and IThreadFn?
Answer:
The MLE sample program shipped with VisualAge C++ shows a simple example using
of IThread and IThreadFn. In addition, OS/2 C++ Class Library: Power GUI
Programming with C Set ++ contains extensive discussion and examples for
IThread and related functions. For more information about this book, see What
Documentation Exists for the User Interface Classes?.
ΓòÉΓòÉΓòÉ 10.13.2. How Do I Start A Thread? ΓòÉΓòÉΓòÉ
Question:
I want to start an asynchronous thread using a function and an unsigned long
argument. How do I start it?
Answer:
There are several ways to start a thread, depending on what you want to use it
for. First decide what code you want to run in the separate thread.
1. If the code matches any of the following, you can use the IThread::start
function directly:
a. A given member function of a given object (with return type void and
no arguments):
// MyClass has member function void foo()
IThread thread;
thread.start( new IThreadMemberFn< MyClass >( *this, foo ) )
b. A _System function accepting an unsigned long argument (that you
would start with DosCreateThread in C):
// non-member function declared as
void _System foo( unsigned long arg);
IThread thread;
thread.start( foo );
c. An _Optlink function accepting a void* argument (that you would
start with _beginthread in C):
// non-member function declared as
void _Optlink foo( void* arg);
IThread thread;
thread.start( foo );
2. If the code you want to run does not match the above descriptions, you
must write a "wrapper" using one of the following two techniques:
a. Derive from IThreadFn and implement run to call the desired member
function of your object. This may be difficult because you typically
need to know what additional arguments to pass, and this technique
provides no way to address that requirement. However, it can be more
syntactically elegant: aThread.start(this) instead of aThread.start(
new IThreadMemberFn<T>(*this, T::foobar) ). Also, the lifetime of
this must transcend the lifetime of the thread.
b. Derive a new class from IThreadFn. Add data members for arguments
to the function you want to run, including the object that a member
function might be invoked on. Add a constructor that accepts
references to the arguments as its arguments. Finally, implement
run to dispatch the function you want with the provided arguments.
The MLE sample program shipped with VisualAge C++ provides an
example of this technique. You could alternatively implement the
function you want to run within MyThreadFn::run.
The IThreadFn object is reference-counted so that it can be automatically
deleted when the thread terminates. As a result, if you use IThreadFn or
a derived class, you must allocate the IThreadFn using the new operator
and you must not delete it.
ΓòÉΓòÉΓòÉ 10.13.3. When Is a PM Message Queue Allocated for a Thread? ΓòÉΓòÉΓòÉ
Question:
When I create a thread with IThread, does PM automatically allocate a message
queue for it? If not, when and how does a message queue get allocated?
Answer:
When you start your thread, if you set the second argument (autoInitPM) to
TRUE, it automatically calls initializePM, which in turn calls WinInitialize
and WinCreateMsgQueue to create a message queue.
If you set autoInitPM to FALSE, the thread initializes PM when it first creates
a frame window (or certain other types of window such as IFileDialog). It does
not create a message queue.
If your thread will be sending PM messages, it requires a message queue.
Because many User Interface class library functions interact with controls by
sending messages, it is recommended you create a message queue for your thread
if it deals with any IWindow objects.
ΓòÉΓòÉΓòÉ 10.13.4. How Do I Open a Window on a Secondary Thread? ΓòÉΓòÉΓòÉ
Question:
My application starts a secondary thread that instantiates a window (inherited
from IFrameWindow) to run in that thread. However, after the window is
constructed, the function in the second thread ends and therefore ends the
thread. The window only appears momentarily. How can I prevent the thread
from ending before the user closes the window for that thread?
Answer:
If you open a window on a thread, you must process the PM window messages for
that thread's message queue. The message processing loop keeps your thread
running while simultaneously handling the messages sent to your window.
You can call IThread::current().processMsgs to enter an event loop for the
thread. This is the same as calling IApplication::current().run in your main
thread. The event loop will normally be terminated when the last primary window
on the thread is closed.
Another alternative is to show the frame window modally by using showModally
instead of show. For a frame without an owner, showModally is equivalent to
showing the frame using show followed by the message processing loop.
ΓòÉΓòÉΓòÉ 10.13.5. Can I Create Child Windows in Another Thread? ΓòÉΓòÉΓòÉ
Question:
Can I create the child windows of the frame window in another thread?
Answer:
No. PM window parentage and ownership cannot cross thread boundaries.
ΓòÉΓòÉΓòÉ 10.14. Fonts and Colors ΓòÉΓòÉΓòÉ
This section discusses the usage of the IFont and IColor classes.
How Can I Detect Font or Color Changes in a Window?
How Can I Save Font Information?
Why Do I Get an Incorrect Font?
ΓòÉΓòÉΓòÉ 10.14.1. How Can I Detect Font or Color Changes in a Window? ΓòÉΓòÉΓòÉ
Question:
Is there a way to determine when the font or color of a window has changed as
the result of a drag/drop operation?
Answer:
When the font or color changes, the IWindow dispatcher calls the virtual
function IWindow::setLayoutDistorted. The first argument to this function is
the set of flags that are being turned on (values defined in the
IWindow::Layout enumeration). The second argument is the set of flags being
turned off. This function is the basic notification vehicle for telling a
canvas that the look of one of its child windows has changed.
To detect font changes, you can provide your own implementation of
setLayoutDistorted in a derived class. Check the first argument, which is
IWindow::fontChanged for a font change and IWindow::colorChanged for a color
change, and then call the base class version of setLayoutDistorted, passing the
original arguments.
ΓòÉΓòÉΓòÉ 10.14.2. How Can I Save Font Information? ΓòÉΓòÉΓòÉ
Question:
Is there a way to save the current font and font attributes from an IFont
object into a .INI file, so that it can be recalled the next time the program
is started?
Answer:
The font face name and size should uniquely identify the font you are using.
You may also want to save the emphasis information so that the font will look
identical in the future. The HELLO6 sample program shipped with VisualAge C++
gives an example of how to save and restore the font facename and size to a
profile. Look at the readProfile and updateProfile member functions in that
sample.
ΓòÉΓòÉΓòÉ 10.14.3. Why Do I Get an Incorrect Font? ΓòÉΓòÉΓòÉ
Question:
I want to use Helvetica bold font with point size 8. However, I always get the
Courier font instead. Why?
Answer:
Make sure you specify the font name as the first parameter of the IFont
constructor, and that it is in the correct case. Because font names in OS/2 are
case-sensitive, "Helvetica" uses the correct Helvetica font, but "helvetica"
does not. If the font cannot be found, the class library defaults to Courier.
ΓòÉΓòÉΓòÉ 10.15. Font and File Dialogs ΓòÉΓòÉΓòÉ
This section discusses the classes IFontDialog and IFileDialog as well as the
related classes.
How Do I Customize Help for IFileDialog?
Why Doesn't IFileDialog Find the Files?
Can I Customize the File and Font Dialogs?
ΓòÉΓòÉΓòÉ 10.15.1. How Do I Customize Help for IFileDialog? ΓòÉΓòÉΓòÉ
Question:
I have set the helpButton style on a IFileDialog. How do I show my help for the
button? Do I have to trap the WM_HELP message? What is the ID of the Help
button?
Answer:
The simplest approach for contextual help support in the file dialog is to
create a HELPTABLE and HELPSUBTABLE in a resource file. Use the IDs that are
defined by PM for the various fields in the subtable to identify the contextual
help panels.
The control IDs for the file dialog are in <pmstddlg.h> after the following:
/*-----------------------------------------
/* File Dialog - dialog and control IDs
/*-----------------------------------------
#define DID_FILE_DIALOG 256
You can use a similar approach for IFontDialog help. The font dialog control
IDs are also in <pmstddlg.h> after the following:
/**********************************************************************/
/* font dialog and control id's */
/**********************************************************************/
#define DID_FONT_DIALOG 300
You can also read about the IDs in the Presentation Manager Guide and
Reference.
ΓòÉΓòÉΓòÉ 10.15.2. Why Doesn't IFileDialog Find the Files? ΓòÉΓòÉΓòÉ
Question:
I created an instance of IFileDialog and used setInitialFileType to set the
type to "*.CPP". There are files with that extension in the directory, but the
Files list box never contains any files. Why?
Answer:
The setInitialFileType specifies an extended attribute type, not the file
extension. Allow the EA type to default to all file types, and use
setFileName("*.CPP") instead of setInitialFileType.
ΓòÉΓòÉΓòÉ 10.15.3. Can I Customize the File and Font Dialogs? ΓòÉΓòÉΓòÉ
Question:
I want to alter the field prompts on the file dialog, but IFileDialog only
supports changes to the title. Can I change the prompts?
Answer:
You can specify your own dialog template using
IFileDialog::Settings::setDialogTemplate or
IFontDialog::Settings::setDialogTemplate. The &pmref. describes how to define
this dialog template. You do have to use specific constants for control IDs
when defining your dialog template. These are also described in the &pmref..
ΓòÉΓòÉΓòÉ 10.16. Direct Manipulation (Drag and Drop) ΓòÉΓòÉΓòÉ
This section discusses the IDM classes and related problems with drag and drop
operations.
How Do I Control Drag and Drop between Containers?
Can I Add Drag and Drop Support to an IComboBox?
ΓòÉΓòÉΓòÉ 10.16.1. How Do I Control Drag and Drop between Containers? ΓòÉΓòÉΓòÉ
Question:
I have two containers with different objects. How can I control what objects
can be dragged from one container to the other, or from one object to another?
What classes or functions should I use?
Answer:
By default, you can move any container object to any container window in your
application.
To restrict or enhance this level of function, you need to write your own
IDMCnrItem-derived class. In your constructors, set the attributes of your
derived item class (type, operations, and rendering mechanisms and formats).
You must also create a corresponding IDMItemProvider that works with your item
class. In most cases, you can use the IDMItemProviderFor class template to
generate that class.
The basic framework moves the container objects to the container controls for
you. If the action of dragging and/or dropping requires some
application-specific action to take place, you must also override the
targetDrop function.
You may find the Drag and Drop samples (DRAG1 through DRAG4) useful in
demonstrating how to enable this support.
ΓòÉΓòÉΓòÉ 10.16.2. Can I Add Drag and Drop Support to an IComboBox? ΓòÉΓòÉΓòÉ
Question:
I tried to add drag and drop support for an IComboBox control, but it didn't
work. Are there restrictions on direct manipulation of combo boxes?
Answer:
IComboBox is a composite control. You have to use PM to enumerate the children
of the combo box for its contained list box and entry field, depending on the
support you require. Use the obtained PM window handles to create an IListbox
and IEntryfield. Then you can add drag and drop support to the new class
objects.
ISpinButton requires similar support; you must add drag support to the entry
field contained in the spin button.
ΓòÉΓòÉΓòÉ 10.17. Dynamic Data Exchange (DDE) ΓòÉΓòÉΓòÉ
This section discusses the Dynamic Data Exchange (DDE) classes.
What DDE Formats Are Supported?
ΓòÉΓòÉΓòÉ 10.17.1. What DDE Formats Are Supported? ΓòÉΓòÉΓòÉ
Question:
Is there a list of valid DDE data formats and what they represent?
Answer:
The information on the IDDE class in the Open Class Library Reference defines a
number of IDDE:Format values. These values represent the predefined DDE formats
defined in the header file <pmwin.h>. (The formats in the header file all
begin with SZFMT_).
Applications can also define their own DDE formats. If you want to use a
format specific to a particular application, check the documentation for the
application you want to communicate with for a description of the format.
ΓòÉΓòÉΓòÉ 10.18. Exceptions ΓòÉΓòÉΓòÉ
This section discusses exceptions and exception handling.
What Happens to Exceptions on Secondary Threads?
Why Does My Program Just Exit?
ΓòÉΓòÉΓòÉ 10.18.1. What Happens to Exceptions on Secondary Threads? ΓòÉΓòÉΓòÉ
Question:
I throw an exception in a secondary thread that I started. What happens if I do
not catch that exception in the function I started on that thread?
Answer:
If you started the thread with either _beginthread or the IThread class, the
exception is handled as though it were the main thread: an uncaught exception
on a thread calls terminate, which then calls abort. To avoid termination, put
a try/catch block around the code in the secondary thread.
If you started the thread with DosCreateThread and did not register the C++
OS/2 exception handler, the C++ exception is treated as though it never
occurred.
ΓòÉΓòÉΓòÉ 10.18.2. Why Does My Program Just Exit? ΓòÉΓòÉΓòÉ
Question:
When I run the program I wrote with the User Interface classes, it simply ends.
Why?
Answer:
What is probably happening is that an exception is being thrown and not being
caught, causing the program to terminate. To learn more about the exception,
use the User Interface library trace facility. Before running your program,
enter:
SET ICLUI TRACE=ON
SET ICLUI TRACETO=STDERR
(You could also set this in your CONFIG.SYS file.)
When you run your program, redirect stderr to a file, for example:
myprog 2> myprog.out
After the program ends, look at myprog.out to see if exceptions were logged.
For more information about the ITrace class, see the Open Class Library
Reference.
ΓòÉΓòÉΓòÉ 10.19. Internationalization ΓòÉΓòÉΓòÉ
This section discusses internationalization and national language support
topics.
Are There Restrictions on National Language Support?
Can I Change Text on Message Box Buttons?
ΓòÉΓòÉΓòÉ 10.19.1. Are There Restrictions on National Language Support? ΓòÉΓòÉΓòÉ
Question:
Are there limitations of the national language support provided in the User
Interface class library? If so, what are they?
Answer:
The known limitations of the class library support for national language
enablement are:
There is no multiple code page support for IFont.
The following functions do not account for double-byte characters (DBCS):
- IString::isLike
- IFont::textWidth
- IFont::charWidth
- IFont::textLines
All messages retrieved from the message file are in English. (In the
Japanese version of VisualAge C++, they are in Japanese.) These messages
are used primarily for exception text for library-specific errors; the
class library retrieves other error messages from OS/2 and PM. If you
want to translate the message file into another language, the source is
available in the Class Library Source Code product. However, the end user
would not see this text unless you display exception text in message
boxes, or do something similar.
ΓòÉΓòÉΓòÉ 10.19.2. Can I Change Text on Message Box Buttons? ΓòÉΓòÉΓòÉ
Question:
I'm developing a bilingual application. I need the buttons to say OUI/NON
instead of YES/NO. Is there a way to change the text on IMessageBox buttons?
Answer:
The PM message box does not support this, and displays the buttons using the
language that was specified during system setup. However, you could replace the
message box with a modal IFrameWindow with an ISetCanvas containing the buttons
as a frame extension. Then you could easily change the text.
ΓòÉΓòÉΓòÉ 10.20. Extending the User Interface Class Library ΓòÉΓòÉΓòÉ
This section discusses how you can extend the User Interface class library.
How Can I Create a New IWindow Class?
Can I Use PM Window Words in My Application?
ΓòÉΓòÉΓòÉ 10.20.1. How Can I Create a New IWindow Class? ΓòÉΓòÉΓòÉ
Question:
I want to create a new IWindow class that is not based on one of the existing
IWindow or derived classes. The new class must work with a new handler class
that processes new message types. What should I do?
Answer:
Assuming you have a unique PM window class, you need to create the windows and
interact with them using C++:
1. Derive from IWindow.
2. Add constructors for your window class. The constructor arguments should
correspond roughly to the values your PM window class takes for its style
and ctldata parameters to WinCreateWindow or WM_CREATE.
3. In your constructor, or in a common intialization function called from
each of your constructors, construct the appropriate arguments and call
WinCreateWindow or IWindow::create. Your constructors should use the
default constructor to construct the IWindow base class.
4. After you have the hwnd value returned by WinCreateWindow or
IWindow::create, call IWindow::startHandlingEventsFor.
5. At this point, you can add handlers to your window. If you choose to
implement your window procedure as an IHandler, add the handler here.
You can have a separate handler for each window, or one that works for
all windows. If you choose the latter, use a static member of your
IWindow-derived class to point to the shared handler (refer to
IFrameWindow for an example). Note that, if your PM window class includes
handler functions in its window procedure, you don't need a handler.
6. Add member functions to your derived IWindow class that correspond to the
window messages your PM window responds to. If your window class is a
conventional PM class, you can implement those functions by sending the
appropriate PM message (IEvent).
7. If your window class is tailorable, meaning it sends notifications or
allows users to override the message handling, declare an
IHandler-derived class with an appropriate implementation of
dispatchHandlerEvent. Typically, you would add virtual functions for the
notifications and events that can be handled.
You can also choose to derive specialized IEvent classes specific to the
events required.
8. If you are implementing the base window behavior as a handler (as
mentioned in step 5) rather than a PM window procedure, separate that
handler from the one described at step 7. The latter should ideally have
empty implementations of all virtual functions. Users inherit the
built-in behavior of your primary handler in the base window by the
chaining done by the IWindow dispatching, not through C++ inheritance.
The inheritance diagram would look like:
This method is recommended because you are adding your handler
automatically at construction; if a user derives from the class without
knowing this, he or she could invoke your handler's code a second time by
calling Inherited::virtFunc.
9. Override inherited IWindow functions as required for your window. Often
you do not need to override any functions.
If you are interested in additional information, the September/October 1994
issue of OS/2 Developer magazine also has several articles relating to this
topic.
ΓòÉΓòÉΓòÉ 10.20.2. Can I Use PM Window Words in My Application? ΓòÉΓòÉΓòÉ
Question:
Does the User Interface class library use the window words provided in PM
controls? Can I use the user words in my application, or will that cause a
conflict?
Answer:
The User Interface class library does not use the QWL_USER value. Currently,
it does not register any new window classes either. You can use the window
words as described in the Presentation Manager Guide and Reference.
ΓòÉΓòÉΓòÉ 10.21. Graphics and Drawing ΓòÉΓòÉΓòÉ
This section discusses using graphics and customized drawing with the User
Interface classes.
Are There Graphics Classes?
How Can I Implement Customized Graphics?
ΓòÉΓòÉΓòÉ 10.21.1. Are There Graphics Classes? ΓòÉΓòÉΓòÉ
Question:
Which class implements the Gpi functions such as GpiLine, GpiPolyline, and
GpiBox?
Answer:
The latest version of the User Interface class library now includes a set of
2-D graphics classes. See the Open Class Library User's Guide and Open Class
Library Reference for more details on these classes and how to use them.
ΓòÉΓòÉΓòÉ 10.21.2. How Can I Implement Customized Graphics? ΓòÉΓòÉΓòÉ
Question:
Can I put graphics in the client area of a window? How?
Answer:
Yes, you can. Use the samples 2D-BMAP, 2D-DRAW, and BIGCPP as a starting point.
The HELLO6 sample also provides some example code that may be helpful. (All of
these samples are included with VisualAge C++.)
ΓòÉΓòÉΓòÉ 11. Creating Portable Applications ΓòÉΓòÉΓòÉ
This section discusses questions you might have about the portability of the
applications you create with VisualAge C++.
What Operating Systems Does It Support?
What Are General Guidelines for Creating Portable Applications?
Are There Guidelines for Portable User Interface Applications?
ΓòÉΓòÉΓòÉ 11.1. What Are General Guidelines for Creating Portable Applications? ΓòÉΓòÉΓòÉ
Question:
I am writing an application that I want to be able to compile and run on other
platforms. Are there any guidelines I should follow?
Answer:
To ensure the greatest degree of portability between operating system
platforms, use only language and library extensions that are defined in current
language standards such as ANSI/ISO and POSIX.
If you are using VisualAge C++ on the other platforms, there may be extensions
that are common. Refer to the language and library references.
If you use language elements that are implementation-defined (as described in
the appendix about implementation-defined values in the Language Reference),
try to code them in a way that will require less effort to port to platforms
with different implementations.
For example, in you require a variable to be exactly 32 bits in length, don't
use unsigned int or unsigned long. A better solution is to use a typedef to
create a new type synonym, and then use that new type name instead. Then when
you port to a different platform, you only have to modify the typedef.
If you are creating a C++ program, another way to increase portability is to
use the class libraries. Because they provide a layer of abstraction above the
operating system, the code you write can be less system-specific. The
VisualAge C++ class libraries are currently available on the OS/2, AIX, and
Solaris operating systems.
Note: Some classes in the class libraries differ slightly from platform to
platform, particularly the User Interface classes which must encapsulate very
different system interfaces. The Open Class Library Reference includes
portability information on each function, and platform-specific notes where
applicable. For tips on creating portable applications with the User Interface
class library, see Are There Guidelines for Portable User Interface
Applications?.
ΓòÉΓòÉΓòÉ 11.2. Are There Guidelines for Portable User Interface Applications? ΓòÉΓòÉΓòÉ
Question:
I am writing an application that uses the User Interface classes, and I want to
port it to other platforms. Are there any guidelines I should follow?
Answer:
The User Interface class library was designed to be as portable as possible to
all supported environments, which currently include OS/2 (PM), AIX (Motif), and
Solaris (Motif). Most of the classes are supported in all of the environments,
but there are some unavoidable system differences.
When you design your application for portability, you should consider the
following differences that exist between the PM and Motif versions of the
library:
Motif does not support DLGTEMPLATE resources or the ability to construct
an IFrameWindow from a DLGTEMPLATE resource. Use the ICanvas classes to
create portable dialogs.
Motif does not support Dynamic Data Exchange (the IDDE* classes).
The current Motif version does not support direct manipulation (IDM*
classes).
Motif does not support the owner-draw classes (IDrawItemEvent and derived
classes) or the handlers that process owner-draw events. To do customized
drawing in Motif, write a handler class to capture the appropriate X
events and use the X functions to do the drawing.
Motif does not support the IDynamicLinkLibrary class. To change the
resource library being used, you must change the locale (the LANG
environment variable and related settings) in the calling environment.
Motif does not support ISystemBitmapHandle or ISystemPointerHandle, or
the IBitmapControl and IIconControl constructors that use
ISystemBitmapHandle::Identifier and ISystemPointerHandle::Identifier as
parameters.
Because Motif does not provide a scheme palette, the IGUIColor class
returns hard-coded color values. It is probably best to avoid color
manipulation where possible and use the default values provided by the
user in the OS/2 scheme palette or X resource database.
Under Motif, IThread does not support the creation or starting of new
threads.
Use ISetCanvas to create group boxes instead of the IGroupBox class for
better portability.
There are other classes and functions that are not provided in all
environments or have no effect in some environments. Refer to the Open Class
Library Reference for details on the support for each class and function.
VisualAge C++ also provides macros you can use to conditionally include
platform-dependent code. In the PM environment (VisualAge C++ for OS/2), the
IC_PM macro is defined. In the Motif environment (C Set ++ for AIX and
Solaris), the IC_MOTIF macro is defined.
ΓòÉΓòÉΓòÉ 12. Compiling and Compiler Errors ΓòÉΓòÉΓòÉ
This section includes questions about using the compiler, as well as questions
about compiler errors and why they occur.
Can I Use an Object File in Both an EXE and a DLL?
How Can I Improve Compiler Performance?
Can the Compiler Generate Assembler Listings?
Can I Compile C Files as C++ Files?
Why Doesn't My _beginthread Function Have _Optlink Linkage by Default?
Why Can't I Increment a Cast Value?
Why Are My Structures Incomplete or Mismatched?
How Should I Compile DB2 Applications?
Can I Inherit Static Data Members?
How Does the /Sn Option Enable DBCS Support?
Why Does My Part Get Compiler Errors?
ΓòÉΓòÉΓòÉ 12.1. Can I Use an Object File in Both an EXE and a DLL? ΓòÉΓòÉΓòÉ
Question:
How do I use VisualAge C++ to compile a library .OBJ file that can be linked
into either an .EXE or a .DLL file?
Answer:
To compile objects that can be linked into an .EXE or DLL file, use the /Ge+
option. These objects must not contain a main function.
To link in the correct startup code for a .EXE, compile the source file that
contains the main function using the /Ge+ option.
To link in the correct startup code for a .DLL, compile one of the source
files, preferably the one that contains your _DLL_InitTerm function, with the
/Ge- option.
/Ge+generates a reference to _exeentry only if a main function is seen.
/Ge- always generates a reference to _dllentry.
ΓòÉΓòÉΓòÉ 12.2. How Can I Improve Compiler Performance? ΓòÉΓòÉΓòÉ
Question: What can I do to get faster compile times?
Answer:
You can speed up some compilations by doing one or all of the following:
Check the settings of your environment variables (LIBPATH, PATH, INCLUDE,
and so on). If the VisualAge C++ directories are at the end of the paths,
the compiler or linker must search through all of the other directories
before it finds the required DLLs, header files, and so on.
Ensure you preload the compiler with the /Tl option (it is preloaded by
default). This option keeps the compiler components loaded in memory.
If you are statically linking to the VisualAge C++ libraries, try dynamic
linking.
Use precompiled header files. See the User's Guide for details on how to
structure your files so the compiler can take full advantage of the
precompiled headers.
Turn off all optimizations.
If you are using the HPFS file system, set the IFS statement in your
CONFIG.SYS file to:
IFS=c:\os2\hpfs.ifs /cache:2048 /crecl:64
This allows OS/2 to keep frequently-used files in memory between
compilations, which can greatly reduce the amount of time it requires the
compiler to process them.
Note: If you experience performance problems and have LAN Requester 4.0
installed, doublecheck this statement in your CONFIG.SYS. Some users have
reported that LAN Requester 4.0 changes these settings and severely
degrades performance.
Add more RAM to your system. In a memory-constrained environment, OS/2
spends more time swapping data to disk, which increases compilation times
tremendously. Additional RAM allows the compiler and its data to remain
in memory, which can make your builds run more quickly.
Define a virtual disk (VDISK or RAM disk) with the OS/2 VDISK device
driver. It creates a disk from your system's RAM. For example, placing
this statement in your CONFIG.SYS file:
DEVICE=C:\OS2\VDISK.SYS 2048,,256
allocates a virtual disk of 2M with 256 directory entries. You can then
copy all the library and header files you need for compiling and linking
to this disk and set your LIB and INCLUDE variables to point to it before
any other directory. Because these files are already in memory, your
compile and link times will improve. (Do not put the compiler executable
files there; the compiler preloads them into memory by default, so you
would then have two copies in memory.)
However, there are drawbacks to using a VDISK. The data on it is lost
when you reboot. Also, memory allocated for a VDISK is unswappable memory
space, meaning it cannot be used as normal memory space by applications.
Because C++ compilations can require a lot of memory, putting memory into
a VDISK could cause excessive memory paging and slow down your
compilation. If you have a large VDISK, it may be to your advantage to
eliminate it or make it smaller to provide more available memory to the
compiler
Minimize dependencies between source files so that changes made to one
file don't require you to recompile all your files.
For C++ programs specifically:
- Create abstract objects that contain only public methods and make
your real objects descendents of those objects. This approach
reduces the amount of total source code in compiles that do not need
to refer to the real objects.
- In .HPP files, only include those files you need.
For example, if all that the .HPP file for class b needs to know
about class a is that class b contains a pointer to a class a-type
object, put class a;, (rather than #include "a.hpp") in B.HPP.
Note: This approach would still allow you to put #include "a.hpp"
in B.CPP.
ΓòÉΓòÉΓòÉ 12.3. Can the Compiler Generate Assembler Listings? ΓòÉΓòÉΓòÉ
Question:
Is there a compiler option that provides instruction offsets in conjunction
with the assembler code?
Answer:
There is no compiler option that provides instruction offsets with assembler
code. You can usually process the output of the /Fa+ option with a 32-bit
assembler.
However, because of the nature of some assemblers, output of /Fa+ that is
processed with an assembler may not be identical to the compiler output. Also,
certain problems, such as variables that have the same name as assembler
statements, may prevent the code from assembling.
You can also link with the /L option to get line offsets. refdi=xlat.
Use the VisualAge C++ Debugger to look at the actual object code.
ΓòÉΓòÉΓòÉ 12.4. Can I Compile C Files as C++ Files? ΓòÉΓòÉΓòÉ
Question:
How do I compile an application written in C as if it were C++ on the
VisualAge C++ compiler? I have tried to do this, but I get syntax errors in
some header files.
Answer:
VisualAge C++ allows you to mix your C- and C++-compiled modules freely as long
as you use extern "C" { ... } with any prototypes of functions that are called
by C code or are compiled as C code.
Note that there are some language elements, such as #pragma linkage directives,
that are valid in C but not in C++. If your C source files contain these
language elements, you cannot compile them as C++. For complete information on
C and C++ compatibility, see the Language Reference.
ΓòÉΓòÉΓòÉ 12.5. Why Doesn't My _beginthread Function Have _Optlink Linkage by Default? ΓòÉΓòÉΓòÉ
Question:
I am using _beginthread to start a thread, and passing func as the function to
run in that thread. I declared func as static void func(void). The compiler
says that it cannot convert func to _Optlink. I thought that _Optlink was the
default calling convention. Why am I getting this error?
Answer:
If you are compiling a C program, _Optlink is the default calling convention.
Make sure you did not change the default with one of the /M compiler options.
If you are compiling a C++ program, the default calling convention is a bit
different. C++ functions have C++ linkage. They use the _Optlink model of
parameter passing, but they also have mangled names and can be overloaded. You
need to tell the compiler that func is a C function by declaring it as extern
"C", extern "OPTLINK", or _Optlink. For example, instead of declaring your C++
function as:
void cpp_func(void *);
use one of the following declarations:
extern "OPTLINK" void cpp_func(void *);
void _Optlink cpp_func(void *);
extern "C" void cpp_func(void *); // if _Optlink is the default
// calling convention (/Mp option)
You cannot specify a member function for _beginthread.
ΓòÉΓòÉΓòÉ 12.6. Why Can't I Increment a Cast Value? ΓòÉΓòÉΓòÉ
Question:
Why does the compiler generate an error message for the statement
((long *)fred)++ ?
Answer:
There are two problems with this expression. First, the operand of the
increment operator (++) must be an lvalue. Because a cast does not produce an
lvalue, the statement above is not valid and the compiler generates an error
for it.
Operators that must have lvalue operands include the increment and decrement
operators ++ and --, as well as the simple and compound assignment operators.
The following statement yields and increments an lvalue:
(*(long **)&fred)++
For more information on casting and lvalues, see the Language Reference.
The other and more important problem is that you are trying to reference a
value using a type other than the one it was defined with. According to the
ANSI/ISO standard, you can only reference an object using its declared type
(with some minor changes such as qualifiers) or a char *. The example statement
may or may not work, but is not guaranteed to work.
Change your code to reference the value either using its declared type or a
char *.
ΓòÉΓòÉΓòÉ 12.7. Why Are My Structures Incomplete or Mismatched? ΓòÉΓòÉΓòÉ
Question:
The compiler says that the argument I am passing to a function doesn't match
its prototype, but both have the same structure type:
int func(struct st *);
struct st {int s1;} ss;
func(&ss);
Why?
Answer:
A structure declaration must appear before any function prototype statements
that use that structure type. GIven the above declaration for func:
int func(struct st *);
a b
At point (a), a new scope is opened for the identifiers that are introduced in
the parameter list. At point (b), this scope is closed. Every identifier that
appears betweeen (a) and (b) is local to that scope, and nothing outside is
allowed to look inside.
The declaration of struct st occurs outside the scope of the function
declaration for func. Therefore, this struct st is different from the struct st
is the function prototype.
As a result, struct st is incomplete when it is introduced in the parameter
list of func, and can never be completed because its scope is closed to
everything outside. Only a void pointer could be passed to func.
To solve this problem, declare the structure before you use it in the the
function prototype. For example:
struct st;
int f(struct st *);
struct st {int s1;} ss;
f(&ss);
Declaring the tag at file scope causes all subsequent occurrences of struct st
to resolve to the same file scope identifier, and everything works correctly.
ΓòÉΓòÉΓòÉ 12.8. How Should I Compile DB2 Applications? ΓòÉΓòÉΓòÉ
Question:
What compiler options do I need to set to create a DB2 application using
VisualAge C++?
Answer:
The easiest way to build DB2 applications is to use Data Access Builder to
create classes to access the DB2/2 database, and code your program in C++.
Using these classes may eliminate the need to call DB2/2 APIs directly. You can
then use whatever compiler options are appropriate.
If you are calling DB2/2 APIs directly, compile with the /DES32TO16 option
(defines ES32TO16) and link with the SQL_DYN.LIB library.
You also need to add the SQLLIB directory to the INCLUDE and LIB paths in your
CONFIG.SYS file.
ΓòÉΓòÉΓòÉ 12.9. Can I Inherit Static Data Members? ΓòÉΓòÉΓòÉ
Question:
The following code gives very different warnings and errors when compiled with
different compilers:
class a {
public:
static int sm;
};
int a::sm = 1;
class b: public a {
};
int b::sm = 2;
I want all classes that inherit from a to have a member sm that has a unique
value for the class. However, VisualAge C++ generates the following error
message:
13 |int b::sm = 2;
test.cpp(13:1) : error EDC3079: "sm" is not a member of "b".
Does this mean that static members are not inherited in C++?
Answer:
There is only one instance of a static member called sm in your program, and it
belongs to class a. Class b does not contain a separate copy of sm, it
inherits a::sm.
Because class b does not contain its own copy of sm, it does not allow:
int b::sm = 2;
However, used in an expression, a::sm and b::sm refer to the same piece of
storage.
If you want class b to have its own copy of sm, declare it as a static member,
which then hides a::sm.
ΓòÉΓòÉΓòÉ 12.10. How Does the /Sn Option Enable DBCS Support? ΓòÉΓòÉΓòÉ
Question:
According to the compiler documentation, the /Sn compiler option allows you to
use the double-byte character set (DBCS). What does that mean?
Answer:
Use /Sn to tell the compiler whether you use double-byte characters in your
source code. It specifies whether characters in the DBCS first-byte range
should be interpreted as single-byte characters (/Sn-) or as the first half of
a double-byte character (/Sn+). DBCS support is always included in the runtime
library and VisualAge C++-generated code, regardless of compiler options.
If you are interested in DBCS support because you want to translate or tailor
your applications for other countries or languages, see the information on
locales and internationalization, beginning with "Introduction to Locale" in
the Programming Guide.
ΓòÉΓòÉΓòÉ 13. Linking and Linker Errors ΓòÉΓòÉΓòÉ
The questions in this section deal with how to link your program and with
errors that occur at link time.
Which Libraries Should I Link To?
How Can I Improve Linker Performance?
Why Are My Symbols Defined More than Once?
When Should I Use the /NOD Option?
Why Do I Get Unresolved External Errors?
Why Does errno Cause an Undefined External Error?
Why Does Inlining Cause Unresolved External Errors?
Why Does My Part Get Unresolved External Link Errors?
Why Is My virtual-fcn-table-ptr Unresolved?
Why Does /Ti Cause Unresolved External References?
ΓòÉΓòÉΓòÉ 13.1. Which Libraries Should I Link To? ΓòÉΓòÉΓòÉ
Question:
What libraries should I use to link?
Answer:
You do not have to specify any libraries for the link step. Information about
the required libraries, including the IBM Open Class library files, is imbedded
in your .OBJ files by the compiler according to the compiler options you use
and the #pragma library statements in the header files you include.
If you mix objects compiled with different runtime options (for example, one
multithread and the other single-thread), the linker generates duplicate
definition errors, as described in Why Are My Symbols Defined More than Once?.
There are compiler and linker options to exclude or ignore the information
about the default libraries (/Gn and /NOD), but we do not recommend you use
them. If you specify these options, you must then explicitly specify the names
of all required libraries to the linker. If the libraries specified are
incorrect, your program may not link or run correctly.
For details on the names of the library files, see What Are the Library Naming
Conventions?.
ΓòÉΓòÉΓòÉ 13.2. How Can I Improve Linker Performance? ΓòÉΓòÉΓòÉ
Question:
What can I do to get faster link times?
Answer:
To improve linker performance:
Invoke the linker using icc to preload it in memory.
Use the /NOEXEPACK option.
Use the /NODEBUG option if you don't need debug information. If you do
need debug information, use /DBGPACK.
Do not use the /NOE or /SEG options unless a linker error message tells
you to.
Convert old .LIB files to the new format:
ILIB /CONV /NOBR xxx.LIB;
or for import libraries:
ILIB /CONV /NOBR /NOE xxx.LIB;
Do not use the /OPTFUNC option.
To improve your application load time:
Use the /EXEPACK option, or /EXEPACK if you are targetting only OS/2 Warp
systems.
Use the /OPTFUNC option.
ΓòÉΓòÉΓòÉ 13.3. Why Are My Symbols Defined More than Once? ΓòÉΓòÉΓòÉ
Question:
When I link my object modules, the linker says that some symbols are defined
more than once. The symbols are not in my source code, so I think they're in
the runtime library. Why do I get this error?
Answer:
You are probably linking objects that were compiled with incompatible compiler
options. For example, if you compile one module as a multithread program
(/Gm+) and another as single-thread (/Gm-), each will include a reference to a
different runtime library. At link time, both libraries are linked in,
resulting in symbols being defined more than once.
Recompile your objects using the same compiler options.
ΓòÉΓòÉΓòÉ 13.4. When Should I Use the /NOD Option? ΓòÉΓòÉΓòÉ
Question:
When should I use the /NOD linker option?
Answer:
We do not recommend the /NOD option for general use. It tells the linker to
ignore the library information included in the object modules being linked and
to link in only the libraries you explicitly specify in the linker command. You
must then make sure that the libraries you link in match the libraries that the
object modules were compiled for. For example, if the objects were compiled as
multithread objects (/Gm+ compiler option) and you use /NOD to override the
specified library and link them with the single-thread library, the linker will
have unresolved references.
However, if you have created your own runtime libraries, you need to use /NOD
and specify the names of your libraries and OS2386.LIB. You can use /NOD in
other situations, but be careful that you specify the correct libraries.
Note also that using the /Gn+ compiler option suppresses the default library
information in the object module itself. Using this compiler option has the
same effect as using the /NOD linker option; you must then explicitly specify
the correct libraries in the linker command.
ΓòÉΓòÉΓòÉ 13.5. Why Do I Get Unresolved External Errors? ΓòÉΓòÉΓòÉ
Question:
Why is the linker generating unresolved external errors?
Answer:
The linker probably cannot find the libraries it needs to construct the
executable module.
Make sure that you specify all necessary libraries when you invoke the linker.
The correct VisualAge C++ libraries are linked in by default, unless you use
the /Gn compiler option or the /NOD linker option.
Avoid using the /Gn compiler option and /NOD linker option. The /Gn option
suppresses information about the default libraries from the linker; the /NOD
option causes the linker to ignore the default libraries. When you use these
options, you must specify on the command line all libraries you use, both
directly and indirectly.
For details about what libraries you need to include, see Which Libraries
Should I Link To?.
This error can also occur if you do not specify your functions and variables
using consistent case. For example, if you define a function as UPPERCASE, but
then call it as uppercase. Because the C language is case sensitive, the linker
is also case sensitive by default.
You can specify the /IGNORECASE linker option to make it case insensitive, but
because the VisualAge C++ libraries and most other C code are case sensitive,
you may encounter more problems at a later time. Change your code so that the
case of the function name is the same in the definition and in the call.
Another possibility is that you are compiling code with templates using the
/Ft+ option. When you use this method of handling templates, additional source
files are created in your TEMPINC directory. Before you link, you must compile
these files as well, and any additional files that are created when you compile
the TEMPINC files. For this reason, use icc to invoke the linker for you to
ensure that all TEMPINC files are compiled before the link step.
For more details on templates and how to use them, see the sections on
templates in the Language Reference and the Programming Guide.
ΓòÉΓòÉΓòÉ 13.6. Why Does errno Cause an Undefined External Error? ΓòÉΓòÉΓòÉ
Question:
Why do I get an undefined external error for errno?
Answer:
When you use the single-thread library, there is only one instance of errno,
and it is defined as an extern int. However, when you use the multithread
library, there is a separate instance of errno for each thread, so it is
defined differently than it is in the single-thread library.
Ensure you:
Always include <errno.h>. It defines errno appropriately for either the
single-thread or multithread library (depending on the compiler option
you specify).
Compile and link all modules with the same library. If you compile module
A with the single-thread library and module B with the multithread
library, linking both together with either library generates an
unresolved external error.
ΓòÉΓòÉΓòÉ 13.7. Why Does Inlining Cause Unresolved External Errors? ΓòÉΓòÉΓòÉ
Question:
I am trying to inline one of my functions, but I keep getting an "external not
found" error in another module. Why?
Answer:
Inline functions are only available in the source file in which they are
defined. (They are conceptually similar to static functions with regard to
scoping.) If you have defined the inline function in one module, it is not
available to your other modules, the reason you are getting the "unresolved
external".
Inlining means you want the compiler to inline the code if possible rather than
linking the functions together. The compiler can't inline code that is not
available until your modules are linked together.
You may want to put your inline function in a .H file and include the .H file
in both source files that need the function. Alternatively, you could use the
intermediate code linker to link the intermediate files together.
ΓòÉΓòÉΓòÉ 13.8. Why Is My virtual-fcn-table-ptr Unresolved? ΓòÉΓòÉΓòÉ
Question:
When I link C++ code, I get the following linker error:
X::virtual-fcn-table-ptr: undefined symbol
What am I doing wrong?
Answer:
The missing virtual-fcn-table for a class is a compiler-generated data
structure that is used to implement virtual function calls for that class. The
compiler has to determine which compilation unit it should generate each table
in. Often, the compiler generates the table in the compilation that contains
your definition of a selected virtual function. If you never define that
function, the table is never generated, and this linker error results.
If you recompile your code with the /Wvft+ option, the compiler will produce a
message similar to:
EDC3281: informational The virtual function table for X will be
defined where X::foo() is defined.
You will find that the function X::foo() has not been defined anywhere.
ΓòÉΓòÉΓòÉ 13.9. Why Does /Ti Cause Unresolved External References? ΓòÉΓòÉΓòÉ
Question:
When I compile the following program with debug information on:
class X
{
protected:
int getI() {return i;}
static int i;
};
main(int argc, char *argv[])
{
X x;
return 0;
}
why does it generate the following linker error?
filename.obj(filename.CPP) : error L2029: 'X::i' : unresolved
external
Answer:
When you compile with debug information on, the compiler generates an external
reference to X::i so that you can see the value of X::i from any other
compilation units that make up your application. If the compiler didn't do
this, you would only be able to view the contents of X::i while you are in the
source view for the compilation unit in which X::i was defined (where the
storage was allocated).
The unresolved reference is a result of no storage being allocated for the
static data member; it was declared but it was not defined. The compiler does
not know if the storage has been allocated in another compilation unit so it
can't check if it should put out the reference or not. Therefore, it always
puts out references to static data members. Add the following statement, which
allocates storage for the data member:
int X::i = <some value>;
If you never reference the static class variable, the amount of storage
available for it is irrelevant. Your program generates the same results
whether or not it exists. The same is true for unreferenced class methods.
One of the reasons that external references are not included when they are not
required is that unreferenced data items may consume page space or address
space, but they do not increase the size of the working set, except for a
slight effect they may have on page tables.
ΓòÉΓòÉΓòÉ 14. Runtime Errors ΓòÉΓòÉΓòÉ
This section contains possible answers to questions that you might have when
you run a program. Refer to this section if your program ends abnormally or
behaves unexpectedly.
Why Does My DLL Work Incorrectly?
Why Does Adding Entry Points Change Existing Ones?
Why Does My DLL End Abnormally When I Call It?
Can I Allocate and Free Memory across Modules?
Should I Link My DLL to the VisualAge C++ Runtime Library?
Why Don't My String and Memory Functions Work in DLLs?
Why Are My Classes Initialized Multiple Times?
Why Is _DLL_InitTerm Causing Errors?
Why Does a Destructor Exception End My Program?
Why Does a Destructor Corrupt the Object?
Why Does Calling a Destructor Explicitly Cause Errors?
Why Do I Get an Access Violation from the Runtime DLL?
Why Can't I Open a File?
Why Does Optimization Cause My Program to Fail?
Why Doesn't My Old C Code Work?
Why Does One Function Alter Information from Another?
Why Do My Window Procedures End Abnormally?
Why Does Printing a _Seg16 Pointer Trap?
What Is __EDCThunkProlog and Why Does It Trap?
Why Does printf Work Incorrectly?
Why Doesn't printf Output Display?
Why Does scanf Behave Unexpectedly?
Why Do Library Functions and APIs Not Work?
Why Do Macros with Increment Operators Work Incorrectly?
Why Doesn't My Macro Resolve Correctly?
Why Don't My Threads Work Correctly?
Why Do My Statements Have No Effect?
Why Do Increment Operators Produce Unexpected Results?
Why Do I Get a SYS2070 Error?
Why Does My PM Application Disappear?
Why Does My Program Work Incorrectly and Inconsistently?
Where Is the Message File?
Why Doesn't My Application End when the Frame is Closed?
Why Does My Program Just Exit?
ΓòÉΓòÉΓòÉ 14.1. Why Does My DLL Work Incorrectly? ΓòÉΓòÉΓòÉ
Question:
Why doesn't my DLL work correctly?
Answer:
You may be mixing objects compiled with the /Ge+ and /Ge- compiler options in
the same DLL.
The VisualAge C++ libraries provide different initialization routines for
executable modules and DLLs. To ensure that the correct initialization routine
is run, use the /Ge+ option when you create an executable module and the /Ge-
option when you create a DLL.
When you link your files, you can override the /Ge option you specified at
compile time. See the User's Guide for more information on how to do this. See
the Programming Guide for more information on DLLs in general.
ΓòÉΓòÉΓòÉ 14.2. Why Does Adding Entry Points Change Existing Ones? ΓòÉΓòÉΓòÉ
Question:
I have an existing DLL that exports a number of functions and works correctly.
However, when I add more entry points (export additional functions), the DLL no
longer works as it did. How can I add entry points without affecting existing
ones?
Answer:
When you add to your DLL, you are probably changing the ordinal numbers
associated with your existing entry points.
A DLL contains a table that maps names to entry points. An ordinal is an index
into this table. The OS/2 loader can resolve entry points by either name or
ordinal, depending on what is available. Resolving by ordinal is faster.
If you build an import library (.LIB) with ILIB using a .DEF file that does not
contain ordinals, the library only provides the loader with names for the entry
points. If you create the library from the DLL, both names and ordinals are
included, and calls to the DLL are resolved by ordinal. If you do not
explicitly associate an ordinal with an entry point, the ordinal could change
when you rebuild the DLL. You then need to rebuild all executables and DLLs
that reference that DLL or library.
To avoid any confusion, you should define both a name and an ordinal for each
entry point in one of the following ways:
1. Use #pragma export to specify the name and ordinal for each export. If
you do not change the #pragma directives when you rebuild your DLL, the
files currently using that DLL do not require rebuilding.
2. List the exports in the .DEF file by name and ordinal. Again, if you do
not change the names or ordinals of existing entry points when you
rebuild the DLL, the files currently using that DLL do not require
relinking. The advantage of using a .DEF file instead of #pragma export
is that your exports are defined in one place.
Alternatively, include the statement OLD in your .DEF file. This statement
tells the linker to maintain the ordinal assignments as used in a previous
version of the DLL. If you are making only a few changes to a DLL that is
mostly complete, this method is quicker than defining ordinals for all entry
points. See the section on Linking in the User's Guide for more information on
the OLD statement.
ΓòÉΓòÉΓòÉ 14.3. Why Does My DLL End Abnormally When I Call It? ΓòÉΓòÉΓòÉ
Question:
My DLL ends abnormally when a second process tries to call it. Why?
Answer:
It could be that both processes are trying to use the same memory for library
data, but only one of them has access. Make sure that you include the following
statements in your module definition (.DEF) file:
LIBRARY INITINSTANCE TERMINSTANCE
This statement identifies the executable file as a DLL. INITINSTANCE
specifies that the _DLL_InitTerm function is called the first time the
DLL is loaded for each process that accesses the DLL. TERMINSTANCE
specifies that _DLL_InitTerm is called the last time the DLL is loaded
for each process that accesses the DLL.
DATA MULTIPLE NONSHARED
This statement defines the default attributes for data segments within
the DLL. MULTIPLE specifies that there is a separate copy of the data
segment for each process that accesses the DLL. NONSHARED specifies that
the data segment is not shared by other processes.
If you need to share memory between two instances of your DLL, use #pragma
data_seg to put the data to be shared in a named data segment. Then put a
SEGMENTS statement in the .DEF file for your DLL and specify that segment
after it.
For more information on DLLs, see Building Dynamic Link Libraries in the
Programming Guide.
ΓòÉΓòÉΓòÉ 14.4. Can I Allocate and Free Memory across Modules? ΓòÉΓòÉΓòÉ
Question:
I allocate memory in one DLL, using new or malloc, and then free it in another
DLL. Sometimes this works, but other times it causes my application to trap.
Why?
Answer:
In most cases, you can allocate memory in one module (executable or DLL) and
free it in another. (Note that this has changed from the previous release of
C Set ++.)
However, both modules must be linked to the same copy of the library code.
ΓòÉΓòÉΓòÉ 14.5. Should I Link My DLL to the VisualAge C++ Runtime Library? ΓòÉΓòÉΓòÉ
Question:
I'm creating a DLL. Do I need to link it to the VisualAge C++ runtime library?
Answer:
If you are not making any runtime calls out of your DLL, you don't have to do
anything else and don't have to link to the runtime library.
If you do use the runtime, you have to specify the /Gd+ option when you
compile. Otherwise, the VisualAge C++ runtime environment may not be
initialized correctly.
You will probably need some kind of runtime support because you probably have a
static constructor and/or destructor in your DLL. Make sure that you call the
__ctordtorInit and __ctordtorTerm routines as described in the Programming
Guide.
ΓòÉΓòÉΓòÉ 14.6. Why Don't My String and Memory Functions Work in DLLs? ΓòÉΓòÉΓòÉ
Question:
I have a problem with the strupr, stricmp, and memicmp library functions when
they are used in a DLL. They work if only a single copy of the DLL is loaded,
but they return incorrect values when they are used by any additional processes
that load another copy of the DLL. The strupr function always returns a
zero-length string, and stricmp and memicmp always return equal values for the
two strings or blocks of memory.
These functions do not exhibit this behavior when they are used in an .EXE
file, and multiple copies of the .EXE are running. What is wrong?
Answer:
Make sure you include
LIBRARY libname INITINSTANCE TERMINSTANCE
(where libname is the name of your library) in your .DEF file when you create
the DLL,
ΓòÉΓòÉΓòÉ 14.7. Why Are My Classes Initialized Multiple Times? ΓòÉΓòÉΓòÉ
Question:
In my program, my class constructor is called each time my DLL is loaded
(called by an executable file), but built-in types are initialized only once.
For example:
class MYCL ....
// global
int i1=4711; // only on 1st loading
MYCL i2(4711); // each time
I specified INITINSTANCE for the DLL. Why does this happen?
Answer:
Because you are building a shared DLL, you should use INITGLOBAL, not
INITINSTANCE. When you specify INITINSTANCE, the library initialization
routine is called for each process that uses the DLL. When you use INITGLOBAL,
the routine is only called once, when the DLL is loaded. The initialization is
calling __ctordtorInit each time, and that is what is initializing your
variable each time.
Important When you use INITGLOBAL, you must ensure that your DLL does not
statically link to the VisualAge C++ runtime library. The VisualAge C++ runtime
library must use INITINSTANCE to correctly initialize the runtime environment.
Making the runtime library INITGLOBAL could lead to problems as described in
Why Does My DLL End Abnormally When I Call It?.
ΓòÉΓòÉΓòÉ 14.8. Why Is _DLL_InitTerm Causing Errors? ΓòÉΓòÉΓòÉ
Question:
I have some questions about _DLL_InitTerm:
1. Why does my program trap when my _DLL_InitTerm calls printf?
2. The Programming Guide says to register a clean-up routine with
DosExitList if I require runtime calls and the runtime library is
dynamically linked. I'm using /Gd+ to dynamically link to the runtime,
but _DLL_InitTerm is called with ulFlag!=0. Why?
3. The Programming Guide says that I need to call _CRT_Term only if the
runtime is statically linked. Does this also apply to __ctordtorTerm?
Answer:
1. Your program traps because _DLL_InitTerm has already terminated the
runtime environment, so you cannot call any runtime functions (like
printf).
2. Specifying TERMINSTANCE in your .DEF file tells OS/2 to call your code
when the DLL is terminated or unloaded.
3. You must always call __ctordtorTerm.
ΓòÉΓòÉΓòÉ 14.9. Why Does a Destructor Exception End My Program? ΓòÉΓòÉΓòÉ
Question:
If an exception is thrown in a constructor of a derived class, and the
destructor of the base class also throws an exception, the program terminates
immediately. It is not even possible to do an output redirection in this case.
Why?
Answer:
If a destructor that is called during exception handling itself throws an
exception, the terminate function is called. This is the way C++ handles
double exceptions. If you have not registered your own terminate routine (by
using set_terminate), the program is aborted by default.
ΓòÉΓòÉΓòÉ 14.10. Why Does a Destructor Corrupt the Object? ΓòÉΓòÉΓòÉ
Question:
Why does a destructor corrupt the address of an object in the following
example?
main(int argc, char *argv[])
{
SharedEventSemaphore *phev = new SharedEventSemaphore;
phev->~SharedEventSemaphore();
delete phev;
return(0);
}
Answer:
According to ANSI, if you call a destructor twice for the same object, the
behavior is undefined.
In the example, you call the destructor once explicitly, and again as part of
the delete processing. Rewrite your program so that the destructor is called
only once.
ΓòÉΓòÉΓòÉ 14.11. Why Does Calling a Destructor Explicitly Cause Errors? ΓòÉΓòÉΓòÉ
Question:
It appears that an explicit call to a destructor sometimes generates an error,
and sometimes creates and destroys an object in one step. It never simply calls
the destructor. When the destructor is called with a this-> statement, it works
properly. Why?
Answer:
You should not explicitly call destructors on objects.
You can use a delete this; statement that calls the destructor, and then free
the memory used by the object.
Note: This should only be done on dynamically allocated objects, and not in
the destructor itself.
ΓòÉΓòÉΓòÉ 14.12. Why Do I Get an Access Violation from the Runtime DLL? ΓòÉΓòÉΓòÉ
Question:
My program runs fine until the very end of main, and then I get an access
violation from the runtime library (DDE4MBS.DLL) after termination. What
causes this and how can I fix it?
Answer:
This behavior is typically caused by problems in the heap, such as writing to
unallocated or freed memory. To find the problem:
1. Compile your program with the /Tm option to enable the debug versions of
the memory management functions.
2. Call _heapmin immediately before the end of main (or before the function
call that ends the program). If your problems are in a DLL, call _heapmin
in your _DLL_InitTerm function.
For more information about debugging your heap problems, see "Debugging Your
Heaps" in the Programming Guide.
ΓòÉΓòÉΓòÉ 14.13. Why Can't I Open a File? ΓòÉΓòÉΓòÉ
Question:
I can edit a file, but I cannot open it. Why?
Answer:
Make sure that, if you store the file name in a constant string, you use a
double backslash (\\) to represent a backslash (\).
In C, a backslash is an escape character for inserting a character that you
normally cannot type. For example, because \t is the tab character, the
following string:
char filename[] = "c:\directory\test.c"
has an actual value of
"c:directory est.c"
To enter the file name correctly, convert the string to the following:
char filename[] = "c:\\directory\\test.c"
ΓòÉΓòÉΓòÉ 14.14. Why Does Optimization Cause My Program to Fail? ΓòÉΓòÉΓòÉ
Question:
My program runs correctly when I create it with no optimization (/O-), but when
I add optimization, it fails or traps. Why?
Answer:
There could be a problem with the optimizer, but often, optimization reveals an
underlying problem in your source code.
For example, given the following code:
int bruce()
{
int dave[8];
char stephan;
int vij[6];
.
.
.
vij[6] = 0; // writes past end of array
.
.
.
return dave[0];
}
With no optimization (/O-), the statement vij[6] = 0; causes stephan to be
overwritten. This may or may not cause a runtime error, depending on how
stephan is used after this statement.
With optimization (/O+), the order of local variables on the stack changes, and
the same statement causes dave[0] to be overwritten. Because bruce actually
returns this value, the problem is more likely to appear.
Using the optimizer is a good way to further test your source code.
ΓòÉΓòÉΓòÉ 14.15. Why Doesn't My Old C Code Work? ΓòÉΓòÉΓòÉ
Question:
Some of the old C code that I have recently started to use does not seem to
work correctly. It seems that the parameters to a function are not being
received correctly. What is happening?
Answer:
Make sure that you do not mix functions defined under the old C standard (KRx)
with functions defined under the ANSI standard. You can still define functions
according to the KRx standard, but you cannot mix prototyped and unprototyped
function definitions because of the difference in conversions.
Note: The C++ language requires that all functions have ANSI-style prototypes.
There are important differences between the standards in the way that functions
are defined and processed by the compiler. Under the old standard, you define
a function as follows:
int my_function( variable1, variable2, variable3 )
int variable1;
float variable2;
short variable3;
{
.
:
}
To make passing of parameters easier, variables of type char or short are
converted to type int, and variables of type float are converted to double.
The ANSI standard formally defines the function using a function prototype.
With the prototype definition, you explicitly state the number and types of
parameters each function receives. The corresponding ANSI definition of the
function above is:
/* function prototype */
int my_function( int variable1, float variable2, short variable3 );
/* function declaration */
int my_function( int variable1, float variable2, short variable3 )
{
.
:
}
The ANSI standard also allows functions with a variable number of parameters,
specified by following the fixed parameter list with an ellipsis (...). Under
this standard, fixed parameters of type char are converted to int, optional
parameters of type char and short are converted to int, and optional parameters
of type float are converted to double.
It is best to convert the function definitions to the ANSI standard.
Prototyping your functions as described in the ANSI standard makes your code
more portable. Defining a full prototype also gives the compiler and optimizer
complete information about the types and sizes of the parameters. As a result,
the compiler does not have to perform conversions to widened types or generate
eyecatcher instructions for the function.
ΓòÉΓòÉΓòÉ 14.16. Why Does One Function Alter Information from Another? ΓòÉΓòÉΓòÉ
Question:
Why is information that I generate by calling one function being altered after
I call a second function?
Answer:
You may be returning the address of a local variable. If you call a function
from within your program, do not rely on any of its local data after it
returns. For example, given the following function:
void a( void )
{
int *x;
x = b(); /* x points to a variable local to b() */
.
:
c();
.
:
printf( "%p", &x ); /* try to access x after c() has been called */
}
The int variable that x points to may not exist after function c is called,
causing an error on the printf statement.
Local data is stored temporarily on the stack, which may be used by the
operating system. If the operating system or another function needs some of
the stack space, it is likely that the original data will be overwritten. The
cause of this problem can be difficult to isolate, because the demand for stack
space is random and unpredictable.
To avoid this problem, declare the variables in the calling function or as
global variables.
ΓòÉΓòÉΓòÉ 14.17. Why Do My Window Procedures End Abnormally? ΓòÉΓòÉΓòÉ
Question:
Why do my window procedures end abnormally?
Answer:
Make sure that you prototype your window procedures to use the _System calling
convention. You can do this by including the appropriate system header file
from the Toolkit. You should also ensure your window procedures include the
EXPENTRY keyword, as described in the Toolkit documentation.
The VisualAge C++ compiler uses the _Optlink calling convention by default,
which is not compatible with the _System calling convention used by the OS/2
system to call window procedures. OS/2 APIs use _System linkage; _Optlink is
used for VisualAge C++ library functions.
It is easiest to use the _System keyword to give individual functions _System
linkage.
For more information on the calling conventions, see the Programming Guide.
ΓòÉΓòÉΓòÉ 14.18. Why Does Printing a _Seg16 Pointer Trap? ΓòÉΓòÉΓòÉ
Question:
I have a char * _Seg16 variable in my application. When I use it with string
functions like strupr, it works fine. However, when I try to print it with
printf, my program traps. Why?
Answer:
VisualAge C++ converts _Seg16 pointers to flat pointers depending on the
function prototype. The string functions always take char * variables, so the
conversion is done for you. However, because printf has a variable argument
list and can take any type, there is no prototype to convert the pointer.
To force the conversion, explicitly cast the _Seg16 pointer to the type you
want to print. For example, to print char * _Seg16 myptr as a string, code:
printf("%s\n", (char *)myptr);
ΓòÉΓòÉΓòÉ 14.19. What Is __EDCThunkProlog and Why Does It Trap? ΓòÉΓòÉΓòÉ
Question:
I have an application that uses both 16-bit and 32-bit modules. When I run it,
it traps in __EDCThunkProlog. What is this function, and why does it cause the
trap?
Answer:
__EDCThunkProlog is part of the VisualAge C++ runtime and is called in the
prolog of any 32-bit function that calls a 16-bit function. It ensures that the
32-bit function's parameters and local variables, as well as the 16-bit
function's parameters and the 16-bit stack, do not cross a 64K boundary on the
stack. If it traps, it usually indicates that you have insufficient stack to
run the 16-bit function correctly.
Check the value specified in your #pragma stack16 statement (the default value
is 4K). This value specifies how much stack __EDCThunkProlog reserves from your
program's stack for your 16-bit functions. If you set this value too low, your
16-bit functions may not have enough stack to run correctly.
Because the 16-bit stack is allocated from your program's stack, you may also
need to increase your program's stack size.
ΓòÉΓòÉΓòÉ 14.20. Why Does printf Work Incorrectly? ΓòÉΓòÉΓòÉ
Question:
When I call printf, why does it print the wrong thing or cause my program to
end abnormally?
Answer:
Make sure that the parameters you list in your format string match the
parameters you are actually passing to the function.
Possible problems include:
Passing a parameter of a different type than you have declared.
For example, the printf function in the following code fragment expects a
string variable, but is passed a variable of type int:
int a;
printf( "%s", a );
The correct printf call should read:
printf( "%d", a );
Passing a parameter of a different size than you have declared.
For example, the format string in the following code fragment indicates
that three variables of type int are expected, but the variables passed
are of type long, int, and short:
long l;
int i;
short s;
printf( "%d %d %d", l, i, s );
Because it reads in the bytes from storage, this call could have
unexpected results. The correct printf call should read:
printf( "%ld %d %hd", l, i, s );
Passing a parameter by reference instead of by value.
For example, in the following code fragment, the printf function expects
a variable of type int, but is passed the address of an int variable:
int a;
printf( "%d", &a );
The correct printf call should read:
printf( "%d", a );
ΓòÉΓòÉΓòÉ 14.21. Why Doesn't printf Output Display? ΓòÉΓòÉΓòÉ
Question:
How do I display a printf prompt on the screen before the program waits for an
answer from scanf?
Answer:
Because printf is line-buffered, its output appears only after a new-line
character or when the buffer is flushed. You can do one of three things:
1. Include a new-line character at the end of every printf statement (for
example,
printf("This will display immediately.\n");
2. Put a fflush(stdout); statement after any output to stdout that precedes
input from stdin. It is usually a good idea to fflush at every point
where you switch between stdout and stdin.
3. Change the buffering mode to unbuffered by calling setbuf or setvbuf at
the beginning of your program after any fopen or freopen statements, but
before any output to stdout:
setbuf(stdout, NULL);
setvbuf(stdout, NULL, _IONBF, 0);
Note that this last solution can make your program run more slowly.
In C++ programs, output from cout and cin is automatically displayed.
ΓòÉΓòÉΓòÉ 14.22. Why Does scanf Behave Unexpectedly? ΓòÉΓòÉΓòÉ
Question:
Why doesn't scanf behave as I expect it to? Sometimes it does not wait for
input, does not convert all input, or goes into an infinite loop.
Answer:
scanf works on streams of characters, not lines of input. It reads the
characters from the specified input stream and formats them according to the
conversion rules that you specify.
Here are some guidelines to follow when reading character input:
Use scanf for machine-generated input only.
Use a combination of the fgets and sscanf functions for user input.
Note: Do not substitute the gets function for fgets. If you use gets,
it is possible to overwrite the character array used to store the input,
and cause memory problems. With fgets, you control the number of
characters that the user can input.
Check the return count from the scanf functions to see how many fields
were processed.
Read the descriptions of the various formats carefully. Some formats
skip leading white space (for example, %d and %f) and others do not (for
example, %c). Remember to include the new-line character.
Remember that the scanf conversion characters are different from the
printf conversion characters.
The following examples show how scanf works and illustrate some possible
problems. All of the examples assume that the input is coming from the user.
The following statement reads an integer from the user:
scanf( "%d", &myint )
The program waits for you to enter a string of characters. If you enter:
25\n
the function reads the digits 2 and 5 and stops when it reads the first
non-decimal digit, the new-line character (\n).
If you instead enter:
13 74\n
the function reads the digits 1 and 3 and stops when it reads the blank,
which is the first non-decimal digit. The %d conversion skips any
leading whitespace characters such as a blank, the tab character (\t),
and the new-line character.
The 74\n remains in the input stream. Because the input stream is not
empty, the next call to scanf will read directly from the stream and will
not wait for user input.
It is possible to enter an infinite loop with a combination of scanf and
unexpected user input. Here is an example:
The following code fragment reads a set of numbers until a negative
number is entered.
answer = 0;
i = 0;
while (answer >= 0) {
scanf( "%d" , &answer );
myarray[i] = answer;
i++;
}
If you enter:
123XYZ\n
the first call to scanf reads 123 as a valid integer and stops at the X,
leaving XYZ\n in the input stream. Because the input stream is not
empty, the next call to scanf tries to read an integer from the stream.
Because X is not an integer, scanf never progresses through the input
stream, and you do not have the opportunity to enter new data. The
result is an infinite loop.
For more information on scanf, see the C Library Reference
ΓòÉΓòÉΓòÉ 14.23. Why Do Library Functions and APIs Not Work? ΓòÉΓòÉΓòÉ
Question:
When I call a library function or OS/2 API, it does not work or it causes my
program to end abnormally. Why?
Answer:
Make sure that you use the #include preprocessor directive to include the
header file that contains the prototype statement for the library function or
API.
Also make sure that you are using the correct calling convention. Use _Optlink
to call library functions. Use _System to call OS/2 APIs. Include the
appropriate header files to ensure that the functions and APIs you use are
prototyped correctly. If you change the default calling convention to _System
(with the /Ms compiler option), you must include header files for all library
functions you use.
Note: Use the /Wpro compiler option to warn about unprototyped functions. This
option is set by default.
ΓòÉΓòÉΓòÉ 14.24. Why Do Macros with Increment Operators Work Incorrectly? ΓòÉΓòÉΓòÉ
Question:
A statement in my C program behaves strangely. It deals with a combination of
a macro and increment operators. What is the problem?
Answer:
When you use a macro, make sure that you know how it will be expanded. If you
define a macro that repeats the input argument, problems might occur in
combination with increment (++) and decrement (--) operators.
As an example, given the following macro toupp:
#define toupp(c) islower(c) ? _toupper(c) : (c)
The following statement is intended to copy every character of source into
dest:
while (*dest++ = toupp(*source++));
After the toupp macro is expanded, the actual statement that is executed is:
while (*dest++ = islower(*source++) ? _toupper(*source++) : (*source++));
This increments source twice each time the loop is done, an unintended result.
ΓòÉΓòÉΓòÉ 14.25. Why Doesn't My Macro Resolve Correctly? ΓòÉΓòÉΓòÉ
I have defined a macro, but it does not always produce the correct answer.
Why?
Answer:
If your macro expands to an expression, make sure that you use parentheses when
you define the macro. You may get unexpected results if you use the macro in
the same statement as other operators. The precedence rules of the other
operators may interfere with the macro definition.
For example, given the following code:
#define DOUBLE(x) x+x
y = DOUBLE(2)+1; /* assigns 5 to y */
z = DOUBLE(2)*3; /* assigns 8 to z */
The last statement evaluates to 8 rather than to 12 because it expands to
z = 2 + 2 * 3. To prevent this problem, use parentheses when you define a
macro. For example, the above macro would give the expected results if it were
defined as:
#define DOUBLE(x) ((x) + (x))
ΓòÉΓòÉΓòÉ 14.26. Why Don't My Threads Work Correctly? ΓòÉΓòÉΓòÉ
Question:
In my program, why do threads other than thread one not work correctly?
Answer:
Ensure that:
You use the /Gs- compiler option to generate stack probes (which is the
default).
You use the /Gm compiler option to link with the multithread libraries.
If you started a thread with the DosCreateThread API, you call _endthread
to end the thread and perform the necessary termination actions. If you
used _beginthread to start the thread, _endthread is called implicitly
when the thread ends.
ΓòÉΓòÉΓòÉ 14.27. Why Do My Statements Have No Effect? ΓòÉΓòÉΓòÉ
Question:
I have a statement or a group of statements that does not seem to do anything.
Answer:
Make sure that you are not missing an end to a comment (*/). In the following
example, an ending comment is omitted, causing a statement to be skipped during
the compilation:
/* This comment has an incorrect terminator *\
...
here = (is > some) ? important : code;
...
/* This comment "accidentally" terminates the previous comment */
code = begins + working / fine->again;
A similar problem can occur with macro definitions. For example:
#define something(important) // An important macro \
this->gets(ignored) \
this->does(too)
Because of the line continuation character (\), the lines are spliced together
before the comment is processed. As a result, the second and third lines of the
macro become part of the comment. For this reason, avoid using // comments in
multi-line macro definitions.
The syntax highlighting in the VisualAge Editor can help you find this type of
problem.
ΓòÉΓòÉΓòÉ 14.28. Why Do Increment Operators Produce Unexpected Results? ΓòÉΓòÉΓòÉ
Question:
A section of my code is not producing the expected results. The statements use
the ++ and -- operators.
Answer:
Make sure that your statements do not depend on side effects of the ++ and --
operators. For example, because the result of the following statement depends
on when the ++ operator is evaluated and when the assignment is done, it may
produce inconsistent results:
s[i++] = t[i];
The order of these operations depends on the compiler being used and possibly
on the optimization requirements. One compiler may compute the source address
first (the right-hand side of the statement), while another may compute the
target address first (the left-hand side).
The same problem often occurs with function parameters. For example, given :
printf("%d %d %d\n", i++, i++, i++);
The parameters can be evaluated and passed in any order, so any code that
depends on a particular order of evaluation will most likely fail.
To produce consistent results, if you use the ++ or -- operators on a variable
within an expression, make sure that the variable appears only once within the
expression.
ΓòÉΓòÉΓòÉ 14.29. Why Do I Get a SYS2070 Error? ΓòÉΓòÉΓòÉ
Questions:
When I try to run my program, it does not run and the operating system
generates a SYS2070 error. Why?
Answer:
The program could not access an external reference. The linker may not have
been able to resolve all of the external references in your program.
Make sure you use the /NOI linker option to preserve the case of external names
when you link your program. This is the default. Do not use the /IGNORECASE
linker option.
See Why Do I Get Unresolved External Errors? for different causes of unresolved
external references.
ΓòÉΓòÉΓòÉ 14.30. Why Does My PM Application Disappear? ΓòÉΓòÉΓòÉ
Question:
Why does my PM application disappear without generating any messages?
Answer:
An exception has been generated and handled by an exception handler that has
terminated the program. A machine-state dump is sent to stderr, but because
the PM interface directs the stderr stream to a null output device, you do not
see the error messages.
Use the _set_crt_msg_handle function to redirect stderr to a file. You will
then be able to see the runtime messages, including exception messages and
machine-state information. Alternatively, you can write your own exception
handler to intercept the exception and handle it however you want.
ΓòÉΓòÉΓòÉ 14.31. Why Does My Program Work Incorrectly and Inconsistently? ΓòÉΓòÉΓòÉ
Question:
My program does not work properly. Sometimes adding or removing statements
changes how the program terminates or may even solve the problem temporarily.
Using a debugger changes the symptoms. What is the problem?
Answer:
There are several possible solutions to your problem:
Make sure that you are calling functions correctly.
If a parameter is missing, the program may replace the parameter with
arbitrary data to complete the function call. The VisualAge C++ compiler
checks for missing parameters if you define your functions using function
prototypes.
Note: Use the /Wpro compiler option to warn about missing prototypes.
This option is set by default.
If the incorrect type of parameter is used, the function misreads the
parameter list.
Make sure that there is not a semicolon at the end of a for, do, or while
statement.
When there is only one statement in the body of a loop, it is common to
code the loop in the following style:
for (... ; ... ; ...)
statement;
It is also a common error to accidentally add a semicolon to the end of
the first line. For example:
for (i = 0; i < SOMENUMBER; i++);
d[i] = 0;
The semicolon at the end of the for statement ends the body of the loop.
The second line, which is the intended body of the loop, is executed only
once.
To catch problems like this, use the /Weff compiler diagnostic option to
locate code that has no effect.
It is also a good idea to enclose the loop statements in braces ({ }).
Ensure that strings are terminated by a null byte.
When you initialize a string, you must include space for the null byte.
For example,
char str1[3] = "ab" /* allocates 'a', 'b', '\0' */
char str2[3] = "abc" /* allocates 'a', 'b', 'c'; no '\0' */
When you use a string, do not overwrite the null byte.
Because the null byte is used to indicate where the string terminates, a
string without the null byte can cause memory problems. If you use a
function such as strcpy on a string without the terminating character,
portions of the memory following the string may be overwritten, causing
problems with the current program or programs that are using that memory
space. Problems could appear immediately or only after the program is
run several times.
Note: Use debug memory management (/Tm option) to help find memory
corruption problems.
Check your function return types.
The compiler assumes that a function declared without a return type
returns an int. This could cause problems if your program is expecting a
different return type. Prototype your functions to avoid this problem.
If you declare an array in one file and reference it in another file
using extern, make sure that the extern statement has the same form as
the declaration statement.
For example, the following declarations are not equivalent:
/* File 1: Global Data definitions */
char x[100];
/* File 2: Using the global data */
extern char *x;
In the second file, the compiler generates code that assumes that the
address at x contains the address of the actual array. The correct
definition in File 2 is:
/* File 2: Using the global data */
extern char x[];
Ensure that you are not referencing beyond the last element of an array.
The first entry of an array is found at index 0 (for example, array[0]).
If you declare an array of size n, the array starts at element 0 and ends
at element n-1.
The following code fragment references beyond the last array element:
char stuff[10];
int i;
.
.
.
for (i = 0; i <= 10; i++) { /* test should have been i < 10 */
stuff[i] = ' ';
}
Referencing beyond the last element in the array may overwrite memory
locations and cause problems with variable data, functions, or the entire
program.
Ensure you use the malloc and free library functions correctly.
The malloc function returns a pointer to an area of memory that is at
least as large as you request. The free function releases memory
previously allocated by malloc.
Make sure that only pointers returned by the malloc function are passed
to the free function. To keep track of what memory is available, malloc
stores information in a section of memory adjacent to the pointer that it
returns. The free function uses this information to return the allocated
space to the list of available memory.
The free function does not check the pointer that it receives. If free
receives a pointer that was not set by malloc, memory problems can occur.
For example, other programs may get unauthorized access to your data
areas, program code, or parts of the operating system.
Also make sure that you do not use memory outside of the memory allocated
by malloc.
To help you find possible problems with these functions, use the debug
memory management functions. Memory management is described in the
Programming Guide; for descriptions of individual functions, see the C
Library Reference
ΓòÉΓòÉΓòÉ 14.32. Where Is the Message File? ΓòÉΓòÉΓòÉ
Question:
When I run my application on another machine, I get the message "Message file
not found". Why?
Answer:
The VisualAge C++ runtime cannot find the message file that contains the
runtime messages it needs.
To solve this problem, do one of the following:
Copy the runtime message files you need to a directory in the DPATH of
the machine running the program. The runtime message files are:
DDE4.MSG C runtime library and I/O Stream and Complex class
libraries.
IBMCRERR.MSG Regular expressions.
DDE4C01E.MSG Collection class libraries.
CPPOOC3U.MSG User Interface class libraries.
DAXCLS.MSG Database Access class libraries.
Use MSGBIND to bind the messages to your application's own runtime. (You
must do this if you will be shipping your application to other people.)
For more information about how to use MSGBIND and what messages you need, see
the section on MSGBIND in the User's Guide.
ΓòÉΓòÉΓòÉ 15. Debugging with the Debugger ΓòÉΓòÉΓòÉ
This section answers questions you may have while debugging your program with
the debugger.
When Should I Use Synchronous and Asynchronous Debugging Modes?
Can I Debug 16-Bit Code?
Can I Debug Optimized Code?
Why Do I Get A DosStartSession Error?
How Does the Debugger Locate Source Files?
Why Can't the Debugger Find the Source File?
How Do I Debug A DLL Called by A REXX Program?
How Do I Debug a WorkPlace Shell DLL?
Why Can't I Typecast in the Monitor Expression Dialog?
How Do I Debug SQC Files?
Can I Run Performance Analyzer and the Debugger at the Same Time?
ΓòÉΓòÉΓòÉ 15.1. When Should I Use Synchronous and Asynchronous Debugging Modes? ΓòÉΓòÉΓòÉ
Question:
When should I run the debugger in synchronous mode, and when should I run it in
asynchronous mode? What is the difference?
Answer:
The difference between the two modes appears when the program you are debugging
is stopped, such as at a breakpoint. In asynchronous mode, you can interact
with non-debugger applications, such as an editor. This is the usual mode for
running the debugger.
However, the debugger then interferes with the normal flow of messages to the
program you are debugging. The debugger responds to the PM messages of your
program in a default manner, so that it does not lock the PM input queue.
If you need to handle your program's messages in a specific way (other than the
default), or if the order of input messages is important, run in synchronous
mode. For example, if your application uses dynamic data exchange (DDE), you
should run in synchronous mode. You will not be able to use other applications
while the debugger is running, but you will capture all the messages to and
from your application.
ΓòÉΓòÉΓòÉ 15.2. Can I Debug 16-Bit Code? ΓòÉΓòÉΓòÉ
Question:
Can I use the VisualAge C++ debugger to debug my 16-bit code?
Answer:
The VisualAge C++ debugger recognizes both IBM and Codeview debugger data, so
you can use it to debug both the 32-bit and 16-bit parts of your application.
ΓòÉΓòÉΓòÉ 15.3. Can I Debug Optimized Code? ΓòÉΓòÉΓòÉ
Question:
Can I debug code that has been optimized?
Answer:
Yes, but you will not be able to use all debugger features. Because some
variables are placed in registers, you cannot monitor variables accurately. The
register and storage windows are both accurate.
To debug optimized code most efficiently, turn off the instruction scheduling
optimization (/Os-) when you compile, and use a mixed source and assembly view
to navigate through your code while using the register and storage windows.
ΓòÉΓòÉΓòÉ 15.4. Why Do I Get A DosStartSession Error? ΓòÉΓòÉΓòÉ
Question:
Why do I get a DosStartSession error when I start the debugger?
Answer:
The debugger starts your program using DosStartSession in trace mode.
DosStartSession does much more checking when trace mode is on, causing some
programs that seem to run correctly outside the debugger to fail under the
debugger. The most common errors and causes are:
Return Code Cause
2 A DLL referenced by the application could not be found.
127 A function in a DLL could not be found (usually because of a missing
EXPORTS line in a .DEF file).
182 An ordinal is invalid (usually caused by picking up a different
level of the DLL than was used to create the import library you
linked to).
ΓòÉΓòÉΓòÉ 15.5. How Does the Debugger Locate Source Files? ΓòÉΓòÉΓòÉ
Question:
How does the debugger locate the source files?
Answer:
The debugger looks in the following places in the following order:
1. The name stored in the .EXE file (from the icc command line)
2. The directory containing the .EXE file
3. The PMDPATH environment variable
4. The current directory
ΓòÉΓòÉΓòÉ 15.6. Why Can't the Debugger Find the Source File? ΓòÉΓòÉΓòÉ
Question:
Why is the debugger unable to find a source file unless the path and file name
are given in the Source Filename Incorrect dialog box?
Answer:
If you recompiled any of the code since the last time you used the debugger, it
may be unable to locate the source file.
If you compile in one directory and run in another, you should either use the
PMDPATH environment variable or put a qualified path on the ICC compile line,
For example, specify:
icc ./test.c
rather than:
ICC test.c
If your ICC command lines are created by the WorkFrame MAKEMAKE utility, check
the make file to see if it is using .\source or source.c on the command line.
ΓòÉΓòÉΓòÉ 15.7. How Do I Debug A DLL Called by A REXX Program? ΓòÉΓòÉΓòÉ
Question:
How do I debug a DLL called by a REXX program?
Answer:
1. Start the debugger with the command:
IPMD CMD.EXE /C your Rexx.cmd
2. When the debugger displays the code for CMD.EXE, set a load-type
breakpoint to stop at the DLL.
3. Select Run from the menu.
4. At the pop-up indicating your DLL has loaded, open the desired parts and
set breakpoints. Use deferred breakpoints to have them set in your next
debugger session.
5. Select Run again.
ΓòÉΓòÉΓòÉ 15.8. How Do I Debug a WorkPlace Shell DLL? ΓòÉΓòÉΓòÉ
Question:
How do I debug a WorkPlace Shell DLL?
Answer:
1. In your CONFIG.SYS file, add the following line:
SET RUNWORKPLACE=C:\OS2\CMD.EXE
2. Reboot your machine.
3. In the initial OS/2 window, enter IPMD C:\os2\pmshell
4. Set a Load-type breakpoint for the DLL containing the WPS program.
ΓòÉΓòÉΓòÉ 15.9. Why Can't I Typecast in the Monitor Expression Dialog? ΓòÉΓòÉΓòÉ
Question:
Why doesn't my typecasting work in the Monitor Expression Dialog?
Answer:
Complex user typecasting is only supported if you build your application with
the C++ runtime library. If you are compiling a C program, use the /Tdp
compiler option to compile it as a C++ program and include the C++ runtime
support.
ΓòÉΓòÉΓòÉ 15.10. How Do I Debug SQC Files? ΓòÉΓòÉΓòÉ
Question:
I am trying to debug some SQC files, but the debugger seems to get lost in
them. Is there a special option that I need to use?
Answer:
The problem originates in the SQL precompiler. To assist with error messages
when you're compiling your .SQC file, the precompiler brackets all the code it
adds to the .C with #line macros. Unfortunately, the #line macros can cause
debuggers to get confused.
To avoid this problem, tell the precompiler not to create the #line macros. You
can do this by modifying the option in your project's SQLPREP action, or by
setting the /# option in your SQLPREP statement. (If you're using SDK/2, add
NOLINEMACRO to your DB2 PREP statement instead.)
ΓòÉΓòÉΓòÉ 16. Tracing with Performance Analyzer ΓòÉΓòÉΓòÉ
This section answers questions you may have about using the Performance
Analyzer.
Note: In previous versions of C Set ++, the Performance Analyzer was called
EXTRA.
Why Can't Performance Analyzer Show My Executable or Object Files?
Why Can't Performance Analyzer Trace OS/2 API Calls?
Why Are There No Events in My Trace File?
Can Performance Analyzer Analyze Child Processes?
Why Can't I Open My Trace File?
Why Can't I View Execution Density or Time Line?
Why Doesn't the Trace File Show All Functions?
How Can I Make My Trace File Smaller?
Why Is My Trace File Incomplete?
Why Do I Get Dashes in the Statistical Summary?
Why Are Many Events Displayed as the Same String?
Why Is the User Event Information Unreadable?
Why Is the Annotate Choice Disabled?
Why Is the Pattern Recognition Choice Disabled?
Why Is the Include Functions Choice Unavailable?
Why Aren't All Events Displayed?
Why Doesn't the Dynamic Call Graph Display?
Why Can't Performance Analyzer Trace My DLL?
Why Can't I Manipulate the Focus in the Overview Window?
Why Can't I See the Function Names?
Why Can't I See My Annotations?
Can I Run Performance Analyzer and the Debugger at the Same Time?
ΓòÉΓòÉΓòÉ 16.1. Why Can't Performance Analyzer Show My Executable or Object Files? ΓòÉΓòÉΓòÉ
Question:
Sometimes my executable files don't appear in the trace generation window.
Other times, my executable file is shown in black, but Performance Analyzer
cannot show the object files. Why?
Answer:
You must compile and link your application with the correct options before you
can use Performance Analyzer.
To compile your application, use the following options:
/Gh Includes the profile hooks that allow Performance Analyzer to monitor
your executable.
/Ti Includes the debugging information in the compiled object (.OBJ) file.
To link your application, use the /DE option to include the debugging
information in the final executable (EXE or DLL file). You must also link
CPPOPA3.OBJ into your executable file.
ΓòÉΓòÉΓòÉ 16.2. Why Can't Performance Analyzer Trace OS/2 API Calls? ΓòÉΓòÉΓòÉ
Question:
Why can't Performance Analyzer trace my calls to the OS/2 APIs?
Answer:
To trace calls to the OS/2 APIs, specify the Performance Analyzer library for
the APIs immediately before the OS/2 libraries in your link statement:
For Dos APIs, use _DOSCALL.LIB.
For Win APIs, use _PMWIN.LIB.
For Gpi APIs, use _PMGPI.LIB.
Each of these libraries also has an associated DLL.
The order of the libraries in the link statement is critical. If the
Performance Analyzer libraries do not immediately precede the OS/2 libraries
in the link statement, Performance Analyzer may not interpret or trace the API
calls.
ΓòÉΓòÉΓòÉ 16.3. Why Are There No Events in My Trace File? ΓòÉΓòÉΓòÉ
Question:
Why are there no events logged in my trace file?
Answer:
Several things could have happened:
All functions were disabled in the Trace Generation window from the Edit
menu. See the online help for the Trace Generation Window for more
information.
The application needs more time to run. Use the Timeout Control choice in
the Trace Generation window to control how long your application can run.
If you set a trigger on a function, the triggered function may not have
been reached.
Your program was not compiled and linked with the correct options. (See
Why Can't Performance Analyzer Show My Executable or Object Files? for a
list of the options).
ΓòÉΓòÉΓòÉ 16.4. Can Performance Analyzer Analyze Child Processes? ΓòÉΓòÉΓòÉ
Question:
Can Performance Analyzer analyze child processes in a multiprocess application?
Answer:
No, Performance Analyzer does not provide this support.
ΓòÉΓòÉΓòÉ 16.5. Why Can't I Open My Trace File? ΓòÉΓòÉΓòÉ
Question:
I can't open a trace file from the command line. I know I successfully created
it; why can't I open it?
Answer:
Make sure you are typing the correct command:
To Display Enter
Statistical Summary icsperf /ss file.ext
Call Nesting icsperf /cn file.ext
Time Line icsperf /tl file.ext
Execution Density icsperf /ed file.ext
Dynamic Call Graph icsperf /cg file.ext
For more information, read the online help for the Trace Analysis Selection
window.
ΓòÉΓòÉΓòÉ 16.6. Why Can't I View Execution Density or Time Line? ΓòÉΓòÉΓòÉ
Question:
Why can't I open the Execution Density or Time Line diagram?
Answer:
If you chose to disable the time stamps from the Trace Generation window, these
diagrams do not display.
To view these diagrams, go to the Trace Generation window and from the Options
menu, make sure that Time stamp events has a check mark. Then create the trace
file again.
ΓòÉΓòÉΓòÉ 16.7. Why Doesn't the Trace File Show All Functions? ΓòÉΓòÉΓòÉ
Question:
Why doesn't the trace file show all the functions?
Answer:
One of three things may have occurred:
1. A trigger may have been set from the Trace Generation window. Read the
online help for Set Trigger for more information.
2. The call depth may be set to null or a low number. Read the online help
for Set Call Depth for more information.
3. Some of the functions may have been disabled before the trace. Read the
online help for the Trace Generation window for more information.
ΓòÉΓòÉΓòÉ 16.8. How Can I Make My Trace File Smaller? ΓòÉΓòÉΓòÉ
Question:
My trace file is very large. How can I make it smaller?
Answer:
To limit the trace file information to a more manageable number of events, you
can:
Use triggers to have a specific function start the trace. You can set
triggers from the Trace Generation window.
Add calls to PerfStart() and PerfStop() to your code, to specify to
Performance Analyzer when to begin and end tracing.
Disable functions, object files, or executables so they will not be
traced. You can do this from the Trace Generation window before you start
the trace.
Limit the tracing to specific threads or specific call depths per thread
by using Call Depth from the Options menu in the Trace Generation window.
If you set the call depth to 0 for a given thread, that thread will not
be traced.
ΓòÉΓòÉΓòÉ 16.9. Why Is My Trace File Incomplete? ΓòÉΓòÉΓòÉ
Question:
My trace file is missing some early events. Why?
Answer:
Your buffer may be set to overwrite the older events. See the online help for
the Buffer Control Action window for information on how to change the buffer.
ΓòÉΓòÉΓòÉ 16.10. Why Do I Get Dashes in the Statistical Summary? ΓòÉΓòÉΓòÉ
Question:
In the Statistical Summary display, why do I see "---" next to a function name?
Answer:
When you traced your application, there was not enough timing information
available for Performance Analyzer to analyze the function. You need to allow
more time for the function to run. Use the Timeout Control in the Trace
Generation window to control how much time is allowed.
ΓòÉΓòÉΓòÉ 16.11. Why Are Many Events Displayed as the Same String? ΓòÉΓòÉΓòÉ
Question:
In the Statistical Summary and Call Nesting diagrams, why are multiple
different user events incorrectly displayed as the same string?
Answer:
Make sure that the string you are passing to the PERF entry point is an ASCIIZ
string. The string must exist in storage when the trace buffer containing the
reference is written to disk.
Also make sure that you have included the correct prototypes for the PERF entry
point. For C programs, the prototype is:
void PERF(PSZ string);
For C++ applications, the prototype is:
extern "C" {
void PERF(PSZ string);
}
ΓòÉΓòÉΓòÉ 16.12. Why Is the User Event Information Unreadable? ΓòÉΓòÉΓòÉ
Question:
In the Statistical Summary and Call Nesting diagrams, why do user events
display with unreadable information?
Answer:
Make sure that the string you are passing to the PERF entry point is an ASCIIZ
string. The string must exist in storage when the trace buffer containing the
reference is written to disk.
Also make sure that you have included the correct prototypes for the PERF entry
point. For C programs, the prototype is:
void PERF(PSZ string);
For C++ applications, the prototype is:
extern "C" {
void PERF(PSZ string);
}
ΓòÉΓòÉΓòÉ 16.13. Why Is the Annotate Choice Disabled? ΓòÉΓòÉΓòÉ
Question:
In the Call Nesting diagram, why is the Annotate choice disabled?
Answer:
When the Pattern Recognition choice is enabled, the Annotate choice is not
available. Disable pattern recognition before selecting Annotate.
ΓòÉΓòÉΓòÉ 16.14. Why Is the Pattern Recognition Choice Disabled? ΓòÉΓòÉΓòÉ
Question:
In the Call Nesting diagram, why is the Pattern Recognition choice disabled?
Answer:
You must select a single thread using the Include threads option from the View
menu:
1. Select the View menu.
2. Select Include threads.
3. Select the thread you want to view, and then select the Use pattern
recognition option.
If the trace file is large, pattern recognition is not available. If this is
your problem, the Include threads menu item is disabled (grayed out). See How
Can I Make My Trace File Smaller? for ways to reduce the size of your trace
file.
ΓòÉΓòÉΓòÉ 16.15. Why Is the Include Functions Choice Unavailable? ΓòÉΓòÉΓòÉ
Question:
In the Call Nesting diagram, why isn't the Include functions choice from the
View menu available?
Answer:
This choice is only available when all threads are displayed. If you have
enabled a specific thread from the Include threads menu (also from the View
menu), you must deselect the pattern recognition checkbox and select the All
Threads choice before you can use Include functions.
ΓòÉΓòÉΓòÉ 16.16. Why Aren't All Events Displayed? ΓòÉΓòÉΓòÉ
Question:
Why isn't the Execution Density diagram displaying all of the events?
Answer:
Check your settings in the diagram:
1. Check which functions are included in the display by selecting Include
functions from the View menu.
2. Check which threads are included in the display by selecting Include
threads from the View menu.
ΓòÉΓòÉΓòÉ 16.17. Why Doesn't the Dynamic Call Graph Display? ΓòÉΓòÉΓòÉ
Question:
Why doesn't the Dynamic Call Graph display?
Answer:
If your trace file contains only one function per thread, no dynamic calls are
made and therefore the Dynamic Call Graph does not display.
ΓòÉΓòÉΓòÉ 16.18. Why Can't Performance Analyzer Trace My DLL? ΓòÉΓòÉΓòÉ
Question:
Why can't Performance Analyzer trace my dynamically-loaded DLLs?
Answer:
Make sure you compiled the DLLs with the correct options (/Gh to enable
profiling and /Ti to generate debug information), and linked using the /DE
option to include debug information in the DLL. You must also link CPPOP3A.OBJ
into your DLL.
Note: Previous versions of C Set ++ did not support tracing dynamically-loaded
DLLs.
ΓòÉΓòÉΓòÉ 16.19. Why Can't I Manipulate the Focus in the Overview Window? ΓòÉΓòÉΓòÉ
Question:
In the Dynamic Call Graph, why can't I manipulate the grey box in the Overview
window to change the focus?
Answer:
Increase the size of the Overview window. (Press mouse button 1 on the corner
of the window and drag it.)
ΓòÉΓòÉΓòÉ 16.20. Why Can't I See the Function Names? ΓòÉΓòÉΓòÉ
Question:
In the Dynamic Call Graph and Time Line diagram, why can't I see the names of
the functions?
Answer:
You need to increase the size of the diagram. Use Zoom In to magnify the
function names.
ΓòÉΓòÉΓòÉ 16.21. Why Can't I See My Annotations? ΓòÉΓòÉΓòÉ
Question:
In the Call Nesting diagram, why can't I see my annotations?
Answer:
You need to disable the Pattern Recognition to see the annotations.
ΓòÉΓòÉΓòÉ 16.22. Can I Run Performance Analyzer and the Debugger at the Same Time? ΓòÉΓòÉΓòÉ
Question:
Can I run Performance Analyzer and the debugger at the same time?
Answer:
No. Because of operating-system limitations, you cannot run Performance
Analyzer and the debugger at the same time.
ΓòÉΓòÉΓòÉ 17. Browsing Your Program ΓòÉΓòÉΓòÉ
This section answers questions about using the VisualAge C++ Browser to
understand your program.
Will the Browser Work with Old .BRS or .PDB Files?
What is QuickBrowse and Why Should I Use It?
Why Doesn't QuickBrowse Show Class Template Instances?
What Is the Difference Between /Fb and /Fb*?
What Are the .PD* Files?
What Does the Hold Button Do?
What Do the Blue Initials in Front of the Names Mean?
Can I Browse SOM Classes?
Can I Browse Programs Written in Other Languages?
What Does Merge Do and Why Should I Use It?
Why Can't I Edit Definitions for Library Member Functions?
Why Are Some Pop-Up Menu Items Disabled?
Why Doesn't Show Documentation Work with My Own Classes?
What Does the Order Menu Choice Do?
Where Is the Source View of My Functions?
Why Is the Text in the Graph So Small?
Why Is QuickBrowse Not Always Available?
How Do I Zoom Into a Small Area on a Graph?
What Are Anonymous Types?
What are Compiler-Generated Constructors and Destructors?
What Does 'n' Instances Mean?
What do Print Client and Print Zone Mean?
What does Weighting Do in the Graph Window?
In What Format Are the Graph Pictures Saved?
ΓòÉΓòÉΓòÉ 17.1. Will the Browser Work with Old .BRS or .PDB Files? ΓòÉΓòÉΓòÉ
Question:
Will the browser work with my old .BRS files from other versions of
VisualAge C++, or with my .PDB files from C Set ++ for AIX?
Answer:
No, you can only use the browser with .PDB files generated by this version of
the VisualAge C++ compiler. Unless you want to continue using the old browser,
you can delete the .BRS files.
ΓòÉΓòÉΓòÉ 17.2. What is QuickBrowse and Why Should I Use It? ΓòÉΓòÉΓòÉ
Question: What is QuickBrowse, why would I want to use it, and how can I make
use of it? How is it different from compiling with the Generate Browser
information (/Fb) option?
Answer:
Use QuickBrowse to quickly obtain and browse type information for code for
which there is no compiler-generated (/Fb) browser information. Use QuickBrowse
because it is faster than compiling your code, and because you may be able to
browse files that do not compile. (Because QuickBrowse parses your code and
ignores function bodies, as long as the type information is complete and valid,
you can browse it with QuickBrowse.)
For example, QuickBrowse is well-suited for:
Understanding class library interfaces.
Browsing code you are porting to OS/2 from another platform.
Understanding an existing code base.
Aiding in the design of new code.
For more information on how to accomplish these tasks with QuickBrowse, see
the Browser How Do I help.
To use QuickBrowse, invoke the browser on your project. If compiler-generated
browser information is not available, the browser displays a window to tell
you the information is missing. From this window, you can choose to invoke
QuickBrowse for the files where data is missing. While QuickBrowse runs,
messages appear in the project's monitor, just as if you were doing a Build.
Although QuickBrowse is faster than compiling, compiler-generated browser
information is more complete than that generated by QuickBrowse. Because
QuickBrowse disregards function bodies, any information in that function body,
including information about calls and thrown exception types, is not included.
If you need this information, compile your source files to generate browser
information.
Note: QuickBrowse is only available when you invoke the browser on a
VisualAge C++ project. If you start the browser from the desktop icon or
command line, QuickBrowse is not available.
ΓòÉΓòÉΓòÉ 17.3. Why Doesn't QuickBrowse Show Class Template Instances? ΓòÉΓòÉΓòÉ
Question:
When I use QuickBrowse, class template instances do not appear in any list of
classes, and listing the instantiations for the templates gives no results.
Why?
Answer:
When you QuickBrowse source files, any class template instances at file scope
appear as global variables. For example, given the following source code:
template<class T> class foo {
T* bar;
};
foo<int> boo;
QuickBrowse produces one class named foo<class T> and one global variable boo
of type foo<class T>.
ΓòÉΓòÉΓòÉ 17.4. What Is the Difference Between /Fb and /Fb*? ΓòÉΓòÉΓòÉ
Question:
What is the difference between the compiler options to generate browser
information (/Fb) and generate all browser information (/Fb*)?
Answer:
The difference between the two options relates to how much browser information
is generated from system header files (specified in angle brackets < > instead
of double quotation marks).
The generate browser information (/Fb) option discards much non-type
information from system header files:
Non-member function declarations are not included in the .PDB file,
including those C and OS/2 header files. Any friendship granted to any
such omitted functions will not be recorded for a class. For example,
given the following declarations:
// in <foo.h>
int foobar(void);
// in "bar.h"
class bar {
friend int foobar(void);
}
This friendship will not be included in the list of friends of class bar.
No global variable declared or defined in the system header files is
included in the .PDB file. This includes variables of an instantiated
template type.
Class member functions declarations will be emitted, but their inline
definitions, if any, will not appear in the .PDB file.
Non-inline function definitions will not be emitted in the .PDB file.
When you choose to generate all browser information (/Fb*), the above
information is included.
Note: In general, you should only use /Fb to generate browser information.
The compiler generates a message if you should use /Fb* instead.
ΓòÉΓòÉΓòÉ 17.5. What Are the .PD* Files? ΓòÉΓòÉΓòÉ
Question:
What are the .PD* files?
Answer:
The .PDB files are output by the C++ compiler. There is one for every OBJ file.
When you browse a target file (.EXE, .DLL, or .LIB), the individual .PDB files
(for the .OBJ files contained in the target) are loaded into memory by the
browser. A copy of this digested data is quickly saved when you stop browsing
the target file, and is quickly loaded when you browse the target file again.
The extension of the saved file is based upon the extension of the target file:
data for a .EXE file is saved in a .PDE file, DLL data in a .PDD file, and LIB
data in a .PDL file. Manually loading one or more .PDB file or performing a
Merge operation is analogous to grouping a set of .OBJ files together into a
single .LIB file, so the saved file version in this case is a .PDL file.
ΓòÉΓòÉΓòÉ 17.6. What Does the Hold Button Do? ΓòÉΓòÉΓòÉ
Question:
What does the Hold button do?
Answer:
Typically, the results of any one action will overlay the contents of the first
window of the right type for the action (for example, a List All Files action
changes the content of the first List window). However, there may be times when
you want to maintain the contents of that window, for example, to keep the list
of all classes available as you look at the contents of different classes.
When you push the Hold button, the contents of the window are maintained as
they are and the results of any action you perform are placed in a separate
window.
ΓòÉΓòÉΓòÉ 17.7. What Do the Blue Initials in Front of the Names Mean? ΓòÉΓòÉΓòÉ
Question:
What do the blue letters in front of names mean?
Answer:
The letters are shorthand icons for common C++ attributes:
V virtual
S static
C const
P pure virtual
E enum
You can choose to see the attribute icons only, the full text only, or both,
using the Styles page in the List Window Settings Notebook.
ΓòÉΓòÉΓòÉ 17.8. Can I Browse SOM Classes? ΓòÉΓòÉΓòÉ
Question:
Can I browse SOM classes?
Answer:
Yes and no. You can browse SOM classes compiled with the Direct-to-Som (DTS)
feature of the VisualAge C++ compiler. You cannot browse SOM classes defined in
IDL unless you generate C++ bindings for these classes, and then compile them
with the DTS compiler support.
ΓòÉΓòÉΓòÉ 17.9. Can I Browse Programs Written in Other Languages? ΓòÉΓòÉΓòÉ
Question:
Can I use the browser to browse programs written in other languages like
Object-Oriented REXX, Object-Oriented Cobol, or C?
Answer:
No. While some similarity exists between C++ and these other OO languages,
this is a C++ class browser. You can browse C files to some extent by compiling
them as C++ files. However, the data you obtain has limited value because
there are no classes in the C language. (Structures and unions are similar to
C++ classes, except that they only contain data members). File and function
information will be present, however.
ΓòÉΓòÉΓòÉ 17.10. What Does Merge Do and Why Should I Use It? ΓòÉΓòÉΓòÉ
Question:
What does Merge do? Why would I want to use it?
Answer:
When you browse a target program (executable file, DLL, or library), you only
see those classes, functions, and files that were actually used in the program.
You do not see related objects. For example, assume that you have written a
small program using the User Interface library, and it contains an
IFrameWindow, a menu bar, and some static text. Next you want to add push
buttons and a bitmap onto your window. You can merge the User Interface
Library data (all of it) with your program's data, and see all the interface
facts about all the classes in the User Interface library.
Also, many programs are written as a .EXE file and one or more DLLs. If you
browse the .EXE file, you only see the data from that file. You can merge in
the data from the DLLs to see the whole program's information.
ΓòÉΓòÉΓòÉ 17.11. Why Can't I Edit Definitions for Library Member Functions? ΓòÉΓòÉΓòÉ
Question:
Why can't I edit the definitions for members of the Open Class library that are
listed in the Load menu. Why not?
Answer:
The browser differentiates between declarations and definitions of objects. The
Edit Definition action edits the file where the object is defined. A function
is defined where it is implemented. If you don't have the body of the function
in any of the files that make up the target that you are browsing (for instance
it may a function from a library), the browser cannot edit the function.
Editing the file containing the declaration for a function whose full prototype
is displayed in the browser would not give any more useful information than you
already have. Also, a function's declaration can appear in multiple files, and
may be (subtly) different in each location. Only your Build process will help
you find all problems with mismatched function prototypes.
ΓòÉΓòÉΓòÉ 17.12. Why Are Some Pop-Up Menu Items Disabled? ΓòÉΓòÉΓòÉ
Question:
Why are some items greyed out (disabled) on pop-up menus?
Answer:
The browser prechecks the contents of its database to see if certain actions
are valid. For objects without definitions, it greys out the Edit Definition
action. For classes that have no base class, it greys out both Graph All Base
and Derived Classes and Graph All Base Classes actions. The Expand Typedef
action only appears on type objects that are typedefs.
The prechecks are done when it is possible to do so quickly. Some actions
require the entire database to be searched for answers. An example of this is
the List Friendships action. This particular action is not prechecked and if
invoked on a class that has not been identified as the friend of any other
class, you will see the "No results were found" response.
ΓòÉΓòÉΓòÉ 17.13. Why Doesn't Show Documentation Work with My Own Classes? ΓòÉΓòÉΓòÉ
Question:
Show documentation does not work with my own classes or functions. Why not?
Answer:
The VisualAge C++ Open Class Library provides special files that enable Show
documentation to display details about particular classes and members. To
enable Show documentation for other classes, including your own, you must
provide:
1. An online document in .INF format that describes the classes. For
information on creating online documentation, see the IPF Guide and
Reference.
2. An index file that lists the classes or members along with information
about where they are described. For information on creating index files,
see the documentation for KwikINF in the User's Guide.
ΓòÉΓòÉΓòÉ 17.14. What Does the Order Menu Choice Do? ΓòÉΓòÉΓòÉ
Question:
What does the Order menu choice do? Why is it sometimes greyed out (disabled)?
Answer:
The Order choice is enabled only when you are looking at the results of a List
Members with Inheritance action. The browser displays all the members of a
class, and all the members that that class inherits from its base classes.
The default order, Class, presents the name of the selected class first,
followed by its base classes. When you expand the + on one of these classes,
you see public, protected, and private; these are the Access levels. If you
expand the + on one of these access levels, you see constructors/destructors,
functions, and so on; these are the Type levels.
If you are interested in the public functions of a class (and all the other
classes through inheritance), you can use a different order to group the
functions that are spread throughout the window. If you sort by Access order,
the items are grouped according to public, protected, and private. If you sort
the information by its Type, you see grouped together all the functions, all
the variables, and so on.
Experiment with the ordering to find out what best suits your needs.
ΓòÉΓòÉΓòÉ 17.15. Where Is the Source View of My Functions? ΓòÉΓòÉΓòÉ
Question:
Where is the source view of my functions?
Answer:
You can see the source for any program object by displaying the pop-up menu for
the object, and selecting the Edit Definition action. This starts your editor
on the file containing the definition of the object. This menu option may be
greyed out if the definition of the object is not available; see Why Can't I
Edit Definitions for Library Member Functions? for more details.
Other C++ and Smalltalk browsers contain a small edit window which is linked to
other list boxes etc. in their browser. This has a number of drawbacks:
The small edit windows introduce yet another editor that you may not want
to use. The VisualAge C++ browser uses your choice of editor, the same
one that you use all the time.
The edit window is small. With small windows you spend more time
scrolling and resizing than you do understanding.
Programming with C++ is not the same as Smalltalk. In Smalltalk, all of
your program's classes and methods are stored in some environment-aware
database, not the file system. When you program in C++, you are still
using files, and frankly the performance of opening a new file, and
locating a line just because the user changed focus or scrolled up with
the arrow keys is slow.
ΓòÉΓòÉΓòÉ 17.16. Why Is the Text in the Graph So Small? ΓòÉΓòÉΓòÉ
Question:
Why can't I read the text in nodes in the drawn graph? Why does the text get
smaller when I zoom in?
Answer:
One problem with drawing an arbitrary graph on a fixed size window is that as
more and more items are displayed in the graph, the size of the items becomes
so small that any associated label is too small to read. That is what is
happening here. The type of font used in the window can also make it worse.
The text does not really grow smaller when you zoom in; it just seems to. If
the font used in the labels in the graph is a bitmap font, then the Graph
Window is limited to the available sizes in that font. The text does not
shrink, but the box around the text grows larger.
If the font used is an Outline (or Vector) font, then the Graph Window is not
limited to a small set of available sizes, but can draw the text in a size that
fits the containing box. Outline fonts are marginally slower in performance
than Bitmap fonts, so a large graph with a lot of node text would draw more
slowly when an Outline font is used.
ΓòÉΓòÉΓòÉ 17.17. Why Is QuickBrowse Not Always Available? ΓòÉΓòÉΓòÉ
Question:
Sometimes I can't use QuickBrowse. Why?
Answer:
The QuickBrowse feature of the browser is not available unless you are browsing
a project. If you started the browser from the command line, or by
double-clicking on its desktop icon, then you are not browsing a project, and
QuickBrowse is not available.
ΓòÉΓòÉΓòÉ 17.18. How Do I Zoom Into a Small Area on a Graph? ΓòÉΓòÉΓòÉ
Question:
How do I zoom into a small area on a Graph?
Answer:
You can do this in one of two ways:
1. Use the mouse to select an area to zoom to. Move the mouse to the corner
of where you want to zoom, hold down mouse button 1, and drag the mouse
to the opposite corner of the area. A small box appears between the
first point and the mouse pointer. Release the mouse button, press mouse
button 2 to display the pop-up menu, and select Zoom in.
2. Select a node, and then either press Ctrl-C, or use mouse button 2 to
display the pop-up menu, and select the Center action. This centers the
picture on that point or node. Then zoom in using one of:
The zoom slider control on the left side of the window
The Zoom in or Max Zoom in actions from either the View menu or from
the window background pop-up menu.
The Ctrl and + keys (equivalent to Zoom in).
The Alt and + keys (equivalent to Max Zoom in).
ΓòÉΓòÉΓòÉ 17.19. What Are Anonymous Types? ΓòÉΓòÉΓòÉ
Question:
Sometimes I see types called [anonymous]. What are they?
Answer:
Both the C and C++ languages have the concept of anonymous, or unnamed,
structures, unions and enumerated types. For example, each of the types below
is anonymous:
struct {
int number;
int code;
char *name;
} record;
union {
int a;
char b;
};
enum { red, yellow, green } color_1, color_2;
ΓòÉΓòÉΓòÉ 17.20. What are Compiler-Generated Constructors and Destructors? ΓòÉΓòÉΓòÉ
Question:
What are compiler-generated constructors and destructors, and why do I see them
in my browser files?
Answer:
When you define a class, but do not define your own default constructor, copy
constructor, or destructor, the compiler will implicitly generate one for you.
They are included to inform you that they are there.
ΓòÉΓòÉΓòÉ 17.21. What Does 'n' Instances Mean? ΓòÉΓòÉΓòÉ
Question:
What does ('n' Instances) mean?
Answer:
When you use multiple inheritance, and two (or more) of your base classes
inherit from a common class, you end up with an inheritance hierarchy like one
of the following:
Nonvirtual inheritance was used by B and C when they inherited from A, but
virtual inheritance was used by F and G when they inherited from E. An object
of type D will contain two copies of the data contained in an object of type A.
An object of type H will contain only one copy of the data contained in an
object of type E.
To highlight this non-diamond shape inheritance structure to you, the browser
indicates when a derived class contains more than one copy of the data from a
base class.
ΓòÉΓòÉΓòÉ 17.22. What do Print Client and Print Zone Mean? ΓòÉΓòÉΓòÉ
Question:
What do Print Client and Print Zone mean in the Graph Window?
Answer:
A client is the client area in the graph window, meaning the part of the graph
that you can see on your screen in the window. (What is shown in the window is
not necessarily the entire graph.) Print Client prints the contents of this
client area on a single page.
A zone is a rectangular area that you select in the graph. Print Zone prints
the contents of a zone on a single page.
ΓòÉΓòÉΓòÉ 17.23. What does Weighting Do in the Graph Window? ΓòÉΓòÉΓòÉ
Question:
What does Weighting (from the View menu) do in the Graph Window?
Answer:
Different graph layouts look better one way (for particular graph contents)
than others. For instance, some wide graphs with wide nodes look best when
shown horizontally, while narrower graphs look best when shown vertically.
Also, graphs can be drawn with all roots of a tree at an equal height, all
leaves at an equal height, or something somewhere in between. Consider the
following three layouts for the same graph: You can choose to lay out a graph
differently so that you can better understand its contents. You may find this
helpful in some situations.
ΓòÉΓòÉΓòÉ 17.24. In What Format Are the Graph Pictures Saved? ΓòÉΓòÉΓòÉ
Question:
In what format are the Graph pictures saved?
Answer:
The pictures are saved as OS/2 bitmap (.BMP) files. To specify the size of the
bitmap to save, see the Bitmap page of the Graph settings notebook.
ΓòÉΓòÉΓòÉ 18. Preparing to Ship Your Application ΓòÉΓòÉΓòÉ
This section answers questions you may have as you prepare to ship your
application to other customers.
Which VisualAge C++ DLLs Can I Ship with My Product?
Should I Build My Own C Runtime DLL?
Can I Rebuild the User Interface Class Library DLLs?
Should I Bind Runtime Messages to My Application?
Can I Use Multiple C Runtime Libraries?
How Do I Imbed a Copyright Statement?
ΓòÉΓòÉΓòÉ 18.1. Which VisualAge C++ DLLs Can I Ship with My Product? ΓòÉΓòÉΓòÉ
Question:
Which VisualAge C++ DLLs can I ship with my product?
Answer:
You can ship any or all of the following DLLs with your product, provided you
rebuild them with another name or rename them using DLLRNAME:
CPPOM30.DLL
CPPON30.DLL
CPPOS30.DLL
CPPOOU3.DLL
CPPOOD3.DLL
CPPOOM3.DLL
CPPOOB3.DLL
CPPOOC3.DLL
CPPOOR3.DLL
CPPOOV3.DLL
CPPODS3.DLL
CPPODI3.DLL
CPPOOR3U.DLL
CPPOOR3J.DLL
CPPOOR3K.DLL
CPPOOR3T.DLL
CPPOOR3P.DLL
Refer to the License Information booklet for details on shipping VisualAge C++
libraries.
Note that if you use the class library resource DLLs, in addition to renaming
them, you must call IApplication::current().setResourceLibrary() in your
application, specifying the new DLL name.
You can also create your own runtime libraries and export the C library
functions from them. See the Programming Guide for more information on
creating your own runtime libraries.
ΓòÉΓòÉΓòÉ 18.2. Should I Build My Own C Runtime DLL? ΓòÉΓòÉΓòÉ
Question:
Should I build my own C runtime DLL to ship with my program? How do I do it?
Answer:
If you own a whole application that contains multiple .DLL and .EXE files, you
should create a runtime DLL with only the functions your application requires
and have all your components dynamically link to that DLL. The advantages are:
1. Your application is smaller.
2. Your application is faster, because only one copy of the runtime
environment needs to be created for each process.
3. The working set is smaller for the same reason as in Should I Build My
Own C Runtime DLL?.
4. You can allocate memory in one module and free it in another.
5. You can open files in one module, read and write in another module, and
close them in another module.
6. All exceptions are handled by one common runtime environment.
If you do not own the whole application and you need to supply a standalone
DLL, you should statically bind the C runtime to your DLL. Make sure that you
use the #pragma handler on all the entry points to the DLL, to ensure that any
exceptions that occur within your DLL are handled. However, you lose the
advantages mentioned in points 4 and 5 above.
VisualAge C++ includes the .DEF files that are used to build the runtime DLLs
shipped with it. Do not be concerned about internal functions, because the
linker links in everything it needs to resolve all external references.
To make your own runtime DLL:
1. Rename the appropriate .DEF files that are provided in the LIB
subdirectory where you installed VisualAge C++. For example, to create a
multithreading DLL, rename CPPOM30.DLL to MYCRTDLL.DEF.
Remember to change the DLL name on the LIBRARY line of the .DEF file.
2. Remove the STUB line from the .DEF file. Remove unwanted functions from
the .DEF file. Remember not to delete anything that is followed by a
**** comment: these variables and functions are always required.
3. Create an empty source file, for example, MYCRTDLL.C.
4. Compile and link the files as follows:
icc /Ge- <options> MYCRTDLL.C MYCRTDLL.DEF
and use one of the following options: /Gm, /Gm-, or /Rn, according to
what type of DLL you want to build.
5. Build the import library as follows:
IMPLIB /NOI MYCRTDLL.LIB MYCRTDLL.DEF
6. Use the ILIB utility to add the necessary real objects to the import
library, as follows:
ILIB MYCRTDLL.LIB +CPPOx30.LIB
where x is M, S, or N, according to whether you want a multithread,
single-thread, or no runtime environment.
7. Compile your .EXE or .DLL files with the /Gn option. When you link,
specify your own libraries, including MYCRTDLL.LIB and OS2386.LIB.
If you want to rebuild the class library DLLs, see Can I Rebuild the User
Interface Class Library DLLs?.
ΓòÉΓòÉΓòÉ 18.3. Can I Rebuild the User Interface Class Library DLLs? ΓòÉΓòÉΓòÉ
Question:
I need to ship the User Interface class library DLLs with my application, but
they are very large. Can I rebuild them so I use only what I need?
Answer:
Yes. To rebuild the User Interface class library DLLs:
1. Change to the ICLUIDLL directory under your install directory.
2. Extract the object files you need from the Open Class static library (in
the LIB directory), using GETOBJS. For example:
GETOBJS ..\LIB\CPPOOC30.LIB
3. Identify the .OBJ files you need for the classes you use. If your
application uses any of the classes in a given .OBJ file, you need that
file. Use the cross-reference tables in the Open Class Library Reference
to determine which .OBJ files implement which classes. (The tables list
the .HPP files, but also apply for the .OBJ files.) Note that some
classes are implemented in multiple .OBJ files, which are numbered
sequentially (for example, IRESLIB.OBJ, IRESLIB1.OBJ, and so on); for
these classes, you must include all of these .OBJ files or none of them.
4. Edit the .RSP files and remove the lines for the .OBJ files you don't
need. (The .RSP files are in the ICLUIDLL directory.)
5. Edit the .DEF files and remove the export entries for the .OBJ files you
don't need. (The .DEF files are in the ICLUIDLL directory.)
6. Delete the .OBJ files you don't need from the ICLUIDLL directory.
7. Link the remaining .OBJ files, using the .RSP and .DEF files.
For more information on the Open Class library and how to rebuild the library
DLLs, see the Open Class Library User's Guide For information on building your
own runtime library DLLs, see Should I Build My Own C Runtime DLL?.
ΓòÉΓòÉΓòÉ 18.4. Should I Bind Runtime Messages to My Application? ΓòÉΓòÉΓòÉ
Question:
Should I bind the runtime message files to my application? What message files
do I need?
Answer:
It depends. You do not need to bind them if your application runs only on
machines where VisualAge C++ is installed, or if all of the following are true:
You do not use the assert, perror, or strerror functions.
You did not compile with the /Tm option to enable the debug memory
management functions.
You do not want compiler-generated trap information.
You do not use any of the class library runtime messages.
If you are shipping your application to other machines that may not have
VisualAge C++ installed, you should probably bind the runtime messages into
the application. You can use MSGBIND to do this. MSGBIND is described in the
User's Guide.
The message files you may need are:
DDE4.MSG Messages for the C runtime library and for the I/O Stream and
Complex class libraries.
IBMCRERR.MSG Messages for regular expressions.
DDE4C01E.MSG Messages for the Collection class libraries.
CPPOOC3U.MSG Messages for the User Interface class libraries.
DAXCLS.MSG Messages for the Database Access class libraries.
The message files are in the HELP subdirectory under your main install
directory. For information on specifying what messages to bind, refer to the
MSGBIND section in the User's Guide.
ΓòÉΓòÉΓòÉ 18.5. Can I Use Multiple C Runtime Libraries? ΓòÉΓòÉΓòÉ
Question:
I don't know which runtime libraries other people will use with my DLL. Is
there any way I can use multiple runtimes?
Answer:
You can have more than one C runtime (and its associated environment) in an
.EXE and its associated DLLs. However, the following restrictions apply:
1. You can read from and write to a stream opened in another library
environment, but you cannot use freopen or fclose on it.
2. fcloseall, fflushall, and similar functions work only for streams opened
in the environment in which they were called.
3. Signal handling is separate for each environment.
4. When you move from one environment to another, the entry point to the
destination environment must have a #pragma handler statement to ensure
that exception and signal handling functions correctly.
5. If a thread executes in several runtime environments, it may not
completely clean up its thread-specific storage when it terminates.
Normally this is not a problem, but can generate strange results if you
depend on everything being set to default values when you start a thread
(signal handlers, random number seeds, and so on).
6. Each environment has its own errno and _doserrno values.
7. The strtok, putenv, and getenv functions only work within a library
environment.
ΓòÉΓòÉΓòÉ 18.6. How Do I Imbed a Copyright Statement? ΓòÉΓòÉΓòÉ
Question:
What is the best way to imbed a copyright statement at the beginning of an
executable file or DLL?
Answer:
Compile a small DOS application with the copyright statement in it, and use it
as the DOS stub. It is put right at the beginning of the .EXE module. This
ensures that the copyright is near the beginning of the file, and also sets up
the executable so it can issue appropriate statements if it is run under DOS by
mistake.
The example that follows is similar to the stub used by VisualAge C++, and is
based on assembler. You can create your stub using any DOS assembler or
compiler.
;******* Data Segment (copyright statement)
DSEG SEGMENT PARA PUBLIC 'DATA'
__COPYRIGHT DB 0dh,0ah
DB 'IBM(R) VisualAge(TM) C++ for OS/2(R), Version 3', 0dh,0ah
DB '(C) Copyright IBM Corp. 1991, 1995.', 0dh,0ah
DB ' - Licensed Material - Program-Property of IBM - All Rights Reserved.', 0dh,0ah
DB 0dh,0ah
DB 'This program will not run in DOS mode'
DB 0dh,0ah
DB 24h ; End marker for DOS call
DB 1ah ; EOF marker
DSEG ENDS
;****** Code segment (Assembler stub to print copyright in DOS)
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG,SS:STACK ;Already set by dos loader
ENTPT PROC FAR ;entry point from DOS
PUSH DS ;set up the stack to have
XOR AX,AX ; the double word vector so the
PUSH AX ; far return will go back to DOS
MOV AX,DSEG ;set up addressability to
MOV DS,AX ; the data segment
ASSUME DS:DSEG ;tell assembler what I just did
;****** Call DOS to print the copyright notice
MOV DX,OFFSET DS:__COPYRIGHT
MOV AH,9
INT 21h
RET ;Return to DOS
ENTPT ENDP
CSEG ENDS
;****** Stack segment
STACK SEGMENT PARA STACK 'STACK'
DB 512 DUP(?) ;512 Byte Stack
STACK ENDS
;****** Mark the entry point
END ENTPT
ΓòÉΓòÉΓòÉ 19. What If I Still Have Questions? ΓòÉΓòÉΓòÉ
Question:
I've looked through this FAQ, and I can't find the answer to my problem. What
do I do now?
Answer:
Contact VisualAge C++ Service and Support. This section tells you how.
Telephone support in the USA and Canada
VisualAge C++ has a free 60-day Getting Started period (GSP) to help you with
installation, usage, and how-to problems. Call 1-800-237-5511. The 60-day
period starts on the date of your first call, and is offered 9-5 (in your time
zone), Monday through Friday. If you need service outside of these hours during
the GSP, service charges apply. Call 1-800-237-5511 for details.
After your 60-day GSP, we offer a wide menu of service options tailored to a
full spectrum of customers needs. Again, call 1-800-237-5511 for details.
Quite often, you may not need technical support, for example when you have
questions about CSD levels and availability, registration cards, or beta tests.
In recognition of these questions, our automated response system contains a
wealth of useful information. You can also receive much of that information by
fax. The response system is available 24 hours a day, 7 days a week. Call
1-800-668-2853. (Outside of North America, you can access the same system at
416-448-4363.)
Telephone support outside North America
For local country support, please contact your IBM branch for details.
Electronic support - worldwide
You can also contact VisualAge C++ Support electronically. There is no charge
for this service, other than what you normally pay for your electronic access.
Compuserve (OS2DF1)
INTERNET
- va_cpp@vnet.ibm.com
- workframe@vnet.ibm.com for WorkFrame-specific questions
IBMLink/ServiceLink
- VA C++ forum
- ETR (electronic reporting of problems)
TalkLink
- VA C++ forum
- ETR (electronic reporting of problems)
If you frequent the Internet, you can also contact other knowledgeable
VisualAge C++ users on the USENET newsgroups. (VisualAge C++ discussions often
appear in the comp.os.os2.programmer hierarchy.)
Other defect reporting channels in the USA and Canada
You can also report possible VisualAge C++ code-related problems using any of
the following methods:
FAX 1-800-426-8602
MAIL
IBM Corp
Personal Systems Support Family
11400 Burnet Road
Internal Zip 2901
AUSTIN, TX 78758
ELECTRONIC CompuServe - 76711,611
Other defect reporting channels outside the USA and Canada
Other IBM countries offer mail-in and fax support. Please contact your IBM
branch for details.