Moving QB/PDS Applications to VB/MS-DOS.
Steve Podradchik, Product Manager, VB/MS-DOS
VBITS March 29, 1993

* See the VB/MS-DOS Knowledgebase on Compuserve for many more articles.

Contents:
1. RUN with Overlays Can Cause "Too many files" error
2. C7 Module, Overlay, and Run-time Module Makes Computer Hang
3. Problem Tracking Location of Error When Using Overlays in VB/DOS
4. Distinguishing Standard and Extended Keys in KeyDown, KeyPress
=========================================================================
=========================================================================
Using RUN With Overlays Can Cause "Too many files" Error

Summary:

If you use the RUN statement to run a program repetitively that has
overlays, an error of "Too many files" or "Input path for run-time module
VBDRT10E.EXE:" is incorrectly returned. The "Too many files" error occurs
when compiling the program with the BC.EXE /O (stand-alone) option, and the
"Input path for run-time module VBDRT10E.EXE:" error occurs when compiling
without the /O option, and using the default run-time module instead.

You can work around this problem by compiling the program without overlays,
or by running the program in the interpreter (VBDOS.EXE) or by calling the
assembly language procedure shown below before using the RUN statement.

Microsoft has confirmed this to be a bug in the Professional Edition of
Microsoft Visual Basic for MS-DOS, version 1.0. We are researching this
problem and will post new information here as it becomes available.

More Information:

Steps to Reproduce Problem
--------------------------
1. Start VBDOS.EXE.

2. Create a module named MAIN.BAS which contains the following code:

   CALL sub1

3. Create another module named SUB1.BAS which contains the following code:

   SUB sub1
      PRINT "In SUB1"
      RUN "MAIN"
   END SUB

4. Exit VBDOS.EXE.

5. Compile and LINK the Basic modules in the following manner using BC.EXE
   and LINK.EXE:

   BC /O MAIN.BAS;
   BC /O SUB1.BAS;
   LINK MAIN.OBJ (SUB1.OBJ);

6. Run the application MAIN.EXE. It eventually exits with the error
   message "Too many files".

7. To reproduce the "Input path for run-time module VBDRT10E.EXE:" error,
   compile the program above without the /o option.

Workaround
----------
You can work around this problem by calling the following assembly language
procedure before using RUN:

COP.ASM:
   .model medium, basic
   ; extern unsigned short __far __cdecl _movefpause
   extrn __movefpause:word
   ; extern void __far __cdecl _movepause( void );
   extrn __movepause:Far
   __MOVE_PAUSE_DISK    equ   2
   __MOVE_PAUSE_CACHE   equ   4
   .code
   CloseOverlayPause proc
      mov    ax,seg __movepause      ; seg for __movefpause
      mov    es,ax
      mov    bx,es:__movefpause      ; get flags to modify
      or     bx,__MOVE_PAUSE_DISK    ; closes EXE
      or     bx,__MOVE_PAUSE_CACHE   ; shutdown caches
      mov    es:__movefpause,bx      ; put 'em back
      call   __movepause             ; execute pause
      ret
   CloseOverlayPause endp
   end

Assemble using MASM:

   MASM COP.ASM;

To apply the workaround to your program, add the following DECLARE to the
beginning of each module that uses RUN:

   DECLARE Sub CloseOverlayPause

Call the procedure before using RUN:

   SUB sub1
      PRINT "In SUB1"
      CALL CloseOverlayPause
      RUN "MAIN"
   END SUB

Link the assembly language procedure into your program:

   LINK MAIN.OBJ COP.OBJ (SUB1.OBJ);


======================================================================
C7 Module, Overlay, and Run-time Module Makes Computer Hang

Summary:

Programs hang when they use all of the following: overlays, a
Microsoft C/C++ version 7.0 module, and a run-time module.

To work around this problem, use one of these options:

 - Compile for stand-alone (BC option /O).
 - Do not use overlays.
 - Do not use C modules.

Microsoft has confirmed this to be a problem in the Professional
Edition of Microsoft Visual Basic version 1.0 for MS-DOS. We are
researching this problem and will post new information here in the
Microsoft Knowledge Base as it becomes available.

More Information:

Steps to Reproduce Problem
--------------------------
1. Type the following code into a source module called MOD1.BAS:

      'MOD1.BAS
      Declare Sub csub cdecl()
      Call csub

2. Compile the Basic module by entering the following command from an
   MS-DOS prompt:

      BC MOD1.BAS;

3. Using the following code, create a C program with Microsoft C/C++
   Version 7.0, and name it MOD2.C:

      /* MOD2.C */
      #include <stdio.h>
      void csub()
      {
         Printf("In the C Subroutine\n");
      }

4. Compile the C module from the MS-DOS prompt by using this command:

      CL /c /AL MOD2.C

5. Link the program in the following way:

      LINK MOD1.OBJ (MOD2.OBJ);

6. Run the MOD1.EXE program from the MS-DOS prompt.

At this point your computer will either hang (stop responding) or crash
(the screen goes blank).

======================================================================
Problem Tracking Location of Error When Using Overlays in VB/DOS

Summary:

When you are using overlays and working with a multiple module program, you
may experience a bug in tracking down the location of an error in your
code. This bug occurs because of the way the LINKer overlays modules.  All
the code in an overlay is in the same segment and the offset is from the
beginning of the segment.

The way code in an overlay is stored was changed in Visual Basic for MS-
DOS, version 1.0. This behavior did not occur in Microsoft Basic
Professional Development System (PDS) for MS-DOS, version 7.1.

Microsoft has confirmed this to be a bug in the Standard and  Professional
Editions of Microsoft Visual Basic for MS-DOS, version 1.0. We are
researching this problem and will post new information here as it becomes
available.

More Information:

The following steps can be used to reproduce this problem:

1. Start VBDOS.EXE.

2. In the default code window, include a CALL statement to a procedure
   named "Test", similar to the lines of code below (Main.BAS).

      DECLARE SUB test ()
      REM This is the main module.
      CALL Test

3. Select New Module... from the File Menu (Sup1.BAS). Add the following
   line:

      REM This is the first support module.

4. Select New Module... from the File Menu (Sup2.BAS). Add the following
   line:

      REM This is the second support module.

5. Select New Module... from the File Menu (Sup3.BAS). Add the following
   line:

      REM This is the third support module.
      SUB test ()
       x = 0
       Print 1 / x
          END SUB

6. Compile each .BAS module mentioned above. For example:

      BC Main.bas;
      BC Sup1.bas;
      BC Sup2.bas;
      BC Sup3.bas;

7. LINK the four modules with overlays. For example:

      LINK Main.obj+(Sup1.obj+Sup2.obj+Sup3.obj);

8. Once the Main.EXE program is created, run it and the following error is
   returned:

   Division by zero in module SUP3  at address 9FF1:00D1

9. This address location is incorrect, which makes it difficult to track
   down the actual location of the error in overlaid modules.

More Information:

Listed below is a portion of the README.TXT file that explains this
limitation in more detail:

1.9 Overlays
------------

Calculating the Offset of Errors
--------------------------------
If you are using the assembly listing generated when compiling with /A to
debug an overlaid program, you must subtract the start address of the
overlaid module from the offset in the error message to get the correct
code offset. For example:

Error Message:

Division by zero in line 0 of WILMA     as address 9FE9:0129

Excerpt of .MAP File Generated by LINK:

Start   Stop    Length Name                Class
. . .
Overlay 1H
00000H  00053H  00054H  FRED_CODE          BC_CODE
00060H  000B3H  00054H  BARNEY_CODE        BC_CODE
000C0H  00154H  00095H  WILMA_CODE         BC_CODE
Overlay 2H
. . .

To calculate the actual error address, subtract the start address of the
module WILMA (000C0H) from the offset given in the error message (0129):

129H - C0H = 69H

The offset of the error is 0069 in the compiler assembly listing.
============================================================================
Distinguishing Standard and Extended Keys in KeyDown, KeyPress

Summary:

In Visual Basic for MS-DOS, the KeyDown and KeyUp events receive the same
key codes for some standard ASCII and extended keys. For example, the F1
key and the lowercase "p" both return a KeyCode value of 112. Since the
KeyPress event only occurs for standard keys, you can determine which key
was pressed by monitoring whether a KeyPress event occurred. This method is
described in detail further below.

Microsoft has confirmed this to be a bug in the Standard and Professional
Editions of Microsoft Visual Basic for MS-DOS, version 1.0. We are
researching this problem and will post new information here as it becomes
available.

This behavior differs from Microsoft Visual Basic for Windows which gives
different KeyCode values for standard ASCII versus enhanced keys.

More Information:

There are three form events that can get called when you press a key:
KeyDown, KeyPress, and KeyUp. When you press an extended key, only the
KeyDown and KeyUp events get called. When you press a standard key, all
three events get called.

You can work around the problem described above since only the KeyDown and
KeyUp events get called when you press an extended key, whereas the
KeyPress event gets called when you press a standard ASCII key. If you set
a variable in the KeyPress event, you can then tell if an ASCII key was
pressed. The following example demonstrates this workaround:

1. Start VBDOS.EXE.

2. From the File menu select New Form... (FORM1.FRM). Form1 is created
   by default.

3. Exit the Form Designer, save all changes.

4. Add the following code to the module level of Form1:

     DIM SHARED Extended AS INTEGER

5. Add the following code to the Form_KeyDown event procedure of Form1:

     SUB Form_KeyDown (KeyCode AS INTEGER, Shift AS INTEGER)
       Extended = -1
     END SUB

6. Add the following code to the Form_KeyPress event procedure of Form1:

     SUB Form_KeyPress (KeyAscii AS INTEGER)
       Extended = 0
     END SUB

7. Add the following code to the Form_KeyUp event procedure of Form1:

     SUB Form_KeyUp (KeyCode AS INTEGER, Shift AS INTEGER)
       Const KEY_F1 = 112
       IF Extended THEN
         SELECT CASE KeyCode
         CASE KEY_F1
           PRINT "F1"
         ' Add more CASE statements to trap more keys.
         END SELECT
       ELSEIF KeyCode >= 32 OR KeyCode < 127 THEN
         PRINT CHR$(KeyCode)
       END IF
     END SUB

8. Press F5 to run the application. This program traps the "F1" and "p"
   keys. To trap more extended keys, add more lines to the SELECT CASE
   statement. To trap more standard ASCII characters, add more IF
   statements.
