PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 1/12 TITLE : Borland Language News - Volume 1 Number 15 _Borland Languages Support News_ ---------------------------------------------------------------- volume 1, number 15 September 27, 1993 ---------------------------------------------------------------- CALLING FUNCTIONS IN A PARENT PROCESS: Though the following is not a common question, it sometimes would be useful to have access to the functions within a parent process while execution is occuring within a child process. This may save code space if the desired function is generic enough for use by the child. Calling a parent's function cannot be accomplished if the child process is executed with the exec() family of func- tions given that overlaying occurs with this family. The spawn() function family, however, does not overwrite the parent's code, such that it will remain intact while the child process is executing. The first thought that a pro- grammer may have is that once the address of the parental function is determined by the child process, that particu- lar function can then be called as any other function in the child assuming that the child know what kind of parameters are needed by the function. Simplistically, this is cor- rect, however, given that the parent is running in differ- ent segments as the child, far pointers need to be used for calling the desired function. The next issue needing to be considered is the need of the parent's function for data in its own data segment. If ac- cess is needed, then register restoration will need to be done. The _loadds modifier will provide this switch of the segment registers and usage can be seen in the source code below. // PARENT.CPP #include #include #include #include #if !defined(__LARGE__) #error compile only in large model #endif PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 2/12 TITLE : Borland Language News - Volume 1 Number 15 void _loadds f(const int); int main() { cout << "(PARENT.EXE)\tbegin" << endl; cout << "(PARENT.EXE)\t"; f(0); const int n = 8; char ws[n], wo[n]; unsigned s = FP_SEG(f), o = FP_OFF(f); itoa(s, ws, 10); itoa(o, wo, 10); cout << "(PARENT.EXE)\t"; cout << "segment:offset = " << ws << ":" << wo << endl; spawnl(P_WAIT, "CHILD.EXE", "CHILD.EXE", ws, wo, NULL); return 0; } void _loadds f(const int i) { asm int 0x03 cout << "f(" << i << ")" << endl; } In this example, the function to be called by the child pro- cess has its address converted into strings which are in turn passed to the child. The interrupt 0x03 in function f() is required for debugging purposes. The child process's code will look similarly -- // CHILD.CPP #include #include #include #if !defined(__LARGE__) #error compile only in large model #endif typedef void (*fp)(const int); int main(int, char *argv[]) { unsigned s = atoi(argv[1]); unsigned o = atoi(argv[2]); cout << "(CHILD.EXE)\t"; cout << "segment:offset = " << s << ":" << o << endl; fp *f = (void (*)(const int)) MK_FP(s, o); PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 3/12 TITLE : Borland Language News - Volume 1 Number 15 cout << "(CHILD.EXE)\t"; asm push ds f(1); asm pop ds cout << "(CHILD.EXE)\tdone" << endl; return 0; } In the child's code, the incoming address (segment & offset) is converted back into unsigned integers before creating the address itself via the MK_FP() macro. The call to function f() is bracketed by a push and pop of the data segment to ensure that the value of the child's DS register is not lost in the translation. This example is not definitive in treating all aspects of calling functions (namely, looking at return values), how- ever, it should provide the reader with an idea of what is needed when utilizing code in a different segment. HOT ISSUES The Borland C++ for OS/2 installation program currently in- stalls incorrectly on systems that do not have drive C as the OS/2 root directory. This is usually the case in sys- tems configured for dual boot or boot manager. The dual boot and Boot Manager allow the computer to contain more than one bootable operating system concurrently on the hard drive. On a typical dual boot system, the OS/2 operating system and its associated configuration file (CONFIG.SYS) are located on drive D. This is the typical scenario that could cause an incorrect installation. When the install- ation program starts, all the files are copied and unpacked to the directory specified. The installation program allows the specification of the OS/2 operating system directory. The location of the OS/2 operating system directory should be used by the installation program to find the CONFIG.SYS and make the appropriate modification to allow Borland C++ to run on the system. Regardless of the path that is speci- fied in the installation program for the OS/2 operating system directory the installation program will always mod- ify the CONFIG.SYS in drive C. These are the modification PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 4/12 TITLE : Borland Language News - Volume 1 Number 15 that take place and need to moved the the correct CONFIG.SYS: ADDITIONS TO CONFIG.SYS: REM --BORLAND INSTALL-- SET IPFC=D:\BCOS2\IPFC Cut and paste these two lines from the CONFIG.SYS file on drive C to CONFIG.SYS file that is used by the OS/2 oper- ating system at boot time. Check the path to the IPF file in BCOS2 to verify that it is correct. MODIFICATIONS TO ENVIRONMENT VARIABLES: The installation program will make modifications to the LIBPATH and the PATH environment variables inside the CONFIG.SYS file. The full path to Borland C++ \BIN is ap- pended to the end of both the LIBPATH and the SET PATH statements in the CONFIG.SYS. These changes must be moved to the correct OS/2 CONFIG.SYS file. On a typical system where the Borland C++ for OS/2 compiler is installed on drive D, the LIBPATH and the SET PATH statements should have the path "D:\BCOS2\BIN" as their last item. For Bor- land C++ to function properly, the following lines must be present in the OS/2 CONFIG.SYS (where X represents the root OS/2 drive). a. Add the line -- SET IPFC=X:\BCOS2\IPFC b. Add the statement X:\BCOS2\BIN to the LIBPATH statement in the OS/2 CONFIG.SYS file. c. Add the statement X:\BCOS2\BIN to the SET PATH statement in the OS/2 CONFIG.SYS file. In items b and c above, remember to separate each statement with a semicolon. eg. PATH=d:\;d:\borlandc\bin;e:\mydlls PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 5/12 TITLE : Borland Language News - Volume 1 Number 15 DOS The following is paraphrased from the _Annotated Reference Manual_ section 12.4, but bears repetition. As a defensive programming practice, declaring destructors as virtual should be considered to be common usage. The following ex- ample points out a frequent pathology: class base { public: base(); ~base(); }; class derived : public base { public: derived(); ~derived(); }; void f() { base *p = new derived; delete p; } Because the base class' destructor is not virtual, operator delete will only call base::~base() and not derived::~de- rived() as possibly expected. Redeclaring base::~base() as virtual solves the problem, however, this also requires each derived class from base to also have a destructor defined. The reason that destructors are not virtual by default is due to the overhead that the virtual table necessitates. This overhead may be too costly in small classes both in terms of efficiency and space requirements. However, adding a virtual destructor to a class which already has virtual functions is adding negligible overhead. In this scenario, virtual destructors should be present in all classes which have at least one virtual function defined. OS/2 To run protected-mode (DPMI) applications under OS/2 such as BC or BCC, you will have to change the settings for your DOS PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 6/12 TITLE : Borland Language News - Volume 1 Number 15 box or DOS window: a. Right-click on the DOS-box icon. b. Click on Open. c. Click on Settings. You will get a 'Notebook'. d. Pull 'Session' from the notebook. e. Click on the 'Settings' button. f. Click on DPMI_DOS_API setting, and set it to 'On'. g. Click on 'Save'. WINDOWS When I try to run Turbo Debugger for Windows (TDW) under Windows 3.1, why do I get the error message, "CANNOT FIND WINDEBUG.DLL"? There are two common causes of this problem. The first is that you are attempting to run TDW 3.0 under Windows 3.1. There are three things you can do to fix this: a. Upgrading to TDW 3.1 will provide all the functionality of the debugger under Windows. b. As a temporary solution, however, you might try down- loading the file TDWIN.ZIP from the Borland DLBBS at (408)431-5096, LIB-2 of either CompuServe's BCPPDOS or BCPPWIN, Genie, or BIX. This contains the file TDWIN.DLL which is to be renamed to WINDEBUG.DLL. c. You can use Windows 3.0 instead of Windows 3.1. The other possible cause of this error is if you install TDW 3.1 over TDW 3.0. If this is the case, delete all the Turbo C++/Borland C++ files and reinstall the product. TURBO VISION My program is too large to use Stack Trace or TD386, but I would like to trace back the strack to find out who is call- ing operator delete. If you have a memory allocation like xxxx:0004, that means it came from function malloc() or another C library func- PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 7/12 TITLE : Borland Language News - Volume 1 Number 15 tion, and this is why check() is failing. Under Turbo Vis- ion, ojbects allocated via operator new will be like xxxx:0014. The first thing to do is simple grep the source code for calls to malloc(), calloc() and strdup(); don't forget to also check any library source code that is avail- able. If this does not help, try a stack trace. Yon may not be able to compile the entire library along with the applica- tion with debugging information enabled, but you can compile just the parts involved in that particular stack trace. Just start adding stuff until the stack trace shows the of- fending function call. Try to compile the entire applica- tion with debugging information, and add TView, TGroup, Grp, and in certain cases TDialog. If that doesn't help, make a local copy of NEW.CPP and re- place the assertion with a conditional statement. Put a breakpoint on it and when it hits, continue to step until some of your own code is executed or whatever code is call- ing operator delete. Even without debugging information, every procedure name will be visible, so the current func- tion can be determined. PARADOX ENGINE 1. How much diskspace must be free when adding an index to a Paradox table? I am getting PXERR_OUTOFDISKSPACE. The step of adding a primary index requires a copy of the table to be made on disk. If the table is 3M in size, en- sure that 3M of free diskspace is available to avoid this error. 2. Why does PXTblExist return false even though I can see the .DB file? PBTblExist does not only check for the existence of the .DB file, but it also checks for the validity of the table. This means that it will return false if the table is sorted in a different order than what the Engine is currently using or there are out of date indices present. PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 8/12 TITLE : Borland Language News - Volume 1 Number 15 PASCAL An abbreviated chronology of Turbo Pascal 3.0 to Borland Pascal 7.0 -- Turbo Pascal 3.0 (1985 - 1987): Both compiler and its accompanying editor stuffed into a 40K .COM file. This version was able to compile and run programs in memory or produce .COM files. Turbo Pascal 3.0 had its own particular form of overlays which were implemented by groups of procedures. Features: elementary graphics support toolboxes functioned on CP/M and MS-DOS generic machines 64k code/64k data unlimited dynamic allocation could run on a single floppy system Turbo Pascal for the Macintosh (1987): The initial Macintosh release was designed for Sys- tem 5.2, however, it would function with System 6.x.x as well. Turbo Pascal for the Macintosh is not compatible with System 7 or the latest gener- ation of Mac computers. Features: 1.0 would run from a single floppy system introduced units supported the Mac Toolbox. version 1.1 supported the Macintosh II Turbo Pascal 4.0 (1987 - 1988): This version sported a complete rework of the Turbo Pascal code base. Version 4.0 would only create .EXE files, and was not source compatible with Tur- bo Pascal 3.0. Features: units BGI graphics. PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 9/12 TITLE : Borland Language News - Volume 1 Number 15 IBM-PC based user interface. multiple code segments up to 64K in size. 64K data unlimited dynamic allocation Turbo Pascal 5.0 (1988 - 1989): Integrated debugging was added and support for the new Turbo Debugger was introduced in this version. Overlays were once again allowed similar in the format of a unit. Turbo Pascal 5.5 (1989 - 1990): The version of the compiler extended the language by adding object-oriented extensions. In most other respects, version 5.5 was very much the same as ver- sion 5.0. Features: Documentation for version 5.5 was the same as for version 5.0 except for the addition of an OOP guide. Turbo Pascal 6.0 (1990 - 1992): Features: new multi-file IDE mouse support for editing introduction of Turbo Vision Turbo Pascal Professional included a command- line compiler (TPCX) that was VCPI compliant. Turbo Pascal for Windows 1.0 (1991): The IDE worked with Windows 3.1, but Turbo Debugger for Windows 2.5 did not. Features: Windows 3.0 support allowed for the creation of DLL's supported null terminated strings shipped with Turbo Debugger for Windows 2.5 shipped with WhiteWater Resource Toolkit PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 10/12 TITLE : Borland Language News - Volume 1 Number 15 initial release of ObjectWindows library Turbo Pascal for Windows 1.5 (1992): Update to TPW 1.0 to include support of Windows 3.1. Features: Resource Workshop Borland Pascal 7.0 (1992): This version added a protected-mode IDE, and allowed real-mode/protected-mode and Windows programming. Turbo Pascal 7.0 (1992): This version also featured a protected-mode IDE, but not protected-mode programming is not allowed. QUIZ Last week's quiz/exercise asked for an example of overload- ing operators new and delete to use only statically allocated memory. The following code demonstrates this idea by allo- cating and deallocating a few of the fundamental types. #include #include #include #include #include const int n = 8; // heap size int i; // heap index char a[n]; // heap void* operator new(size_t m) { if (m > n - i && _new_handler != 0) (*_new_handler)(); char *p = a + i; *p = m; i += m; return p + 1; } void operator delete(void *p) { PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 11/12 TITLE : Borland Language News - Volume 1 Number 15 i -= *((char*)p - 1); } void empty() { printf("heapspace exhausted\n"); exit(1); } void view() { printf("i = %d\theap = ", i); for (int i = 0; i < n; ++i) printf("%4d", a[i]); printf("\n"); } int main() { set_new_handler(&empty); char *p = new char; *p = 'a'; delete p; view(); const char *s = "Hello"; char *q = new char[strlen(s) + 1]; strcpy(q, s); delete [] q; view(); int *r = new int; *r = 0xffff; delete r; view(); float *t = new float[n]; return 0; } For this week's quiz, refer to the last two issues of the newsletter where binary addition was overloaded to turn on bits within a class member. Now overload binary subtraction to turn off bits in a similar fashion. NEW TECHNICAL INFORMATION DOCUMENTS AVAILABLE Some of the latest technical information documents available to customers include the following. PRODUCT : Borland Language News NUMBER : 8514 VERSION : All OS : All DATE : October 25, 1993 PAGE : 12/12 TITLE : Borland Language News - Volume 1 Number 15 642 "Duplicate Symbol" error on external variables. 864 How to resolve "Undefined Symbol" messages. This document describes the meaning and possible causes for this error. 1170 Resolving random and strange keyboard behaviours. 1171 Borland Languages Problem Report Form for reporting problems and anomalies with one of the Borland language pro- ducts. 1288 Creating a DLL with Borland C++ which is to be called from Paradox for Win- dows. 1394 Different methods in which an application can load a DLL in OS/2. These documents can be found on either LIB-2 of BCPPDOS or BCPPWIN on CompuServe, Borland's DLBBS at (408)431-5096, TechFAX at (800)822-4269, or OAS at (408)431-5250. DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.