Rationalization

Once you've successfully segmented your program so that it can be linked and executed as a .EXE file under MS-DOS, the next step is to rationalize your code. By rationalization I mean converting your program into a completely well-behaved MS-DOS application.

First, you must ruthlessly eliminate any elements that manipulate the peripheral device adapters directly, alter interrupt priorities, edit the system interrupt-vector table, or depend on CPU speed or characteristics (such as timing loops). In protected mode, control of the interrupt system is completely reserved to the operating system and its device drivers, I/O ports may be read or written by an application only under very specific conditions, and timing loops burn up CPU cycles that can be used by other processes.

As I mentioned earlier in this chapter, display routines constitute the most common area of hardware dependence in an MS-DOS application. Direct manipulation of the video adapter and its regen buffer poses obvious difficulties in a multitasking, protected-memory environment such as OS/2. For porting purposes, you must convert all routines that write text to the display, modify character attributes, or affect cursor shape or position into Int 21H Function 40H calls using ANSI escape sequences or into ROM BIOS Int 10H calls. Similarly, you must convert all hardware-dependent keyboard operations to Int 21H Function 3FH or ROM BIOS Int 16H calls.

Once all hardware dependence has been expunged from your program, your next priority is to make it well-behaved in its use of system memory. Under MS-DOS an application is typically handed all remaining memory in the system to do with as it will; under OS/2 the converse is true: A process is initially allocated only enough memory to hold its code, declared data storage, and stack. You can make the MS-DOS loader behave like the OS/2 loader by linking your application with the /CPARMAXALLOC switch. Alternatively, your program can give up all extra memory during its initialization with Int 21H Function 4AH, as recommended earlier in this chapter.

After your program completes its initialization sequence, it should dynamically obtain and release any additional memory it may require for buffers and tables with MS-DOS Int 21H Functions 48H and 49H. To ensure compatibility with protected mode, limit the size of any single allocated block to 65,536 bytes or less, even though MS-DOS allows larger blocks to be allocated.

Finally, you must turn your attention to file and device handling. Replace any calls to FCB file functions with their handle-based equivalents, because OS/2 does not support FCBs in protected mode at all. Check pathnames for validity within the application; although MS-DOS and the 3.x Box silently truncate a name or extension, OS/2 refuses to open or create a file in protected mode if the name or extension is too long and returns an error instead. Replace any use of the predefined handles for the standard auxiliary and standard list devices with explicit opens of COM1, PRN, LPT1, and so on, using the resulting handle for read and write operations. OS/2 does not supply processes with standard handles for the serial communications port or printer.