OnLine's Electronic Magazine (EMAG) Issue #5 The fifth issue of OnLine's Electronic Magazine (EMAG) is available for downloading in the Software library. The file is EMAG5.ARC. Microsoft has created this magazine to provide our OnLine customers with information about the OnLine service, including techniques on how to most effectively use the service. We also hope the magazine will encourage you to send us feedback so that we can provide the best possible service to you, our OnLine customers. Table of Contents ----------------- Product Support Services Is Taking Off -- Internationally........................................by Deb Chastain Knowledge Base Search Help: Queries....................by C.J. Pilgrim Microsoft Technical Tips................by MS OnLine Support Personnel (The information in these articles may also be found in the Knowledge Base by searching on the appropriate Q number shown in parentheses.) FAT Versus HPFS File System Information (Q50213) New Method of Starting Programs in OS/2 Version 1.20 (Q50620) Making an Application HPFS Aware for Version 1.20 (Q57842) Installing Version 1.20 DUALBOOT (Q51673) Copying Files from FAT Drive to HPFS Drive in 1.20 (Q51807) Configuring a Secondary HPFS Partition in Version 1.20 (Q51686) .TYPE Extended Attribute Information (Q57542) PM and LAN Manager Printing Information (Q52203) Playing of Metafile Can Result in Out of Memory Error (Q51993) Blanking Out the Password in a Dialog Box (Q52208) Storing a Multipaged Document in a Metafile (Q57424) Disabling Key Combinations Such As CTRL+ALT+DEL (Q57419) Setting Up OS/2 LAN Manager to Use Replicator in 2.00 (Q57836) Avoiding File Access/Locking Problems (Q52205) Load-Time and Run-Time Dynamic Linking Overview (Q59745) Microsoft FORTRAN 5.00..............................by Debbie Watkins (The information in these articles may also be found in the Knowledge Base by searching on the appropriate Q number shown in parentheses). FORPATCH Available in Software Library (Q51298) Reading Environment Variables from FORTRAN 5.00 (Q48957) OS/2 Graphic Routines Available with FORTRAN 5.00 GRTEXTP.LIB (Q50600) Graphics Routines, Unresolved Externals, and FGRAPH.FI & FGRAPH.FD (Q48025) C Compatibility and FORTRAN 5.00 Libraries (Q49446) Opening More Than 20 Files with FORTRAN 5.00 (Q48797) FORTRAN Reserved Filenames (Q50332) VAX Extensions Available with FORTRAN 5.00 (Q50504) Presentation Parameters and Combination Boxes for OS/2 Version 1.20.....................................by Joe Hayes Creating and Using a Dynamically Linked Version of the C Run-Time Library................................by Rick LaPlante C Run-Time Routines Cannot Be Placed in an Overlay..by Renata Bachelor Programming the Mouse for a Hercules Monochrome Graphics Card..........................................by Tony Claflin Answers to Common Questions About Microsoft QuickBASIC Version 4.50.................by Edna Kainz and Steve Elston ====================================================================== Microsoft Product Support Services Is Taking Off -- Internationally! by Deb Chastain There are currently 14 Microsoft subsidiaries in various locations around the globe. They are: England, Sweden, Germany, France, Spain, Holland, Italy, Australia, Canada, Mexico, Brazil, Japan, Korea, and Taiwan. The mission of International Product Support is to "Make sure that Microsoft's services to customers are the best in the software industry in each country." To provide this high quality support, Microsoft has made a large investment in personnel and technology. The support staff in each country is responsible for providing the highest quality support in a timely manner to Microsoft customers via telephone calls, letters, faxes, and electronic Service Requests. International support staff members around the world recently received a new support tool -- PRISM. PRISM provides them with an up-to-date knowledge base of technical information, the ability to receive and respond to customer-generated Service Requests via Microsoft OnLine, and the ability to monitor and track customer activity. PRISM is an internally developed OS/2 application that uses Microsoft LAN Manager and SQL server to full advantage. With the release of PRISM, all of Microsoft's international PSS customers are on equal footing with the U.S. customers because of the 24-hour update capabilities our internal network provides. This is an important step for Microsoft's international support organizations, and one that will greatly benefit Microsoft's international customers. The subsidiaries have set individual service and quality goals for the OnLine product, and several subsidiaries are actively advertising and selling the OnLine product to customers. Currently, the subsidiaries in Europe, Canada, and Australia are selling OnLine and striving toward their projected goals. The subsidiaries in the Far East and in Mexico and South America will develop marketing plans for OnLine and begin selling in July. Below is a list of subsidiary telephone numbers for inquiries about local OnLine availability: Country Telephone Number ------- ---------------- Reading, England (44)(734) 391-123 Stockholm, Sweden (49)(89) 461-070 Munich, Germany (46)(8) 752-5600 Paris, France (33) 69-86-46-46 Madrid, Spain (34)(1) 262-7000 Copenhagen, Holland (31) 25-03-13181 Milan, Italy (39)(2) 210-7201 Sydney, Australia (61)(2) 452-0288 Ontario, Canada (416) 673-9728 Mexico City, Mexico (52)(5) 525-2121 Sao Paulo, Brazil (55)(11) 530-4455 Tokyo, Japan (81)(3) 221-7230 Seoul, Korea (82)(2) 780-0286 Taipei, Taiwan (886)(2) 504-3122 The subsidiaries aren't in this alone! They have various organizations at Microsoft in Redmond, Washington, to help them provide high quality support to their customers. The following three groups provide support to the subsidiaries on various issues: the International Product Support Services Team, the International Sales Support Team, and the International Product Development Group. International PSS works primarily with the support organizations to help deliver tools, technical training, and information, which will in turn help the subsidiary support staff provide support to the customers. The International Sales Support Team provides sales support to the marketing and retail groups in the subsidiaries who are selling Microsoft products, and keeps customers informed of prelate programs. The International Product Development Group works with the subsidiaries to localize products for release into the international marketplace. Customers play an important role in helping us build better localized products by providing feedback directly to our Product Support personnel in the subsidiaries. The subsidiaries, with the assistance of these three organizations, have built a strong worldwide support team for Microsoft customers. We look forward to serving you in the future. ====================================================================== Knowledge Base Search Help: Queries by Charles Pilgrim Before pursuing the closing puzzle of my last article, a short history lesson is in order. It is commonly known in literary circles that Charles Dickens was paid serially. For those who do not understand the jargon of the writing industry, being paid serially means that the author is paid based on the number of words in the article or story. For example, at a base rate of $0.03 per word, a 5000 word article or story would return $150.00. This is hardly enough to pay the groceries for the time it took to write the article. As a consequence of being a serial author, Dickens adjusted his writing style to increase the number of words in his stories, thereby increasing the amount he received. By converting all of the "of the person" to "the person's," "Great Expectations" could have been about half the length. Now, what does this have to do with searching the Knowledge Base and the Software Library? Consider the number of words composing the two queries (shown below, taken from the "no hit" list) that I used in my last article. (Also consider the costs associated with connect time while performing these searches.) prod(mouse) and ibm and word and date(x891011 -to- x999999) prod(mouse) and ibm and prod(word) and 5 In the first query, the phrase "and ibm" and the date function are likely not helping; in the second query, "and ibm" is probably not helping, and having two prod functions in the same query presents a problem. (Remember that each article is keyed to only one product.) Removing these extraneous phrases, and adjusting, yields the following queries: prod(mouse) and word prod(mouse) and word and 5.* At the time I tried these queries, the first returned three articles; the second, two. Begging the pardon of Aesop, the moral of this story is to use as few words and phrases as possible when composing a query. (Why did I add the wildcard on the version number? The complete and totally honest reply is pure, unadulterated laziness. I didn't want to spend the time or try my brain remembering what 5.00 sub-versions of Word, if any, were shipped -- besides, it's fewer keystrokes.) Do these queries return the information that was being sought? Possibly, but I think not. The problem in this case is not returning too many articles, but too few. I suspect the query is seeking information about problems with the mouse while running Word 5.00. As such, the following query might be a more reasonable start in locating the desired information: prod(word) and mouse Of course, the large number of articles returned by this query requires refining the query somewhat, but it provides enough returned articles that the desired information is only a matter of another phrase or two away. Up to now, my articles have centered on querying the Knowledge Base. The Software Library also uses the same query structure as the Knowledge Base, and many of the querying practices described in previous articles work equally well -- especially succinctness. The Knowledge Base and the Software Library are similar in many respects, but differ in others. For example, the prod function that simplifies searching in the Knowledge Base does not exist in the Software Library -- beyond the DATE and TITLE functions, the Software Library does not have additional, customized functions. The Knowledge Base consists of a large number of text articles that are searched according to the phrases in a query. The Software Library consists of a number of uploaded files, each file having a unique S- Number (identical to a unique Q-Number in the Knowledge Base), a title line, and a description (the combination of the file, the title and the description is referred to as a document). When querying the Software Library, the title line and the descriptions are searched based on the phrases of the query. Note that the files themselves are NOT searched. The Knowledge Base and the Software Library are interconnected through the use of keywords, the unique S-Numbers, and the unique Q-Numbers. Also, for each file in the Software Library, at least one article exists in the Knowledge Base that references that Software Library file. Now that most readers are scratching their heads trying to decipher what this all means, let's look at the interconnections a little closer. The primary keyword in the Knowledge Base that connects the Knowledge Base and Software library is "SOFTLIB". SOFTLIB is used in Knowledge Base queries as follows: softlib and prod(word) prod(c) and softlib prod(fortran) and softlib These queries return the articles for the specified products that reference files in the Software Library. When I tested this, the third query, FORTRAN, returned one article. The article title is "Q51298 FORPATCH Available in Software/Data Library." Reading the article, I learn this file is a patch for the first pass of the FORTRAN 5.00 compiler as well as the high-capacity compiler. I also learn that the S-Number for this file is S12450. Armed with this information, the Software Library can now be queried using "S12450". Since S-Numbers are unique, one document is returned for the file described in Knowledge Base article Q51298. (S-Numbers appear in the titles of the Software Library documents, but unlike the Knowledge Base, entering "TITLE(S12450)" is not necessary to return the unique document.) The above discussion shows how to locate and use an S-Number from the Knowledge Base to find a document in the Software Library. Once the Knowledge Base article is found, the Software Library can also be queried using the Q-Number of the article, which returns the same document in the Software Library. Whether the S-Number or the Q-Number is used to query the Software Library is inconsequential UNLESS the Knowledge Base article references more than one Software Library document. If this is the case, using the Q-Number returns all Software Library documents that are referenced by the Knowledge Base article. Let's perform a Dickensian review: Knowledge Base articles that reference Software Library documents contain the keyword "SOFTLIB"; the unique S-Number referenced in a Knowledge Base article is used to locate the document in the Software Library; and the Q-Number of the Knowledge Base article that references a Software Library document can be used to query the Software Library. (No, I don't get paid serially. Repetition is the rote of learning; besides, I'm naturally wordy.) This article has shown how to locate references in the Knowledge Base to Software Library documents, and how to use the information contained in these Knowledge Base articles to query the Software Library and find the document. In closing, I will state that it is possible to go from the Software Library back to the Knowledge Base to locate the Knowledge Base articles that reference a document in the Software Library. Having brought that up, it is now a fine time to present this issue's querying puzzle. Correct the following Software Library queries, then locate the Knowledge Base articles that reference the returned documents. (The corrected queries may return quite a few documents; just locate the matching Knowledge Base articles for a couple or a few.) dde and os2 prod(winsdk) prod(quickc) Since you've suffered through Dickens so patiently, I'll leave you with more than just the above gruel: this article contains all the information you need; and remember the uniqueness of the interconnections. ====================================================================== Microsoft Technical Tips by Microsoft OnLine Support Personnel FAT Versus HPFS File System Information Listed below is information on FAT versus HPFS file systems: FAT = File Allocation Table --------------------------- FAT is the file system used by MS-DOS and OS/2. Filenames can have up to eight characters for the filename and three characters for the filename extension. For example, "88888888.333". Alpha-numeric, underscore, and hyphen characters are allowed in filenames. HPFS = High Performance File System ----------------------------------- HPFS is an optional addition to OS/2 Version 1.20. It allows for longer filenames (up to 255 characters) and case sensitivity. Blanks are also allowed in the middle of a filename (for more information, query in this Knowledge Base on "metacharacter and o_os2sdk and 1.20"). For example: LongCaseSensitive.Names and blanks HPFS is 40 percent faster than a FAT system (with a range of 20-500 percent). The cluster size is 512 bytes (FAT is 4096 bytes); this saves disk space. An HPFS drive cannot be formatted with the MS-DOS FORMAT command. It must be formatted from OS/2 with HPFS arguments. An HPFS drive is NOT recognized by MS-DOS. If you try to access an HPFS drive from MS-DOS, you receive an "invalid drive specification" error. An HPFS drive is recognized by OS/2 Version 1.20, and the OS/2 Version 1.20 DOS compatibility box, although only DOS-legal (8.3) filenames will be displayed. ====================================================================== New Method of Starting Programs in OS/2 Version 1.20 In Version 1.10, OS/2 launches applications using the Start Programs menu. Under OS/2 Version 1.20, there no longer is a Start Programs menu. Instead, there are multiple, user-defined Group menus that are used to launch your applications. Despite this difference, the way in which programs are started is essentially the same as it is under OS/2 Version 1.10. That is, the program group menus are oriented toward applications rather than documents. You use the program menus to indicate what application you want to start, and then you indicate to the application what document (if any) you want the application to process. The File Manager (known as the File System under OS/2 Version 1.10) provides a more object-oriented approach to using your computer. The File Manager displays documents with a corresponding icon (the icon can be a default icon, or a user-associated icon) and allows you to associate a particular document with one or more programs. You then can select and launch a document along with its associated application in a single step using either the mouse or the menus. You also can do this with the File System under OS/2 Version 1.10; however, the OS/2 Version 1.20 File Manager makes more effective use of icons. ====================================================================== Making an Application HPFS Aware for Version 1.20 The following changes are necessary to make an application HPFS aware. There is a new keyword that must be used in your module definition file (.DEF file) to mark your application as HPFS aware. Place the LONGNAMES directive on the same line as the NAME directive in your .DEF file. For example, for a VIO window compatible application called FOO that recognizes long HPFS filenames, you would use the following statement in your .DEF file: NAME FOO WINDOWCOMPAT LONGNAMES The LONGNAMES directive tells LINK to set the NEWFILES bit in the executable file header. It indicates that the module supports non-8.3 filenames. This bit is meaningless in real mode, MS-DOS, and in versions of OS/2 earlier than Version 1.20. You also should make sure that you use the version of LINK.EXE that comes with OS/2 Version 1.20, or the version that comes with IBM's development toolkit for OS/2 Version 1.20. The version of LINK.EXE that comes with the Microsoft C Compiler Version 5.10 does not understand the NEWFILES bit. Another method to set the LONGNAME bit in the EXE header is to use the lfns switch in the resource compiler (RC) from the OS/2 Version 1.20 toolkit. This will set the LONGNAME bit and allow you to still use the linker that came with the Version 1.20 toolkit (or C 5.10), rather than the linker that came with OS/2. It is preferable to use the linker from C 5.10 since the linker that comes with OS/2 Version 1.20 causes problems when you attempt to bind applications to run in real mode. ====================================================================== Installing Version 1.20 DUALBOOT The following are questions about how the Version 1.20 Install Program installs DUALBOOT: 1. The Install program appears to check certain prerequisite conditions for DUALBOOT, copies BOOT.COM, and then performs the necessary actions to install DUALBOOT. What are the prerequisite conditions it checks for? To install DUALBOOT on your hard disk, you must already have either MS-DOS (Version 3.20 or later) or an earlier version of Microsoft OS/2 DUALBOOT installed on your hard disk. The Microsoft OS/2 Install program does not install MS-DOS on your computer. If you have chosen to use HPFS on your start-up drive, you cannot install DUALBOOT. If you have been running only MS-DOS in the past, you must create a C:\DOS subdirectory and copy your MS-DOS files to this new subdirectory before you install Microsoft OS/2 DUALBOOT. You must also specify the location of your MS-DOS files for OS/2 by modifying your AUTOEXEC.BAT and CONFIG.SYS files (make sure that you modify the MS-DOS versions of these files if you already have the Version 1.10 DUALBOOT installed). To specify the location of your MS-DOS files in your CONFIG.SYS file, perform the following modifications: a. Add "SHELL=C:\DOS\COMMAND.COM C:\DOS /P" to your CONFIG.SYS file. b. Edit any DEVICE and COUNTRY configuration statements in your CONFIG.SYS file so that the new C:\DOS subdirectory is specified in these statements. To specify the location of your MS-DOS files in your AUTOEXEC.BAT file, edit the SET PATH command so that it includes the new C:\DOS subdirectory. In addition to the above modifications to AUTOEXEC.BAT and CONFIG.SYS, you should move the MS-DOS COMMAND.COM file to the C:\DOS subdirectory. 2. If the prerequisite conditions are met, what does the Install program do to install DUALBOOT? After you install DUALBOOT on your computer, you will find copies of both the Microsoft OS/2 and MS-DOS configuration files in the C:\OS2\SYSTEM subdirectory of your hard disk. You will also find a file called BOOT.DOS in the C:\OS2\SYSTEM directory. BOOT.DOS is a copy of the MS-DOS boot record that existed on your hard disk prior to installation of Microsoft OS/2. 3. What does BOOT.COM do when it is run? When you execute the command "BOOT /DOS" from Microsoft OS/2, the following occurs: a. The Microsoft OS/2 configuration files are copied from the root directory and placed in C:\OS2\SYSTEM as AUTOEXEC.OS2 and CONFIG.OS2. b. The MS-DOS configuration files (AUTOEXEC.DOS and CONFIG.DOS) are copied from C:\OS2\SYSTEM and placed in the root directory as AUTOEXEC.BAT and CONFIG.SYS. c. A copy of the OS/2 boot record is made and placed in C:\OS2\SYSTEM as BOOT.OS2, and the file BOOT.DOS is copied from C:\OS2\SYSTEM to the boot record of the primary partition. An analogous process occurs when you type "BOOT /OS2" from MS- DOS. ====================================================================== Copying Files from FAT Drive to HPFS Drive in 1.20 It is not necessary to use the File Manager when copying files from a FAT drive to an HPFS drive. You can use the COPY command to copy files back and forth between FAT and HPFS file systems. However, there are a few things to be aware of when copying files with long names. If you use the COPY command to copy a file with a long name from an HPFS partition to a FAT partition, you must specify a short name for the file on the FAT partition. By using the File Manager, you can copy a file or directory between different file systems without losing the long name. The File Manager automatically shortens the name for use in the FAT file system and gives you the option of preserving the long name in an extended attribute on the FAT partition. ====================================================================== Configuring a Secondary HPFS Partition in Version 1.20 During the installation process, you selected the primary partition as a FAT file system. To format the secondary partition as HPFS, you inserted the following line in your CONFIG.SYS file: IFS=C:\OS2\HPFS.IFS /C:64 You also deleted the line "DISKCACHE=64" since Page 49 of the "Microsoft Operating System/2 Command Reference for Version 1.20" recommends not using the DISKCACHE statement if your system has an HPFS partition. You then could format the secondary partition as HPFS. You should use the following statements in your CONFIG.SYS file for HPFS, and caching with HPFS: IFS = C:\OS2\HPFS.IFS /C:64 RUN = C:\OS2\CACHE.EXE /LAZY:ON CACHE.EXE is used with HPFS drives. DISKCACHE is not used with HPFS, although no harm should be done if HPFS, CACHE.EXE, and DISKCACHE are used together. However, DISKCACHE gives optimum results with a FAT file system. ====================================================================== .TYPE Extended Attribute Information Question: The documentation describes the .TYPE EA (Extended Attribute) as "similar to the earlier use of filename extensions" on Page 25 of the "Microsoft Operating System/2 Programmer's Reference Volume 4" for Version 1.20. Does this literally mean that OS/2 will be moving away from using file extensions of .EXE, .CMD, etc., for recognizing executable files? Also, we didn't find any .EXE files with a .TYPE EA in the files included with Version 1.20. Is there a reason for this? Response: Microsoft is moving toward using the .TYPE fields rather than file extensions. This transition will take quite a while since most or all current applications aren't yet aware of the .TYPE field or EAs in general. As you noticed, the .EXE files shipped with Version 1.20 don't contain .TYPE EAs. This is an example of the fact that it will take a while for more applications to become EA aware. In the case of our .EXE files, the linker must be EA aware to write the .TYPE field of the .EXE file when it created the file. Since the linker isn't aware of EAs yet, it didn't add those EAs. ====================================================================== PM and LAN Manager Printing Information The following are questions regarding the interaction of the GPI calls, the printer driver, the OS/2 spooler, and the LAN Manager spooler and redirector: 1. What is transferred over the network, given a series of GPI calls destined for the printed page? The only information that is transferred over the network is the escape codes that are appropriate for the printer in question. By the time a job actually gets sent over the network, whether or not the spooler has intervened in the process, the job has been entirely translated to escape codes/PostScript, etc. 2. We assume that the device driver "intercepts" the GPI calls at some location and translates this information into a bitmap representation, given the size of the file that the LAN Manager spooler deals with. Where does this occur? Given the redirection, does the device driver even need to be installed on the netstation? Yes, the device driver does interpret the GPI calls. It does so as the GPI calls are made (locally). A printer driver's internal entry point for various low-level primitives can be entered whenever those primitives are called by the graphics engine. The Epson driver has the graphics engine primitives actually executed. Other drivers might go ahead and implement some of the primitives themselves, which saves the engine simulations for more difficult tasks. At any rate, at this point from the first time the printer driver was called, the printer driver has created something in a format only it knows about: either printer escape codes for a direct job, or possibly translated into a "metafile" language format for stored spooled jobs. All of this occurs on the private workstation. Because it is necessary to have the device driver present [by use of DosLoadModule()] locally to open a DC (device context), not to mention that the device driver must be around to be called by the engine, a device driver for the printer in question must exist on the workstation. 3. Ignoring the current OS/2 Version 1.10 problem with the OS/2 spooler, what would the spooler do on the netstation and the server? The flow of events is diagrammed below: Spooling Data Flow PM application Non-PM application | | | DevOpenDC(OD_QUEUED..) | V | PM device driver (Part I) | | | | SplQmOpen | V V Spooler puts data (metafile or raw data) into remote file | | V Spooler chooses job | | SplQpOpen V Print processor | | DevOpenDC(OD_DIRECT..) V PM device driver (part II) | | PrtOpen V Spooler | | DosOpen (or DosMonWrite) V port Please note that this diagram is for the "local" chain of events. Again, on the server side, it is queuing up files with escape codes only. That is, by the time the file gets to the network server to which the printer is attached, no translation of the print job data will take place. 4. Is the action of the OS/2 spooler discussed in Question 3 different in Version 1.20? The diagram above also describes how the Version 1.20 spooler works. 5. If we define, via the Control Panel, an entry for a printer on a redirected port (for example, LPT7), using the same device driver, where is the translation from GPI to printer control characters/bitmap made? How do driver settings (for example, low/medium/high resolution settings) interact between the client and the server? Again, since all print job creation takes place locally, there is no effect on client/server communication, regardless of the settings. The final translation to escape codes takes place at the last step in the above diagram for some printer drivers, and at the first step for other printer drivers. 6. What is the preferred method of performing printing in a situation like this? It makes no difference how you print. There is no reason to alter your printing strategy based on whether or not the spooler is involved because you are not altering the eventual chain of events. In fact, whether or not the spooler is attached should be entirely transparent to the application. ====================================================================== Playing of Metafile Can Result in Out of Memory Error GpiPlayMetaFile() allocates DCs (device contexts) and bitmaps that are not released until the process is terminated. Because there is an approximate limit of 100 on the number of DCs, PMGRE soon runs out of heap space and an out of memory error occurs. The problem with a PS (presentation space) not releasing the DCs and bitmaps created during the playing of a metafile can be alleviated via the use of GpiReset(hps, GRES_ALL). It is by design that the resources are not automatically freed after a GpiPlayMetaFile() call is issued. If you call the GpiReset() function, you should not run out of heap space. Interestingly, this implies a limit on the number of bitmaps in a metafile. That limit is approximately 100, the limit of the number of DCs that can be created at any one time. This is a limit because you cannot "reset" the PS containing the bitmaps before the metafile finishes playing. Thus, during the course of the playing of the metafile, PMGRE will run out of heap space. ====================================================================== Blanking Out Password in a Dialog Box Question: When obtaining a password on a login procedure for a PM program, using a dialog box to get the name and a second dialog box to obtain the password, the password characters are visible. Is it possible to blank out the characters going to the screen while getting them for password verification? Response: In Version 1.10, you can accomplish this by subclassing the entry field in question and handling the WM_CHAR message. When a character is entered in the entry field, if it is alphanumeric (in the set of characters you allow in passwords), you must "replace" the character with some other character, for example a blank or an asterisk (*) character. There are a couple of ways to keep track of the characters that were entered in the control. You can track them yourself, or send a duplicate of the WM_CHAR messages to an invisible entry field that will track them for you. In Version 1.20 of the system, you can set the color of the text in the entry fields using Presentation Parameters. Thus, you can specify white on white, and there will be no problem with password entry fields because the text won't be visible. ====================================================================== Storing a Multipaged Document in a Metafile If you are using a metafile to store some sort of a generic multipage document, you may find that metafiles are less than optimal for this purpose. The following is a discussion of the drawbacks and possible workarounds that you should consider before using this approach. A metafile is a tape recorder of GPI functions. When played, it does nothing more than execute the graphics orders it contains on the PS (presentation space), creating an image but no underlying data structures. This will make it difficult for you to "read in" a document stored as a metafile. You can store GPI segments in metafiles, which is one way to impose some sort of structure on the saved image. When played into a PS in Retain mode, the segments will be re-created. This method could be used to store a multipage document: one parent segment per page, with the numbering of the segments predetermined. However, you are again limited as to what you can "store" in a metafile. It would be difficult to transparently store formatting information, or any other object not expressly provided for by the GPI functionality. Another alternative is to store information in some sort of rich text format, by using the metafile as an intermediary between your application and the "real" output/data structures that drive it. For example, you could store a document in rich text format via multiple GpiCharString() calls, and query out the metafile bits when you load the metafile. You would never actually be playing the metafile. However, this is again a nontrivial operation as you will have to parse the metafile to retrieve your information. One last limitation you should be aware of is that metafiles, like GPI, have a 16-bit limit on coordinates. This implies a -32K/+32K limit on the coordinate space used to store any image or document. This may or may not be a consideration for you if you need to represent highly dense coordinate spaces. Metafile orders are stored in a graphics language called GOCA, which is a language that closely mirrors GPI. GOCA and the format of metafiles is documented by IBM in its "IBM Operating System/2 Version 1.1 Technical Reference" manuals. This information is not included in Microsoft's OS/2 Version 1.10 Programmer's Toolkit; however, it will be included in a future release of QuickHelp. You may be interested in examining this language/format to see if it would fit your needs as a storage medium, and to get a better idea of what you would be working with if you decided to parse, modify, or write code dependent on the metafile structure. ====================================================================== Disabling Key Combinations Such As CTRL+ALT+DEL It is not possible to disable CTRL+ALT+DEL, CTRL+ESC, or ALT+ESC. This is with regard to writing software for process monitoring and control, while at the same time preventing accidental (or deliberate) disruption of programs, These hotkeys never enter the monitor chain (the normal way to stop or alter keystrokes is with a keyboard monitor), and thus, no application ever gets a chance to see or change them. They are translated into keyboard events, which are handled by the kernel. With respect to CTRL+C and CTRL+BREAK in a VIO application, an application can prevent these from stopping or breaking the application by setting a signal handler for the application. In this manner, the signals generated by the CTRL+C and CTRL+BREAK keystrokes can be intercepted. See the documentation for DosSetSigHandler() for more information. In a PM application, these keystrokes have no special effect, so you do not need to be concerned with these keystrokes. You might be able to partially generate the behavior you require by writing your entire application as a VioPopup() application. VioPopup() windows cannot be exited by pressing CTRL+ESC or ALT+ESC. You can still reboot the machine with CTRL+ALT+DEL; however, you cannot switch screen groups. Generally speaking, the inability to prevent the behaviors associated with these "system" keystrokes is a design limitation of the system. The system simply lacks the facilities to implement a truly "secure" application, one that is safe from all user interaction. ====================================================================== Setting Up OS/2 LAN Manager to Use Replicator in 2.00 The replication service is a new feature included in OS/2 LAN Manager Version 2.00. The documentation for the replication service is fairly complete, and documents the two points discussed below; however, these two points can be somewhat confusing. In the example listed below, assume the export server is named EXPORT1, and the import server is named IMPORT1. When starting the replicator, you should do the following: 1. Make sure the IMPORT1 account on EXPORT1 (the export server) has "RA" authority on the entire C:\LANMAN\REPL\EXPORT tree. The easiest way to do this is with the NET ADMIN command. First, authorize IMPORT1 (the import server) to solely C:\LANMAN\REPL\EXPORT, then immediately after clicking on you will be returned to a menu where you can click on . 2. On IMPORT1, the import server, do the following md c:\lanman\repl\import\subdir1 md c:\lanman\repl\import\subdir2 so that the subdirectories that IMPORT1 is supposed to import (in this example, subdir1 and subdir2) will already exist. The replicator will not create these subdirectories for you; you must do this yourself. The replicator does not create these subdirectories for you because this is one way to control which subdirectories, of the potentially many subdirectories an export server might export, are actually imported to by a given import server. ====================================================================== Avoiding File Access/Locking Problems Question: A workstation and a server are on a local area network (LAN). The server shares one of its drives with the workstation. When an application running on the workstation locks a record (10 bytes) in a file on the shared drive, the server does not see the lock because the same application running on the server is able to lock the same record in the file. Using the NET ADMIN utility, you can see the file being opened by the workstation; however, the record lock does not show on the status screen. If a second copy of the application is run on the workstation, the application receives a lock error. The NET ADMIN utility sees the file open for the second time and finally "sees" the lock from the first application. Is there a workaround for this problem? Response: When you lock a portion of a file from a remote workstation, the file locking mechanism of the server records this fact, such that if you try to lock the same portion of the file from a second workstation (or run the same program from a different screen group of OS/2), you get a locking violation error. However, if you run a file locking program on a workstation and you run the same program on the server, then try to lock the file, the server does not know about this lock, and thus will not return an error message. The server keeps all over-the-network locks to itself and does not pass them down to OS/2. That's why the second workstation (or a second screen group) will get a locking violation if it tries locking over the network. If you are accessing files on the server from the server itself, you may experience a number of access violation problems. Please see Chapter 14 of the "Microsoft Operating System/2 LAN Manager Administrator's Guide" ("Monitoring and Trouble-shooting Server Operations") for more information on how to avoid these problems. Listed below are some helpful hints on how to avoid these access violation problems. From the server, use the shared drive/directory as a remote drive. For example, use the following commands on the server: net share share=d:\ net use s: \\server\share When accessing the files locally on this share point, do not use the direct paths (for example D:\FILES). Instead use redirected paths (for example S:\FILES). This way, you will eliminate any possible access/locking violations. ====================================================================== Load-Time and Run-Time Dynamic Linking Overview Listed below is information about the two types of dynamic linking: load-time dynamic linking and run-time dynamic linking. Load-Time Dynamic Linking ------------------------- When you build an .EXE file that explicitly calls functions contained in a .DLL (dynamic linked library), these external references are recorded in the .EXE file; however, they remain unresolved until the .EXE file is actually loaded. When you launch a program that contains such unresolved .DLL calls, the following occurs: 1. The OS/2 loader checks to see if the .DLL has already been loaded and brings it into memory, if necessary. 2. Any global or instance initialization of the .DLL is performed. 3. The loader examines the segment tables for the .DLL and allocates a selector from the launching program's LDT (local descriptor table) for each segment in the .DLL. One step still remains. Each segment in a .DLL is marked as either PRELOAD (load the segment at run time) or LOADONCALL (don't load the segment until it is called during execution of the program). All segments marked as PRELOAD are brought into memory by the loader and any unresolved external references to those segments are fixed up. Segments marked as LOADONCALL are not brought into memory until they are called, and any unresolved external references to those segments remain unresolved until that segment is explicitly accessed. Run-Time Dynamic Linking ------------------------ When you use run-time dynamic linking, your application explicitly directs the kernel to load a .DLL [using DosLoadModule()] and obtain the address of the desired function in that .DLL [using DosGetProcAddr()]. If the .DLL is not already in memory, or if referenced LOADONCALL segments of the .DLL are not yet in memory, the kernel must load the necessary items from disk. Any per instance initialization of the .DLL also occurs at this point, and this may incur other disk performance hits. While run-time dynamic linking is a bit more complex, it does have the following advantages: memory is conserved, load time is decreased, and you have more flexibility in how and when you load functions. This is a quick overview of dynamic linking under OS/2. For more detailed information on dynamic linking, please see the books in the following bibliography: 1. "Design Concepts and Considerations in Building an OS/2 Dynamic- Link Library," by Ross M. Greenberg. "Microsoft Systems Journal," Volume 3 Number 3, May 1988. 2. "Strategies for Building and Using OS/2 Run-Time Libraries," by Ross M. Greenberg. "Microsoft Systems Journal," Volume 4 Number 3, May 1989. 3. Chapter 19, "Dynamic Link Libraries," "Advanced OS/2 Programming," by Ray Duncan. Microsoft Press, 1989. 4. Chapter 3, "How Dynamic Link Libraries Work," "Software Tools for OS/2: Creating Dynamic Link Libraries," by Michael J. Young. Addison-Wesley, 1989. 5. "Inside OS/2," by Gordon Letwin. Microsoft Press, 1988. 6. Chapter 45, "Dynamic Linking," "Microsoft Operating System/2 Programmer's Reference Volume 1" for Version 1.10. 7. Chapter 2, "Segmented-Executable Linker," "Microsoft Operating System/2 Presentation Manager Programming Tools" for Version 1.10. 8. Chapter 6, "IBM Operating System/2 Version 1.1 Technical Reference Programming Reference: Volume 1." ====================================================================== Microsoft FORTRAN 5.00 by Debbie Watkins FORPATCH Available in Software Library There is a file in the Software Library called FORPATCH that consists of a README file, a patched version of the first pass of the FORTRAN Version 5.00 compiler (F1.EXE), and a patched, high-capacity compiler (F1L.EXE). This update corrects the following problems: 1. The I/O of a STRUCTURE element generates an F1001 Internal Compiler Error in omf_ms.c:1.118, line 1093, or a protection violation. 2. NAMELIST statements in multiple subprograms in one file cause the machine to hang. 3. SAVEing a common block in multiple subprograms causes a compiler error F2348: already declared SAVE. 4. Using /4Yi, /4Ys, or /4Yv, and an asterisk in column one to indicate a comment generates a compiler error F2037: illegal label field. This file can be found in the Software Library by searching on the keyword FORPATCH, Q51298, or S12450. FORPATCH was archived using the PKware file-compression utility. ====================================================================== Reading Environment Variables from FORTRAN 5.00 The program below demonstrates how to obtain environment variables from the MS-DOS environment. The program calls the C getenv() function, which is a built-in part of the FORTRAN Version 5.00 library. The interface statement and the character function GETENV are the required portions, while the main program is for demonstration purposes. The problem occurs because the C function is designed to return a pointer to the contents of the variable. The function does not find the variable; it returns a NULL, which causes a problem under FORTRAN because there is no way to check for a NULL. To correct this problem, you need to look for a variable that does not exist. Use the following procedure: 1. Call getenv() a on nonexistent variable. 2. Call getenv(VAR) where VAR is what you want to find. 3. If the results match, VAR does not exist. 4. If the results do not match, you have a return value. Sample Program -------------- program environment character name*20, string*128, fgetenv*128 write (*,*) ' Enter name of environment variable' read (*,'(A)') name string = fgetenv(name) write (*,*) 'Value is: ',string stop end interface to character*128 function getenv [c] (var) character*21 var [reference] end character*128 function fgetenv(var) character getenv*128, dummy*128, var*20, cvar*21 integer n n = len_trim(var) cvar = var(1:n)//char(0) fgetenv = char(0) dummy = getenv(fgetenv) fgetenv = getenv(cvar) if (fgetenv.eq.dummy) then fgetenv = ' ' end if fgetenv = fgetenv(1:index(fgetenv,char(0))) return end ====================================================================== OS/2 Graphic Routines Available with FORTRAN 5.00 GRTEXTP.LIB The OS/2 graphics library GRTEXTP.LIB supports the following routines (which are also listed in the "Microsoft FORTRAN Advanced Topics" manual, on Page 148): clearscreen getvisualpage settextwindow displaycursor outtext setvideomode getactivepage setactivepage setvideomoderows getbkcolor setbkcolor setvisualpage gettextcolor settextcolor wrapon gettextcursor settextcursor gettextposition settextposition getvideoconfig settextrows This library must be linked instead of GRAPHICS.LIB to use these routines under OS/2. Routines not included in the above list are not available under OS/2. The OS/2 Presentation Manager can be programmed to use additional graphics routines under OS/2. ====================================================================== Graphics Routines, Unresolved Externals, and FGRAPH.FI & FGRAPH.FD Page 138 of the "Microsoft FORTRAN Advanced Topics" manual for Version 5.00 states that for every file that makes a graphics call, you must have the INTERFACE statements at the beginning of that file (INCLUDE 'FGRAPH.FI'). You then must include FGRAPH.FD (variable declarations) in every subroutine that calls a graphics routine. Note: The INTERFACE statements (or the line INCLUDE 'FGRAPH.FI) need to be in EACH FILE in which a graphics routine is called. If these include files are not in the proper location within the program, the link error, L2029, unresolved external may be generated. ====================================================================== C Compatibility and FORTRAN 5.00 Libraries In the second paragraph under "Specifying Libraries" on Page 79 of the "Microsoft FORTRAN Advanced Topics" manual for Version 5.00, the following statement is made: If your program uses both FORTRAN and C, then specify the library for the most recent of the two language products first. The above information is correct; however, the following later sentence is incorrect: If you use C 5.1 or later, specify the C library first. The FORTRAN 5.00 library should come before the C 5.10 library because the FORTRAN 5.00 library contains newer start-up code. The next line states that you should "make sure you choose a C-compatible library when you install FORTRAN." If the version of FORTRAN is newer than the version of C (for example, FORTRAN 5.00 is newer than C 5.10), FORTRAN should NOT be installed with C compatibility, and the LINK options /NOD and /NOE should be used to avoid errors about multiply defined symbols. ====================================================================== Opening More Than 20 Files with FORTRAN 5.00 Under FORTRAN Version 5.00, you are limited to opening 20 files. This limit can be changed by following the instructions on Pages 405-407 of the "Microsoft FORTRAN Reference" manual for Version 5.00 This modification requires Microsoft Macro Assembler Version 5.10. ====================================================================== FORTRAN Reserved Filenames The following is a list of reserved filenames in Microsoft FORTRAN. This information is from the FORTRAN 5.00 README.DOC. Reserved Word Description ------------- ----------- CON Keyboard and screen USER Keyboard and screen PRN Printer (LPT1) COM1 Communications port 1 LPT1 Printer NUL Null device AUX Communications port (COM1) ERR Standard error output (screen) LINE Communications port (COM1) You can use READ, WRITE, and OPEN statements (as appropriate) to access these devices, and you can use CLOSE statements to disconnect them, just as you would with other files. FORTRAN carriage-control characters are recognized for these devices. Problems can occur if you use these reserved words incorrectly (for example, if you try to use one as a regular disk filename). For instance, if you open a file called LINE.DOC, reading from that file can cause your computer to lock unless there is an active data transmitting device connected to COM1. ====================================================================== VAX Extensions Available with FORTRAN 5.00 Microsoft FORTRAN includes many, but not all, VAX extensions. Most of these extensions are found on Pages 331-332 of the "Microsoft FORTRAN Reference" manual for Version 5.00. Appendix B of the same manual lists additional features that are new in FORTRAN 5.00. Query on Q50504 for a complete list of the available VAX extensions. ====================================================================== Presentation Parameters and Combination Boxes for OS/2 Version 1.20 by Joe Hayes Introduction ------------ On January 8, 1990, Microsoft announced and shipped the OS/2 Presentation Manager Toolkit Version 1.20. This development environment, specifically designed for OS/2 and Presentation Manager applications, incorporates the new additions introduced in OS/2 Version 1.20. Two of these new features, presentation parameters (presparams) and combination boxes (combo boxes) are discussed here and are demonstrated in the sample application PRESPARM.EXE contained within PRESPARM.ARC. The file PRESPARM.ARC can be found in the Software/Data Library by searching on the filename PRESPARM, the Q number xxxxx, or S12520. PRESPARM was archived using the PKware file-conversion utility. Further information can be obtained from the "Microsoft Operating System/2 Programmer's Reference Volume 4," the "Microsoft Operating System/2 Presentation Manager Softset: Software Tools for Developing OS/2 Presentation Manager Programs," and the QuickHelp included with the OS/2 Programmer's Toolkit Version 1.20. Presentation Parameters ----------------------- Presparams are a feature of OS/2 Version 1.20 that control the appearance of a custom dialog box, window, or control when it is first created. Presparams can also be used to change the appearance of the dialog box, window, or control dynamically during program execution. This is a new feature, as by changing the presparam, a paint message is not sent to the dialog box, window, or control. This is handled internally by OS/2 as a final step in output pipeline. Two examples of the presentation parameters demonstrated in the sample program are color and fonts. These parameters of the dialog box, window, or control can be set in the resource file through the use of the PRESPARAMS, CONTROL, or WINDOW statement. They can also be changed on the fly using the WinSetPresParam() function. Combination Boxes ----------------- Combo boxes are a new feature of OS/2 Version 1.20. They can be thought of as a concatenation of two existing control types: a single line entry field and a list box. A combo box gives the user the flexibility of entering data in the entry field, as in previous OS/2 applications. EM_ messages can also be sent to the combo box entry field to provide a similar interface to the standard entry field. The list box portion of the combo box gives the user a standard array of choices that can be selected into the entry field. This gives both you and the user some predefined choices that can be selected and optionally edited in the entry field before use in the application. LM_ messages can be sent to the list box portion of the combo box, again to add the standard interface now used for existing list boxes. Other new CBM_ and CBN_ messages have been added to the Toolkit to give the application developer the ability to manipulate and be notified by the combo box. For example, an application using combo boxes that have drop-down lists can display the list of a combo box by sending it a CBM_SHOWLIST message. The user would display the list by clicking the drop-down icon just to the right of the entry field. There are three types of combo boxes: simple combo boxes, drop-down combo boxes, and drop-down-list combo boxes. Simple combo boxes are a combination of an entry field and a list box that is always displayed. The user can choose list box selections and/or edit selections from the entry field. Drop-down combo boxes are identical to simple combo boxes, except the list box is not always displayed. The user accesses the list box portion by clicking the drop-down icon. Drop-down-list combo boxes are identical to drop-down combo boxes except that the user cannot edit the list box selections. Drop-down-list boxes are excellent for finite numbers of fixed choices where the selection itself needs to be displayed after the selection is made. Sample Program -- PRESPARM.ARC ----------------------------- The sample program PRESPARM.EXE is a simple Presentation Manager window with a Demomenu presenting a Dialogmenu item. By selecting the Dialog item, a dialog is displayed demonstrating presentation parameters and combo boxes. The dialog box contains two combo boxes, a list box, three entry fields, three push buttons, and several descriptive text fields. The combo box toward the upper left of the dialog box is a drop-down combo box. It is used to control the editing of the text field immediately below it. The text field is intended to be the title of the list box. Thus, the user can select one of the predefined text items contained in the drop-down combo box list portion and can then edit and/or select that item as the title of the list box below. The list box title can be changed by pressing the Update Display push button. Some code for this combo box can be found in the WM_INITDLG: portion of the GetPresParamsDlgProc() function. For example: /* Initialize drop down combo box */ WinSetDlgItemText (hwnd, DID_EDITLIST, szTitle) ; WinSendDlgItemMsg (hwnd, DID_EDITLIST, LM_INSERTITEM, MPFROMSHORT ((SHORT) LIT_END), MPFROMP ((PSZ) "Demo Strings:")) ; WinSendDlgItemMsg (hwnd, DID_EDITLIST, LM_INSERTITEM, MPFROMSHORT ((SHORT) LIT_END), MPFROMP ((PSZ) "Test Strings:")) ; WinSendDlgItemMsg (hwnd, DID_EDITLIST, LM_INSERTITEM, MPFROMSHORT ((SHORT) LIT_END), MPFROMP ((PSZ) "List Strings:")) ; The three entry fields toward the upper right of the dialog box are the RGB values that correspond to three presentation parameters of the list box toward the lower left of the dialog box. By entering different RGB values and selecting "Update Display," the user can then change the color of the presentation parameters. The presparam can be selected using the drop-down-list combo box immediately under the RGB entry fields. A drop-down-list combo box was selected because the choices for the presparams are finite and cannot be edited by the user. Code for the presentation parameters can be found in the WM_COMMAND: portion of the same function. For example: /* Get new color value */ WinQueryDlgItemShort (hwnd, DID_RED, &usTempRed, FALSE) ; WinQueryDlgItemShort (hwnd, DID_GREEN, &usTempGreen, FALSE) ; WinQueryDlgItemShort (hwnd, DID_BLUE, &usTempBlue, FALSE) ; clr = RGB (usTempRed, usTempGreen, usTempBlue) ; /* Query type of PresParam to change */ usTempListIndex = (USHORT) WinSendDlgItemMsg ( hwnd, DID_LISTCOMBO, LM_QUERYSELECTION, MPFROMSHORT ((SHORT) LIT_FIRST), 0L) ; /* Update PresParams */ WinSetPresParam (hwndListBox, idPresParam[usTempListIndex], (LONG) sizeof (LONG), (PVOID) &clr ) ; To close the dialog box, select the Save Changes or Cancel push button. The Save Changes button saves the presparams for the duration of the application's execution. The PRESPARAMS statement is demonstrated in the resource file PRESPARM.RC to set the font used by the About dialog box. To view this dialog box, select the About option under the Demo menu selection. ====================================================================== Creating and Using a Dynamically Linked Version of the C Run-Time Library by Rick LaPlante With programming for the OS/2 operating system becoming more significant, it is clear that some important features of programming for OS/2 are in need of further documentation. One such feature is the ability to use Microsoft C Version 5.10 to create a dynamically linked version of the C run-time library. This article will discuss two issues regarding creating a dynamically linked version of the C run time (CRT): how to create the dynamic- linked libraries (DLL) version, and program design considerations when using the DLL version of the CRT. How to Create a DLL Version of the CRT --------------------------------------- The following information is taken from Section 5, "Creating Dynamic- Link Libraries," of the Microsoft C Version 5.10 MTDYNA.DOC file. The process of creating a multiple-thread dynamic-link library version of the C run time is outlined below. This process is also contained in the file CDLLOBJS.CMD: 1. Create a definition file that specifies the exports from the C run- time library for the dynamic-link library. The file CDLLOBJS.DEF, which is included with Microsoft C Version 5.10, is a sample definition file that includes all of the C run-time functions currently supported. Any routines listed in the EXPORTS section of the definition file will be included in the DLL. 2. Link the special start-up file CRTLIB.OBJ with CDLLOBJS.LIB, DOSCALLS.LIB, and the definition file (CDLLOBJS.DEF) from Step 1. This creates a customized C run-time dynamic-link library file (named CRTLIB.DLL). The following files are linked together: link crtlib.obj,crtlib.dll/noi,,cdllobjs.lib doscalls.lib /NOD /NOE, cdllobjs.def where: crtlib.obj Start-up code for CRT library files cdllobjs.lib C run-time library object modules doscalls.lib OS/2 support library (may use OS2.LIB cdllobjs.def Definition module from Step 1 crtlib.dll Output from LINK 3. Run IMPLIB on the definition file from Step 1 to create a customized library file (CRTLIB.LIB) containing the exported functions. The command is shown below: implib crtlib.lib cdllobjs.def The only similarity between libraries created by IMPLIB and libraries created by LIB is the filename extension ".LIB". Libraries created by IMPLIB contain the names of functions and modules only to satisfy the linker. The actual code is brought in later by loading dynamic-link libraries. 4. Use the Microsoft Library Manager (LIB) to append CDLLSUPP.LIB to the customized library created in Step 3. The file CDLLSUP.LIB contains a few small routines that cannot be dynamically linked due to design constraints as they are called near. lib crtlib.lib+cdllsupp.lib; Programming Considerations -------------------------- One of the most important things to remember when using a DLL version of the CRT is that the DLL is multiple-threaded. Therefore, you MUST use the multiple-threaded version of the C header files (include files). To do this you can either give explicit paths to the multiple- threaded include files in the source or use the CL compiler switch "/I" to modify the current setting of the INCLUDE environment variable. Compiling a C source using Microsoft C Version 5.10, and utilizing a DLL version of the CRT, would look something like the following: cl /I\include\mt /AS /Gs2 /DDLL /c main.c The "/I\include\mt" specifies that the multiple-threaded include files are to be used. The "/Gs2" switch generates 80286 code and turns off stack checking. This is very important. Stack checking MUST be turned off with small or compact memory model programs, which utilize DLLs. Stack checking can be on with medium or large/huge memory models. The /DDLL switch defines the DLL symbol, which is used to distinguish between the non-DLL version of the CRT, LLIBCMT.LIB, and the DLL version, CRTLIB.DLL. To link an object module with the DLL version of the CRT, the following command is used: link /NOI /NOD main+crtexe,,,crtlib.lib doscalls.lib,main.def The /NOD is required so that symbols are not multiply defined. The file CRTEXE.OBJ links in start-up code for the executable file that is not present in the library created by IMPLIB. MAIN.DEF is the module definition file for MAIN.C. Another thing to consider during program design is that the C run-time data is shared between the main program and any other DLLs that access the CRTLIB.DLL in the process. In other words, even though the main program and each DLL have their own data segments, which are not shared, they all share the C run-time data. C run-time data includes such things as environment strings, global C run-time data, and thread ID numbers. The following is from Section 5.2 in MTDYNA.DOC: A program built using the dynamically linked multiple-threaded support of the run-time library may share the C run-time library with one or more dynamic-link libraries that are closely related to it. C run-time global data (such as the standard I/O package FILE, pointers of buffered I/O, and memory allocated with malloc functions) is shared. This means that the program and the associated dynamic-link libraries must cooperate on the usage of this data. For complete details on creating a DLL version of the C run time, as well as other information on both single and multiple-threaded programs, your first reference should be MTDYNA.DOC. ====================================================================== C Run-Time Routines Cannot Be Placed in an Overlay by Renata Bachelor On some occasions you may want to extract a routine from the C run- time library and put it in an overlay. If you try this procedure, your program will compile and link without warnings or errors. However, when you run the program, your machine may hang. This problem occurs because a segment is requested by a call to a routine in that segment. The FIRST request for a segment determines where the linker will place the ENTIRE segment. After you extracted a module from the library, you put the .OBJ in either the root or in an overlay. If you put the overlay in the root, the entire segment goes in the root; if you put it in an overlay, the entire segment goes in the overlay. This is expected linker behavior for the following reasons: 1. The run-time routines for medium and large models (the only ones that overlays deal with) are compiled with /NT _TEXT. This causes ALL the run-time routines to be placed in the same named segment (_TEXT); the linker cannot split a segment between the root and the overlay. 2. Segmentation takes precedence over overlays. 3. The linker constructs overlays from segments, not individual functions or library modules. So, when you extract a module from the run-time library and put it in the overlay, ALL the run time gets put in the overlay. As a result, the entry point of the overlay manager is put into the overlay and not in the root. The overlay manager code (also in the _TEXT) is not present in memory at startup and the machine hangs. Putting the .OBJ in an overlay may APPEAR to succeed (the machine does not hang) if the first reference to _TEXT is made by a function called from the root. The entire segment of routines is then placed in the root, including the routines called from the "overlaid" .OBJ. The linker behavior is the same for routines from GRAPHICS.LIB (and PGCHART.LIB, which is distributed with QuickC and QuickAssembler). If you are curious about which segments get which symbols, create and view a link map made at compile or link time. ====================================================================== Programming the Mouse for a Hercules Monochrome Graphics Card by Tony Claflin When programming the mouse driver in C to display the default graphics cursor (an arrow), you must perform the following steps in the sequence shown: 1. Store a "6" in memory location 40h:49h if the Hercules card is using the C run-time library (CRT), Page 0. Store a "5" in memory location 40h:49h if the Hercules card is using the CRT, Page 1. 2. Reset the mouse driver (call function 0). 3. Put the Hercules card into graphics mode. 4. Display the cursor (call function 1). The sequence of steps in the "Microsoft Mouse Programmer's Reference Guide" is incorrect for C programming. When this sequence is followed, the program displays streaks and/or dots instead of an arrow. The new "Microsoft Mouse Programmer's Reference" from Microsoft Press has the correct sequence in the programming example on Pages 250-252. The following programming example displays an arrow and allows you to move it around with the mouse. This ability terminates when you press a key. #include main() { char far * videomode=(char far *)0x00400049; int m1,m2,m3,m4; *videomode=6; m1=0; cmouses(&m1,&m2,&m3,&m4); _setvideomode(_HERCMONO); m1=1; cmouses(&m1,&m2,&m3,&m4); getch(); *videomode=7; _setvideomode(_DEFAULTMODE); } ====================================================================== Answers to Common Questions About Microsoft QuickBASIC Version 4.50 by Edna Kainz and Steve Elston This article is intended for individuals who are using QuickBASIC Version 4.50 for the IBM PC and compatibles, and provides answers to common questions, along with supplementary information on QuickBASIC Version 4.50. MEMORY MANAGEMENT AND MODULAR PROGRAMMING ----------------------------------------- Modular Programming ------------------- Question: What is modular programming? How do I modularize a program? Response: QuickBASIC has several features to help you create programs that are organized in a logical and structured manner. This style of programming is often referred to as "modular" programming. There are many advantages to modular programming; the most important advantage is that the logic of a modular program is clearer. A modular program is structured in such a way that the various functional blocks of source code are isolated in separate procedures. This makes it easy to reuse particular procedures in other programming projects and greatly simplifies debugging. In a modular program, problems can be quickly isolated to a given procedure. The procedure can then be tested and debugged separately, without you having to consider the remainder of the program. QuickBASIC Modular Programming Vocabulary ----------------------------------------- There are several important terms used by QuickBASIC programmers when talking about program structure. It is important to understand these terms in order to fully utilize the QuickBASIC programming environment. 1. Module: A section of program source code that is stored in a separate file and can be separately compiled. Every program has at least one module (the main module) and may consist of many modules (support modules). The modules are separately compiled and linked together to produce a finished executable program. 2. Procedure: A general term referring to either SUBs or FUNCTIONs in QuickBASIC. Conceptually, a procedure is a functional block of code that performs a specific action and that is logically distinct from the rest of the program. 3. SUB: Short for SUBProgram. A block of QuickBASIC code is delimited by SUB....END SUB. Do not confuse this with a subroutine. Subroutines are blocks of code that are terminated with a RETURN statement and were used in older forms of BASIC. 4. FUNCTION: A block of code that is delimited by FUNCTION....END FUNCTION. Similar to SUBs except that FUNCTIONs are used when a procedure is needed that returns a single value. Do not confuse FUNCTIONs with the older DEF FN functions. 5. Module level code: The code that is found at the module level, which is outside of any procedure. 6. Procedure level code: The code that is found inside a SUB or FUNCTION procedure. QuickBASIC Modular Programming Features --------------------------------------- By pressing the F2 key or choosing View Subs from the View menu inside QuickBASIC, you can see an outline view of the program that is currently loaded. The resulting window will show each module name, and each of the procedures in that module will be indented under it. Each editing window in QuickBASIC shows the code of one procedure at a time. Use the View Subs display window to select the procedure that you want to edit. Also, from this same display, you can delete and move procedures at will. Whenever you enter the reserved word SUB or FUNCTION, followed by a procedure name, QuickBASIC creates a new editing window for you so that you can add the code for that procedure. The fastest way to program in QuickBASIC is to design your program so that the main module-level code calls procedures. Just determine each action that the program must perform and then write a procedure to accomplish that task. Then create the module-level code to tie all of the procedures together. Execution starts at the beginning of the main module-level code. If your program requires more than one module, your support modules will contain additional procedures; however, note that since the only way to transfer control across modules is to call a procedure, module- level code in support modules is unreachable. This means that support modules contain only declarative statements and procedures. You will never have any executable statements in the module-level code of a support module. The flow of control, for the overall program, is governed by the module-level code of your main module. Memory Management, the Big Picture ---------------------------------- Question: How do I get more string space? Response: There are several things to keep in mind when programming in QuickBASIC. Because BASIC manages memory for you, you need to understand the limitations of the BASIC memory-management system. The most important points for the programmer are the following: 1. Your program receives one 64K code segment for each module that it contains. If the code generated by the compiler for a given module approaches 64K, you must add a new module to your program to continue adding code. The easiest way to determine if you need to add a new module is to look at the .MAP file produced by the linker, LINK.EXE. You will notice at the top of the .MAP file listing that there is a segment with the same name as your module with an _CODE appended, listed under the BC_CODE class. This is the code segment for that module and must be smaller than 64K. 2. Your entire executable program, no matter how many modules it contains, has only one near data segment. All ordinary variables, all variable-length STRINGs, and your stack are located in this segment. The FRE() function can be used to determine if you are close to filling up this segment. The "Out of STRING Space" error indicates that this segment is full. Usually, the best approach to minimizing your usage of the near data segment is to move as many items as possible out into the far heap. However, the BASIC memory management engine allows only certain types of data items to be placed in far memory. These items are DYNAMIC arrays of numeric data or fixed-length STRINGs. Variable-length STRINGs never go in the far heap. The easiest way to move these items out of the near data segment is to make all arrays DYNAMIC unless there is a specific reason to keep them STATIC. Usually, the program structure shown below is the simplest organization: Pseudo Code ----------- DIM all STATIC arrays first COMMON statements next REM $DYNAMIC DIM all DYNAMIC arrays here, including the ones placed in COMMON Also, if practical, use only arrays of fixed-length STRINGs. Remember, arrays of variable-length STRINGs cannot go into the far heap. These techniques will minimize the portion of the near data segment that your program's data requires, leaving more room for conventional variables and variable-length STRINGs. If any of your DYNAMIC arrays must be larger than 64K, you will need to start QuickBASIC or compile with the /Ah option. Note: Microsoft BASIC Professional Development System (PDS) 7.00 offers support for far variable-length strings and Expanded Memory Specification (EMS 4.0), while giving your programs more code and data space so that you can develop dramatically larger programs for MS-DOS or OS/2. COMPATIBILITIES --------------- Question: Which versions of Microsoft FORTRAN, Macro Assembler, Pascal, C Compiler, and QuickC are required with QuickBASIC 4.50 for mixed- language programming? Response: QuickBASIC Version 4.50 creates .OBJ modules that can be linked with .OBJ modules from the following languages: Microsoft Pascal Version 4.00 Microsoft FORTRAN Versions 4.10 and 5.00 Microsoft C Version 5.10 and QuickC Versions 1.01 and 2.00 Microsoft Macro Assembler (MASM) Versions 5.00 and later Programs should be assembled/compiled using the medium, large, or huge memory model to be compatible with compiled BASIC, which is effectively in the medium memory model. Video Problems -------------- QuickBASIC Version 4.50 is more selective of the video hardware on which it will operate than QuickBASIC Versions 4.00 and 4.00b. QuickBASIC requires a video card that is 100-percent compatible with an IBM CGA, EGA, VGA, or Hercules Monochrome card. If QB.EXE Version 4.50 does not operate with your video system, try invoking QuickBASIC with each of the video-specific options, such as: Option Description ----- ----------- /b (black-and-white) option /nohi (no high-intensity) option /g (update screen as fast as possible) option /h (high-resolution) option Example: qb /b Also, try setting the video mode from MS-DOS using the MODE command before initiating QuickBASIC (for example, MODE CO80 or MODE BW80). Example: MODE CO80 qb MODE BW80 qb If a ghost image appears after running QuickBASIC on your video system, use the MS-DOS MODE command to clear the screen if CLS doesn't clear it. The following is a list of known compatibility problems: 1. According to Microsoft's testing, the following cards loaded QB.EXE, but had numerous problems with screen swapping: Tecmar VGA Quadram VGA Vega Video Seven FastWrite VGA Vega VGA (a customer suggested QB /H for better Vega VGA behavior) 2. According to Microsoft's testing, the following cards will not load QB.EXE: COMPAQ Laptop (BIOS problem -- no correction) COMPAQ SLT/286 (okay with AC power, fails with battery unless you disable the power-conservation utility PWRCON.EXE or PWRCON.COM.) Genoa SuperVGA HiRes ATI VIP VGA Sigma EGA HINTS AND SUGGESTIONS --------------------- Question: How should I set up my COMmunications line in QuickBASIC 4.50? Response: If you have problems using COM1 or COM2, try the following OPEN statement, which makes BASIC as tolerant as possible of hardware- related problems: OPEN "COM1:300,N,8,1,BIN,CD0,CS0,DS0,OP0,RS,TB2048,RB2048" AS #1 (This OPEN is FOR RANDOM access.) The following is an explanation of each recommended parameter used in this OPEN statement: 1. The higher the baud rate, the greater the chances for problems; thus, 300 baud is unlikely to give you problems. 2400 baud is the highest speed possible over most telephone lines, due to their limited high-frequency capability. 19,200 baud, which requires a direct wire connection, is most likely to cause problems. (Possible baud rates for QuickBASIC are 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 9600, and 19,200.) 2. Parity usually does not help you significantly; because of this, you should try No parity (N). For those devices that require parity, you should use the PE option (Parity Enable, required to turn on parity checking) in the OPEN COM statement. When the PE option turns on parity checking, a "Device I/O error" occurs if the two communicating programs have two different parities. (Parity can be even, odd, none, space, or mark.) For example, a "Device I/O error" occurs when two programs try to talk to each other across a serial line using the following two different OPEN COM statements: OPEN "COM1:1200,O,7,2,PE" FOR RANDOM AS #1 and OPEN "COM2:1200,E,7,2,PE" FOR RANDOM AS #2 If the PE option is removed from the OPEN COM statements above, no error message displays. 3. 8 data bits require No parity (N) because of the size limit for BASIC's communications data frame (10 bits). 4. The BIN (binary mode) is the default. Note: The ASC option does NOT support XON/XOFF protocol, and the XON and XOFF characters are passed without special handling. 5. Ignoring hardware handshaking often corrects many problems. Thus, if your application does not require handshaking, you should try turning off the following hardware line-checking: CD0 = Turns off time-out for Data Carrier Detect (DCD) line. CS0 = Turns off time-out for Clear To Send (CTS) line. DS0 = Turns off time-out for Data Set Ready (DSR) line. OP0 = Turns off time-out for a successful OPEN. 6. RS suppresses detection of Request To Send (RTS). 7. For buffer-related problems, try increasing the transmit and receive buffer sizes above the 512-byte default: TB2048 = Increases the transmit buffer size to 2048 bytes. RB2048 = Increases the receive buffer size to 2048 bytes. A larger receive buffer can help you work around BASIC delays caused by statements such as PAINT, which use the processor intensively. The following are additional important hints for troubleshooting communications problems: 1. You should use the INPUT$(x) function in conjunction with the LOC(n) function to receive all input from the communications device [where x is the number of characters returned by LOC(n), which is the number of characters in the input queue waiting to be read; n is the file number that you OPENed for "COM1:" or "COM2:"]. Avoid using the INPUT#n statement to input from the communications port because INPUT#n waits for a carriage return (ASCII 13) character. Avoid using the GET#n statement for communications because GET#n waits for the buffer to fill (and buffer overrun could then occur). 2. For an example of data communications, please refer to the TERMINAL.BAS sample program that comes on the release disk for QuickBASIC Version 4.50. Many communications problems may actually be due to inappropriate source code design and flow of control. 3. Many communications problems can be shown only on certain hardware configurations and are difficult to resolve or duplicate on other computers. We recommend experimenting with a direct connection (with a short null-modem cable) instead of with a phone/modem link between sender and receiver to isolate problems on a given configuration. 4. The wiring schemes for cables vary widely. Check the pin wiring on your cable. For direct cable connections, a long or high-resistance cable is more likely to cause problems than a short, low-resistance cable. 5. If both "COM1:" and "COM2:" are open, "COM2:" will be serviced first. At high baud rates, "COM1:" can lose characters when competing for processor time with "COM2:". 6. Using the ON COM GOSUB statement instead of polling the LOC(n) function to detect communications input can sometimes help you work around timing or buffering problems caused by delays in BASIC. Delays in BASIC can be caused by string-space garbage collection, PAINT statements, or other operations that heavily use the processor. Many commercial communications programs use sophisticated techniques not found in Microsoft BASIC, and may give better performance. If you need better communications performance than you are getting from BASIC, you may want to try Microsoft C. (You can call Microsoft C Versions 5.x routines from QuickBASIC Version 4.50.) Question: Why doesn't QuickBASIC support COM3 and COM4 serial ports? Response: Support for these two additional communications ports requires a larger code size for QuickBASIC in both the compiler and the run-time module. Therefore, the decision was made NOT to support COM3 and COM4. The QuickBASIC compiler supports the use of serial communications ports COM1 and COM2 through the use of the OPEN "COM" statement. To access COM3 and COM4, it is possible for compiled BASIC to call third-party library routines, which are listed in catalogs such as the "Programmer's Connection Buyer's Guide" [in the United States: (800) 336-1166, in Canada: (800) 225-1166, Customer Service: (216) 494- 8899]. For example, you may want to contact the Software Interphase Company to determine if its QuickComm product supports COM3 and COM4, which are called from Microsoft compiled BASIC. Question: Can you give an example of key trapping? Response: Pressing any key in combination with CTRL, SHIFT, ALT, CAPS LOCK, or NUM LOCK changes the keyboard scan code. To trap combinations of keys, the KEY statement requires adding together the values of the keyboard flags as shown in the code example below. The following is a code example: CONST alt = &H8 CONST noflag = &H0 CONST leftshift = &H1 CONST rightshift = &H2 CONST ctrl = &H4 CONST numlock = &H20 CONST capslock = &H40 CONST extendedkeyboard = &H80 CONST left = &H4B CONST right = &H4D CONST up = &H48 CONST down = &H50 CONST C = &H2E CONST scrolllock = &H46 KEY 15, CHR$(extendedkeyboard + numlock) + CHR$(left) KEY 16, CHR$(extendedkeyboard + numlock) + CHR$(right) KEY 17, CHR$(extendedkeyboard + numlock) + CHR$(up) KEY 18, CHR$(extendedkeyboard + numlock) + CHR$(down) KEY 19, CHR$(ctrl + capslock) + CHR$(C) KEY 20, CHR$(extendedkeyboard + ctrl + numlock) + CHR$(scrolllock) ON KEY(15) GOSUB Keyleft ON KEY(16) GOSUB Keyright ON KEY(17) GOSUB Keyup ON KEY(18) GOSUB Keydown ON KEY(19) GOSUB Keybreak ON KEY(20) GOSUB Keybreak KEY(15) ON KEY(16) ON KEY(17) ON KEY(18) ON KEY(19) ON KEY(20) ON WHILE UCASE$(INKEY$) <> UCASE$("q") WEND END Keyleft: PRINT "left" RETURN Keyright: PRINT "right" RETURN Keyup: PRINT "up" RETURN Keydown: PRINT "down" RETURN Keybreak: PRINT "break" RETURN Execution Speed --------------- Question: Why are the newer versions of QuickBASIC slower than the previous ones? Response: The execution speed differences among different versions of QuickBASIC are due to different internal floating-point math representations. QuickBASIC Versions 1.00 and 2.00 used Microsoft Binary Format (MBF) representation. QuickBASIC 3.00 was actually shipped with two different versions: QB.EXE used MBF representation, and QB87.EXE, for machines with a math coprocessor, used IEEE format floating-point representation. All Microsoft BASIC products (for MS-DOS or OS/2) since QuickBASIC Version 4.00 have used IEEE format exclusively. There are several reasons why Microsoft chose to support the IEEE floating-point standard rather than continuing to use MBF. The main reason is that IEEE is the industry standard and is required for the Intel 80x87 math coprocessors. Also, all other Microsoft language products (except COBOL) use IEEE. Therefore, supporting IEEE in QuickBASIC, as well, makes interlanguage programming using any combination of these products much easier. IEEE support, however, requires more overhead and did cause execution speed to slow, although execution speed on machines equipped with a math coprocessor is slightly faster than older (MBF) versions of BASIC. Since INTEGER math is much faster than floating-point math, the best way to improve the speed of your program is to use INTEGER variables whenever possible. One easy way to accomplish this is to use the following code fragment in the beginning of your programs: DEFINT A-Z The default, in BASIC, is to create new variables as SINGLE-precision floating point. Using the DEFINT A-Z forces all new variables that are not declared as some other type (usually this is done with a type specifier such as x! for SINGLE precision) to be INTEGERs. On most programs this makes a dramatic improvement. The variables that have the greatest effect upon execution speed are those that are frequently accessed, such as loop and array indexes. Make these types of items INTEGERs whenever possible. Limitations of Floating-Point Mathematics ----------------------------------------- Question: What are some mathematical rounding issues? Response: Floating-point mathematics is a complex topic that confuses many programmers. The tutorial below should help you recognize programming situations where floating-point errors are likely to occur and show you how to avoid them. It should also allow you to recognize cases that are caused by inherent floating-point math limitations as opposed to compiler errors. Decimal and Binary Number Systems --------------------------------- Normally, we count things in base 10. The base is completely arbitrary. (The only reason that people have traditionally used base 10 is that they have 10 fingers, which make handy counting tools.) The number 532.25 in decimal (base 10) means the following: (5 * 10^2) + (3 * 10^1) + (2 * 10^0) + (2 * 10^-1) + (5 * 10^-2) 500 + 30 + 2 + 2/10 + 5/100 _________ = 532.25 In the binary number system (base 2), each column represents a power of 2, instead of 10. For example, the number 101.01 means the following: (1 * 2^2) + (0 * 2^1) + (1 * 2^0) + (0 * 2^-1) + (1 * 2^-2) 4 + 0 + 1 + 0 + 1/4 _________ = 5.25 Decimal How Integers Are Represented in PCs ----------------------------------- Since there is no fractional part to an integer, its machine representation is much simpler than it is for floating-point values. Normal integers on PCs are 2 bytes (16 bits) long with the most significant bit indicating the sign. Long integers are 4 bytes long. Positive values are straightforward binary numbers. For example: 1 Decimal = 1 Binary 2 Decimal = 10 Binary 22 Decimal = 10110 Binary etc. However, negative integers are represented using the "two's complement" scheme. To get the two's complement representation for a negative number, you need to take the binary representation for the number's absolute value and then flip all the bits and add 1. For example: 4 Decimal = 0000 0000 0000 0100 1111 1111 1111 1011 flip the bits -4 = 1111 1111 1111 1100 add 1 Note that -1 Decimal = 1111 1111 1111 1111 in binary, which explains why BASIC treats -1 as logical true (all bits = 1). This is a consequence of not having separate operators for bitwise and logical comparisons. Often in BASIC, it is convenient to use the code fragment below when your program will be making many logical comparisons. This greatly aids readability. CONST TRUE = -1 CONST FALSE = NOT TRUE Note that adding any combination of two's complement numbers together using ordinary binary arithmetic produces the correct result. Floating-Point Complications ---------------------------- Every decimal integer can be exactly represented by a binary integer; however, this is not true for fractional numbers. In fact, every number that is irrational in base 10 also is irrational in any system with a base smaller than 10. For binary, in particular, only fractional numbers that can be represented in the form p/q, where q is an integer power of 2, can be expressed exactly with a finite number of bits. Even common decimal fractions, such as decimal 0.0001, cannot be represented exactly in binary (0.0001 is a repeating binary fraction with a period of 104 bits). This explains why a simple example, such as the following will print 1.000054 as output: SUM = 0 FOR I% = 1 TO 10000 SUM = SUM + 0.0001 NEXT I% PRINT SUM ' theoretically = 1.0 The small error in representing 0.0001 in binary propagates to the sum. For the same reason, you should always be very cautious when making comparisons on real numbers. The following example illustrates a common programming error: item1# = 69.82# item2# = 69.20# + 0.62# IF item1# = item2# then print "Equality!" This will NOT print "Equality." Why? Because 69.82 cannot be represented exactly in binary, which causes the value that results from the assignment to be SLIGHTLY different (in binary) than the value that is generated from the expression. In practice, you should always code such comparisons in such a way as to allow for some tolerance. For example: IF (item1# < 69.83#) AND (item1# > 69.81#) then print "Equal" This WILL print "Equal." Other Common Floating-Point Errors ---------------------------------- The following are common floating-point errors: 1. Round-off error This error results when all of the bits in a binary number cannot be used in a calculation. Example: Adding 0.0001 to 0.9900 (SINGLE precision) Decimal 0.0001 will be represented as follows: (1.)10100011011011100010111 * 2^(-14+Bias) (13 leading zeros in binary!) 0.9900 will be represented as follows: (1.)11111010111000010100011 * 2^(-1+Bias) Now to actually add these numbers, the decimal (binary) points must be aligned. For this they must be unnormalized. Here is the resulting addition: .000000000000011010001101 * 2^0 (Only 11 of 23 bits retained) +.111111010111000010100011 * 2^0 ________________________________ .111111010111011100110000 * 2^0 This is called a round-off error because some computers round when shifting for addition. Others simply truncate. Round-off errors are important to consider whenever you are adding or multiplying two very different values. 2. Subtracting two almost equal values .1235 -.1234 _____ .0001 This will be normalized. Note that although the original numbers each had four significant digits, the result has only one significant digit. 3. Overflow and underflow This occurs when the result is too large or too small to be represented by the data type. 4. Quantizing error This occurs with those numbers that cannot be represented in exact form by the floating-point standard. 5. Division by a very small number This can trigger a "divide by zero" error or can produce bad results, as in the following example: A = 112000000 B = 100000 C = 0.0009 X = A - B / C In QuickBASIC, X now has the value 888887, instead of the correct answer, 900000. 6. Output error This type of error occurs when the output functions alter the values they are working with. More Information ---------------- For more information on floating-point mathematics, consult the following references: 1. Stark, Peter A. "Introduction to Numerical Methods." McMillan Publishing, 1970. 2. Forsythe, George E; Malcolm, Moler. "Computer Methods for Mathematical Computations." Prentice-Hall, 1977. For further information on the topics covered in this article, consult the following reference books: 1. Hergert, Douglas. "Microsoft QuickBASIC Developing Structured Programs in the Microsoft QuickBASIC Environment." Microsoft Press, 1989. 2. Wilton, Richard. "Programmer's Guide to PC & PS/2 Video Systems." Microsoft Press, 1987. 3. Norton, Peter. "The New Peter Norton Programmer's Guide to the IBM PC & PS/2." Microsoft Press, 1985. 4. Duncan, Ray. "Advanced MS-DOS Programming." Microsoft Press, 1988. 5. Clark Craig, John. "Microsoft QuickBASIC Programmer's Toolbox." Microsoft Press, 1988.