PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 1/12 TITLE : Borland Language News, Volume 1 Number 16 _Borland Languages Support News_ ---------------------------------------------------------------- volume 1, number 16 September 27, 1993 ---------------------------------------------------------------- USER-DEFINED CLASSES WITH THE OBJECT CONTAINER CLASS LIBRARY: To use user-defined classes as the atomic type of any of the containers offered in the Object class based container class library, the programmer needs to remember one fundamental aspect of inheritance with pure virtual member functions. Anytime a class is derived from an abstract base class, all pure virtual member functions residing in the base class will need to be defined in the derived class if the program- mer intends on making instances of the derived class. Sec- tion 10.3 of the ARM gives the relevant background on this aspect of the C++ language specification. As can be sent in the class definition for class Object (\CLASSLIB\INCLUDE\OBJECT.H), five member functions are de- fined as pure virtual member functions. Their prototypes are given as -- virtual classType isA() const = 0; virtual char _FAR *nameOf() const = 0; virtual hashValueType hashValue() const = 0; virtual int isEqual( const Object _FAR & ) const = 0; virtual void printOn( ostream _FAR & ) const = 0; The purpose of these member functions is as follows: isA() returns the class to which an object belongs. nameOf() returns a character string representa- tion of the class name. hashValue() returns a unique key for each instance of the class. isEqual() Boolean test determining whether one object is equivalent to another. printOn() customized display format for contents of the object. Any class derived from Object must override each of these PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 2/12 TITLE : Borland Language News, Volume 1 Number 16 pure virtual function to avoid the error "cannot create an instance of abstract class...". The following simplistic example demonstrates what is needed using the container class library with user-defined types. #include #include #include class foo : public Object { int v; public: foo(const int i) : v(i) { } virtual classType isA() const { return __firstUserClass; } virtual char _FAR* nameOf() const { return "foo"; } virtual hashValueType hashValue() const { return hashValueType(_rotl(v, 1)); } virtual int isEqual(const Object _FAR &o) const { return v == ((foo&)o).v; } virtual void printOn(ostream _FAR &out) const { out << "foo(" << v << ")"; } }; int main() { Array a(2, 0); foo &r0 = *new foo(0); foo &r1 = *new foo(1); foo &r2 = *new foo(2); a.addAt(r0, 0); a.addAt(r1, 1); a.addAt(r2, 2); cout << a << endl; return 0; } HOT ISSUES When I use setcolor() and setbkcolor() to set the foreground to BLACK and any other color, I never get the foreground PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 3/12 TITLE : Borland Language News, Volume 1 Number 16 color to display correctly. Is this a bug in the BGI li- brary? The BGI library uses the zeroth entry of the palette table for the background color. Calling setbkcolor() causes the reference to BLACK to be lost. The simplest workaround is temporarily assign another palette entry to BLACK before calling the setbkcolor() function. eg. #include #include #include #include int main() { int d = DETECT, m, e; const char path[] = "C:\\BORLANDC\\BGI"; initgraph(&d, &m, path); if ((e = graphresult()) != grOk) { cerr << "ERROR: " << grapherrormsg(e) << endl; cerr << "press any key to continue" << endl; getch(); exit(1); } settextjustify(CENTER_TEXT, CENTER_TEXT); const int tmpcolor = 5; setpalette(tmpcolor, BLACK); setbkcolor(RED); setcolor(tmpcolor); int x = getmaxx() / 2, y = getmaxy() / 2; outtextxy(x, y, "Hello, world!"); getch(); closegraph(); return 0; } DOS How do I write an efficient file copying routine? Typically, programmers think of using the fread()/fwrite() combination of functions to read/write large blocks of data from the source file to the destination file. This is par- PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 4/12 TITLE : Borland Language News, Volume 1 Number 16 tially correct. Both fread() & fwrite() utilize a 512 byte block for reading/writing regardless of the size of the buf- fer specified by the programmer. read(), _read(), write(), & _write(), however, go to DOS directly calling interrupt 0x21 function 0x3F which will use the buffer size specified by the programmer. Several factors temper the following code. The source and destination files are opened via open() since file handles are dealt with as opposed to file structures (look at the FILE structure in STDIO.H). Though the simplest manner of opening files would be to do so strictly in binary mode, _open() requires that the files already exist. This is not necessarily what is desired with respect to the destination file. _read() & _write() are designed with the same philos- ophy as _open() and read/write the file in the same binary fashion. This is important when considering file copying where exact images are required. Functions read() & write() will do carriage return translations which also introduces execution time overhead over _read()/_write(). #include #include #include #include int main(int argc, char *argv[]) { const int n = 3; // #required arguments int in, out; // file handles if (argc != n) { fprintf(stderr, "insufficient arguments\n"); exit(1); } if ((in = open(argv[1], O_RDONLY | O_BINARY)) == -1) { perror("ERROR"); exit(1); } if ((out = open(argv[2], O_CREAT | O_EXCL | O_WRONLY | O_BINARY)) == -1) { perror("ERROR"); exit(1); } int i; PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 5/12 TITLE : Borland Language News, Volume 1 Number 16 do { const int n = 30720; // 30k char buf[n]; // copy buffer if ((i = _read(in, buf, n)) == -1) { perror("ERROR"); close(in); close(out); exit(1); } if (i) { // write only if read int j; if ((j = _write(out, buf, i)) == -1 || i != j) { // check #bytes written perror("ERROR"); close(in); close(out); exit(1); } } } while (i); // read entire file close(in); close(out); return 0; } OS/2 How do I call a 16-bit DLL from within my Borland C++ for OS/2 application? Suppose you have a 16-bit OS/2 DLL (like many database DLL's) and you want to use it from your 32-bit OS/2 appli- cation. Here's what is needed for prototypes of the DLL's functions: a. 16-bit functions taking/returning an int should be prototyped as taking/returning a short, since 16-bit int's are now considered 'short'(USHORT or APIRET16 are the typedefs in OS2DEF.H). b. The function should be declared as APIENTRY16, or, _far16 _pascal. c. Any pointers that the function takes as parameters PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 6/12 TITLE : Borland Language News, Volume 1 Number 16 must be declared as _far16. eg. Former prototype in FOO.H (FOO.DLL's associated header file): int FooData(char *, int); New prototype for linking 32-16 (in your Borland C++ for OS/2 application): short _far16 _pascal FooData(char _far16*, short); (NOTE: Don't use char* _far16! It's easy to make this association/mistake since IBM's pointers are declared with _Seg16 after the '*', eg. char * _Seg16.) If you wanted to use the types declared in OS2DEF.H, it would be: APIRET16 APIENTRY16 FooData(PCHAR16, SHORT); In this case, the compiler will take care of the address conversions for the function and the data being passed. NOTES: a. Most DLL's need the _pascal calling convention. Sybase is an exception. Sybase DLL functions need to be called as _cdecl. b. It's difficult to pass a 32-bit function pointer to be executed from a 16-bit DLL ("callback"). See \BCOS2\EXAMPLES\THUNK for more information. c. Functions in a 16-bit DLL that take variable argument lists (eg. printf()) are unworkable. The compiler can- not know to convert their addresses. An array of pointers cannot be converted, for the same reason. WINDOWS I am using a common dialog from within an ObjectWindows ap- PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 7/12 TITLE : Borland Language News, Volume 1 Number 16 plication. It comes up fine, but when I switch away from it back to the application and bring up another common dialog of the same type, it does not appear to be operating as a modal dialog. What is going on? The hwndOwner data member of the initializing structure of a common dialog identifies the window that owns it. This is the window for which the common dialog is modal. If the common dialog structure is initialized in the construc- tor of a TWindow descendent, the HWindow is not valid, and the dialog will behave as described above. Similarly, if the hwndOwner member is NULL, the dialog has no owner and can be switched away losing focus. The solution is to not initialize the hwndOwner member of the structure until SetupWindow(). TURBO VISION The Borland C++ 3.1 IDE is reporting in my Turbo Vision ap- plication that DEFAULT_ARRAY_SIZE is an undefined symbol in ARRAYS.H. Why? With the command-line compiler, this same problem will be reported as "Undefined symbol 'DEFAULT_ARRAY_SIZE' in function BI_OArrayAsVector::BI_OArrayAsVector()". The reason is most likely because \TVISION\INCLUDE is listed in the "Include Directories" path (for the IDE) before \CLASSLIB\INCLUDE (look for the path ordering behind -I in TURBOC.CFG for the command-line compiler). Both the container class libraries and Turbo Vision have their own ARRAYS.H header files which will conflict in this scenario. To fix this problem, simply move \CLASSLIB\INCLUDE before \TVISION\INCLUDE under Options| Directories for the IDE or within TURBOC.CFG for the command-line compiler. PARADOX ENGINE How do I create a DLL which can be called from an Object PAL script in Paradox for Windows? PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 8/12 TITLE : Borland Language News, Volume 1 Number 16 The following example creates a single function MyFunc() which takes a window handle and a pointer to a character string as function parameters. It will then call the stan- dard Windows API MessageBox() function to encapsulate the displaying of the string. // // PWDLL.CPP // #define STRICT #include // turn off name mangling for the exported functions #ifdef __cplusplus extern "C" { #endif UINT CALLBACK _export MYFUNC( HWND, LPSTR ); #ifdef __cplusplus } #endif int FAR PASCAL LibMain(HINSTANCE, WORD, WORD, LPSTR) { return 1; } UINT CALLBACK _export MyFunc(HWND hWnd, LPSTR msgstring) { MessageBox(hWnd, msgstring, "Info from Paradox for Windows", MB_OK); return 1; } // // PWDLL.DEF // LIBRARY PWDLL DESCRIPTION 'DLL callable from Paradox for Windows' EXETYPE WINDOWS CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE SINGLE PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 9/12 TITLE : Borland Language News, Volume 1 Number 16 HEAPSIZE 8192 To create the DLL, issue the following command at the DOS prompt: BCC -WDE -w PWDLL.CPP Next, create a Paradox for Windows form, and insert a button into it. In the pushbutton method for the button, add the following code: uses pwdll MyFunc(hWnd CWORD, msgstring CPTR) CWORD enduses method pushbutton(var eventInfo event) MyFunc(windowHandle(), "Hello from Paradox for Windows!!") endmethod Now run the form and push the button to add in the function- ality of the DLL to Paradox for Windows. PASCAL How do I determine the kind of machine my application is run- ning on? Program SystemID; Uses Crt; const MachineIDSeg = $F000; MachineIDOfs = $FFFE; var MachineIDByte: byte absolute MachineIDSeg:MachineIDOfs; ch: char; begin ClrScr; PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 10/12 TITLE : Borland Language News, Volume 1 Number 16 write('The system running this program is an: '); case MachineIDByte of $FF: writeln('Standard PC'); $FE: writeln('XT'); $FD: writeln('PCjr'); $FC: writeln('AT, XT286, PS/2-50, PS/2-60'); $FA: writeln('PS/2-30'); $F9: writeln('PC Convertible'); $F8: writeln('PS/2-80'); else writeln('Unkown system ID'); end; ch:= ReadKey; end. QUIZ Last week's quiz asked for a class which would overload bi- nary substraction to turn off bits in a specific class mem- ber. The code below starts with the value 65535 (0xFFFF) and iteratively turns off the most significant set bit. The resulting list of numbers is very close to the powers of two series. #include class foo { unsigned v; public: foo() { } foo(const unsigned u) : v(u) { } unsigned value() { return v; } unsigned value() const { return v; } foo operator-(const int i) { return v ^ 1 << i; } }; inline ostream& operator<<(ostream &out, const foo &f) { return out << "foo::v = " << f.value(); } int main() { foo i, j; i = j = 0xffff; PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 11/12 TITLE : Borland Language News, Volume 1 Number 16 for (int k = 15; k > -1; --k) { cout << j << endl; j = j - k; } return 0; } For this week's quiz/exercise, create a simplistic string class which has the functionality of extracting substrings using the following notation: string s = "Hello, world!"; // ... string t = s(j, k); With this sample code, 'j' is the starting index of the substring to be copied. 'k' is the number of characters in the substring. The effects of "string t = s(j, k);" should be nondestructive to string 's'. NEW TECHNICAL INFORMATION DOCUMENTS AVAILABLE Some of the latest technical information documents available to customers include the following. 719 Getting the size of a file. 726 Explanation of "Null pointer assignment" error message. 813 How to cope with stack overflow mes- sages. 1390 How to access Borland's DLBBS (Download Bulletin Board System) and a partial listing of popular C/C++ files. 1393 Explanation of some known problems en- countered between MS-DOS 6.0 and our products. Workarounds and resolutions are included. 1400 Conversion between Micrsoft's floating point format and the IEEE standard. These documents can be found on either LIB-2 of BCPPDOS or BCPPWIN on CompuServe, Borland's DLBBS at (408)431-5096, PRODUCT : Borland Languages NUMBER : 8515 VERSION : All OS : All DATE : October 25, 1993 PAGE : 12/12 TITLE : Borland Language News, Volume 1 Number 16 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.