ACCU Home page ACCU Conference Page
Search Contact us ACCU at Flickr ACCU at GitHib ACCU at Google+ ACCU at Facebook ACCU at Linked-in ACCU at Twitter Skip Navigation

pinReaders Letters

Overload Journal #3 - Aug 1993 + Letters to the Editor   Author: Mike Toms

Large Projects using Turbo Vision

Whilst using Turbo Vision I have encountered some problems - maybe someone out there knows the answers though the Borland Support Line was unable to offer assistance.

CompuServe offers a number of useful files in the Borland Forum for using far virtual tables (farvt.zip) and overlaying Turbo Vision (Borland Technical Document TI1006.zip). Unfortunately the two are not compatible since overlayed TV functions require a local (near) pointer to virtual tables.

Using the IDE to create an overlayed project, some difficulties were encountered using multiple sub-directories for the project files. With a set-up as follows the compiler had certain problems:-

C:\Project.dir\Sub_dir.1 
\Sub_dir.2
\Sub_dir.3
\etc.

Using the flag option Options/Compiler/Compile via Assembler as given in the tech.doc.(TI1006) the assembler first ran out of memory whilst compiling, which was resolved by replacing the Transfer option TASM to the extended Assembler TASMX. Although this cured the 'out of memory' problems further strange things started happening - namely the linker was unable to find the Object files. A little searching provided the answer, that the assembler was being called not through the transfer mechanism but directly from the IDE compiler although the correct (TASM/TASMX) assembler was being called as set-up in the Transfer list.

This had the result that the transfer option for the OBJ destination directories (Subdir.1 etc.) was being ignored all the OBJ files were being dumped in the top (Project.dir) directory. The linker subsequently looked for the files in their respective sub-directories and not finding them produced an error.

We eventually came up with two solutions to this problem, firstly, placing all the project files in the project directory though since many files had the same name but were in different sub-directories this involved considerable renaming of source files. A possible second solution was proposed in calling a small 'c' routine named TASM that resolved the sub-directory calls (possibly a batch file would be sufficient).

So having renamed the files two further (minor) problems developed. The code size, data size and line count on the project file lines were not available and secondly, when compiling with  debug  information  enabled the  compiler

produced the error message 'Cannot read diskette in drive B(or A)' with the options 'Retry' and 'Cancel'. Selecting 'Retry' the compiler would continue though this error was repeated several times before compilation was finally completed (the computer was only equipped with one floppy).

If you have any solutions to the above problems or similar 'interesting' experiences it would be nice to hear from you.

Finally one tip in using TV, if you are not using stream resource files it certainly pays to extract all the streamable functions from the TV library files (::build, ::write, ::read and overloaded << and >> functions) and re-Making the TV.LIB. The resulting library is about half the size of the original and for overlayed applications allows the use of an overlay buffer of 64K (instead of 128-192K required for the complete library), a definite advantage when memory is tight !

Martin Anderson


Dear Mike,

The first two copies of Overload are very good. As a novice in C++, I really learnt a lot. Well done. I have a few questions, and I wonder if you can find the answers for me.

  1. I noticed a lot of C++ books and some C++ compilers are labelled with different AT&T versions. I heard AT&T version 3 supports templates, but on the other hand some people are saying the template standard is still under development. Hence I am confused. Can you tell me what each AT&T version means.
  2. I know you are going to publish a review on Borland C++ for OS/2, and I am looking forward to reading it. How likely for you to publish reviews on or comparison among other C++ compilers, especially Watcom C/C++32 9.5, Zortech C++ 3.1, High C++ and GNU C++? I happen to have access to Salford C/386 (including C++ extension) on an evaluation license (expiring the end of July). I think I would like to submit a review of this, but I am not sure about the license agreement. If you like the idea, I think it would be better for you to speak to them on the magazines behalf.

  3. I think I read somewhere in the second issue of Overload that a destructor can be called directly. Can you tell me how to do it and under what situation this is needed.

  4. I declared a class in a header file which is included in a few  CPP files. One of the constructors has a constant array as a default argument. It looks like I have to define the constant array before the class definition. Therefore I end up with multiple copies of the same array in the same
    executable file. I think only one copy is enough but do not know how to do it. May I have some advice.

  5. In the book review section in Overload, I think if the publication date is printed next to the ISBN would be very helpful. Can this be done?

  6. As you mentioned you were going to do a review on "World of ObjectWindows C++" video, I think it is the right time to ask this question. In the accompanying workbook, the printed code more or less in the middle of page 39 reads something like:

    class TFrameWin  :  public TWindow
    {
    public:
    virtual void CMFileNew(RTMessage)
    = [CM_FIRST + CM_FILENEW];
    :
    };

    I do not understand the syntax for this virtual function declaration (the use of []). Would you explain what this system is please?

Best regards. Polan Tang.

Any congratulations belong to all the contributors. I will answer your questions as best as I can.

1)    A detailed description of the AT&T standards is of little use to us. The AT&T versions represent steps in the evolution of the C+ + language. The latest AT&T version is 3.0. The evolution and standardisation of the language has now been taken on by the ANSI/ISO committees. I don't think any of the current compilers fully supports the AT&T 3 standard (though I feel I will soon be corrected). To the best of my knowledge none of the current crop of compilers support exceptions (the AT&T way). As to templates, the AT&T 3 templates as defined by Bjarne Stroustrup in the ARM (Annotated Reference Manual) 2nd edition is the latest version. I believe that the ANSI/ISO committee have not yet finalised all the details. .

2) We will be looking at many C+ + compilers in the coming editions and trying to evaluate the strengths and weaknesses of each. In order to fully evaluate a compiler and the components that go into making up the complete environment is a long task and cannot be accomplished in a few weeks.
IDE's can appear glossy on the surface, its only through use that their usefulness as professional tools can be evaluated.

3) You read correctly, a destructor can be called explicitly by means of  -> or . operators. In the ARM, Bjarne Stroustrup says "Explicit calls of destructors are rarely needed. One use of such calls is for objects placed at specific addresses using a  new   operator.   Such   use   of explicit placement and destruction of objects can be necessary to cope with dedicated hardware  resources and for writing  memory management facilities".

4)    If I understand your problem correctly the following method should ensure that there is only one instance of the constant array in your executable, and that all object modules use the same one.

Header file:

#ifndef ThisHeaderFile_H 
#define ThisHeaderFiIe_H
#if defined(ThisIsMain)
const char MyArray[] = {"This is Overloaded"};
#else
extern const char MyArray[];
#endif
#endif

The main program should then contain the statements:

#define ThisIsMain 
#include "header.h"
#undef ThisIsMain

The Other modules including this header file must not define ThisIsMain. The extern keyword indicates to the compiler that the variables concerned belong to another module and the address is then fixed up by the linker.

5) I see no reason not to. I shall try to ensure all book reviewers supply me with the date of publication.

6) Borland have extended the C+ + compiler to handle this syntax. It is not standard C++. It does, in my opinion, one of the main reasons that I prefer using OWL rather than MFC. This extension allows the programmer to trap messages by a very simple process. OWL programs do not suffer from the "switch from hell" statements that C/Windows API programs used to suffer from. Object Windows allows you to associate the response to a message with the window by means of defining a member function of the class to handle that particular message.

These  member functions are called  message response functions and they contain the dispatch index which identifies the member function that will be called. All the message response functions have a similar syntax as follows:

virtual void MemberFunction(RTMessage) =  [dispatchIndex] ; 

This often looks worse than it really is because of the use of the constants and offsets, in your example:

virtual void CMFileNew(RTMessage) =   [CM_FIRST + CM_FILENEW];

The CM_FIRST is the offset. The offsets can take one of the following values depending on the source of the message that you wish to trap (table is on page 99 of my OWL manual):

WM_FIRST Windows Messages
WM_USER  Programmer defined window messages
WM_INTERNAL    Reserved for internal use
ID_FIRST     Programmer defined Child ID messages
ID_INTERNAL    Reserved for  internal use
NF_FIRST Programmer defined notification messages
NF_INTERNAL    Reserved for internal use
CM_FIRST Programmer defined command messages
CM_INTERNAL    Reserved for internal use

The internal ones can be ignored, of the others, any of the standard windows messages (WM_PAINT etc) can be trapped by using [WM_FIRST + WM_PAINT]. If you have defined a radio button on a dialog box and you want to respond to it (to gray items?) everytime it is pressed then you will trap this message by use of the [ID_FIRST + ID_MyRADBUT] dispatch index. The command messages are used primarily to pick up on the messages from the menu system. In the case of your example we will pick up one of the predefined message numbers. If you had allocated an id of 112 to a menu item in the resource editor, you then create a message response function to trap it as follows:

virtual void MenuItem(RTMessage) =  [CM_FIRST + 112];

I hope that has helped to clear up some of your problems. If this is not clear enough, let me know and I'll put an article on OWL Basics in the next edition.

Mike,

Just a quick note to say how good Overload is and keep it up. I find the 'tutorial1 parts are pitched just right for me. I quite liked all the different fonts in issue 1, but then I'm a font junky so the people who complained there where too many where perhaps correct!

If you can't fit everything on the issue disk what about gzip? I would think in the context of overload it would be free and an advert for the FSF. I might not agree with their philosophy, but some of the results are excellent!

Keep up the good work,
Rick Stones


Mike,

"On another topic, there is a matter I should like the group liaising with Borland to raise with the company. There is a systematic error in the version 3.0 ObjectWindows for C++ User's guide, which makes the tutorial section of the guide unnecessarily confusing. In the reference section none of the class private members is documented, except for class TStreamable. As far as I can make out, this error is not corrected either in the documentation files for 3.0 or in the documentation in the 3.1 upgrade."

"As to the matter of the ObjectWindows documentation, on pp. 225, under the section 'Sample Class Header File' it states that:

All functions with protected member access are labelled to the right of the program text (declarations). All functions with public member access are not labelled. Private members are not listed.

I suppose this is done because the private members play no part in the ObjectWindows class hierarchy (i.e. private member functions in a base class cannot be accessed by classes derived from that base class). On the other hand, the private pure virtual member streamableName is mentioned as it must be replaced in all classes derived from TStreamable. This in no way affects the protection scheme as a friend of a base class can have virtual access to the derived class members.

This is the only time that I can see a need for a user of ObjectWindows to know what private members are present. In our case the only place where streamableName is used is in opstream, which is a friend of TStreamable. Opstream uses the unique name returned from calling the derived classes streamableName member function.

Normally, as this is a different chapter, I would not expect the constraint imposed on chapter 16 to apply to chapter 17. However, they have stated that the sample class entry format on p225 applies to this chapter also.

I will also forward your comments to Borland UK if you wish" - Mike

"If you don't pick up the point that private members are not documented in the reference section, you are liable to experience disorientation when you go from the tutorial to the reference section and discover that the child list, a data member referred to throughout the tutorial, is not documented. Doubts may arise whether the tutorial and the documentation fully reflect the current behaviour of the OWL software.

Borland would, I think comment along the following lines. Their policy of not documenting private members is clearly stated on p.225 of the OWUG. Documenting private members would be irrelevant, and indeed counter, to the objective of helping the programmer to use the OWL application framework successfully. Such use involves deriving classes from a set of fundamental classes whose behaviour has been adequately defined by Borland.

With most of this I am in agreement. I believe, however, the manual has the potential to mislead readers who don't read manuals consecutively and completely. To enhance understanding of key concepts such a reader may turn from the tutorial to the reference section. He may find that reading only the first two pages of the introduction to the reference section is needed to use the reference section. The false statement on the first page (p. 223) that all class members are listed and the exposition in the following paragraph could together lead the reader to believe that all class members are documented. As the windows object, introduced early in the tutorial, is a key concept in OWL, it is likely that the TWindowsObject documentation will be one of the first parts of the reference section to be consulted by the tutorial reader. He will quickly discover that the child list data member is frequently referred to in the TWindowsObject documentation and is itself undocumented. This unexpected discovery is liable to leave the reader feeling confused.

The reader described above is not entirely hypothetical; I am one such reader. What changes do I suggest to the OWL manual? First, the false statement on p. 223 should be corrected. Second, the two mentions of the private data member CreateOrder in the documentation of TWindowsObject read and write member functions are inconsistent with the implementation of the Borland policy on private member documentation; they should be removed. Third, there should be a prominent statement of the Borland policy on private members where it will not be missed by the tutorial readers who don't read manuals consecutively and completely - possibly the majority. The paragraph on the OWL Reference in the introduction (p. 2) would be a suitable place."

Okay, well we haven't heard a complaint like this one before, but I've forwarded these comments to the US. My feeling is that private members are, as the word says, private, and not supposed to be used by the developer. I think you've answered entirely reasonably. If he wants to give me a call about it, then give him my number, and get him to give me a call. - Guy Martin - Borland UK Ltd

Dear Mike,

The magazine is excellent. I am glad that it will also include Microsoft C++ (and I hope users of other C++ systems). I like the idea of the EMail interviews. (I.e. the Barnje Stroustrup interview) It is an easy way of contacting the great and the good with out having to send a reporter to the other side of the world. I hope that there will be more interviews with prominent persons, e.g. Messrs King (MS), Martin (Borland), Jenson (JPI) etc possibly even Gates and Khan?

Wonderful idea, would you like to do it? I am currently interviewing Tom Cargill and I have several more lined up, but any assistance would be gratefully received.

Can any one help with a problem I have? I am using radio buttons with Borland's Turbo Vision screen graphics library. I am trying to switch 48 items as one unit. The most sensible layout appears to be 4 columns of 12. As far as I can see I must do this as 4 separate sets of buttons.

Does any one know of a simple way of setting up the 4 columns of 12 buttons as one set of radio buttons? I would ask Borland but they charge for tech support these days.

Turbo Vision is limited to 16 radio buttons in a single block. This is co-incidently the number of bits in an integer, which is used to record the current button pressed by setting the appropriate bit. Borland assure me, that this can be altered by modifying it to a long (I think you may need to check anything using that field and function return types as well). This will extend your button range to 32.

IMHO, I think you have a serious design problem. Anything requiring 48 radio buttons sounds like a Visual Basic programmer struggling to get out somewhere. I suggest that you try using a drop-down combo-list, so that only one of the list can be selected at any one time. This has the advantage of only taking up a small area of screen and the list can be sorted, making the items easy to find.

Something that occurred to me whilst reading Adrian Fagg's item on multiple compiler coding in CVu V5i6. Can we bring pressure to bear on the major C++ compiler manufacturers re standardisation?

I am not asking for much. Just the same functions (using the same names) in the same header files. They should put extensions and differences into one or two separate .h/.hpp files. (There is a starting point, header extensions) The C++ market is still young enough not to be set in it's ways, I hope.

It should not be to difficult to do for future compiler releases but it does depend on co-operation between companies. This will only happen if it is seen as something the market wants. Do we want it?

When C started it was hailed as portable, C++ has inherited the mantle. If we end up with code that is specific to a machine & compiler what happens when "The next PC" arrives? Rewrite all the code? We have the next platforms on the horizon (Alpha, Power PC etc). Now is the time to press for a core standardisation.
Regards - Chris Hills

Overload Journal #3 - Aug 1993 + Letters to the Editor