Microsoft KB Archive/101516

From BetaArchive Wiki

Article ID: 101516

Article Last Modified on 8/16/2005



APPLIES TO

  • Microsoft Visual Basic for MS-DOS
  • Microsoft Cinemania 97 Standard Edition
  • Microsoft QuickBasic 4.5 for MS-DOS
  • Microsoft MS-DOS 6.0 Standard Edition



This article was previously published under Q101516

SYMPTOMS

Using the BLOAD statement to load binary images directly into video memory from a disk drive that uses either the DoubleSpace disk compressor (DBLSPACE.BIN) or the SMARTDrive disk cache (SMARTDRV.EXE or SMARTDRV.SYS) may result in a corrupted image.


CAUSE

The DoubleSpace and SMARTDrive implementations assume they can read back from memory the same data they write. But because graphics screen memory is write-only with some video systems, this can yield incorrect data.

RESOLUTION

Here are several possible workarounds:

  • Copy the files to a drive that does not use SMARTDrive or DoubleSpace (such as a RAM drive). Then use BLOAD to load the files from that drive.
  • Use BLOAD to load the image into the memory occupied by a temporary dynamic array. Then move the image to video memory using PEEK and POKE. This method is slow but it works. For example:

    REDIM tmp(0 TO (BitPlaneSize - 1) \ 4) AS LONG  ' allocate memory
       DEF SEG = VARSEG(tmp(0))
       BLOAD f$, VARPTR(tmp(0))
       DIM j AS LONG
       FOR j = 0 TO BitPlaneSize - 1
          DEF SEG = VARSEG(tmp(0))
          DIM byte AS INTEGER
          byte = PEEK(VARPTR(tmp(0)) + j)
          DEF SEG = VideoPageSegment
          POKE j, byte
       NEXT
       REDIM tmp(0) AS LONG  ' deallocate memory
                            
  • Use BLOAD to load the image into the memory occupied by a temporary dynamic array. Then move the image to video memory using the Microsoft C function _fmemcpy. This method is fast, but it requires the correct version of Microsoft C. For example:

       ' put the next statement at the module level, all on one line
       DECLARE SUB fmemcpy CDECL ALIAS "__fmemcpy" (BYVAL o%, BYVAL s%,
          SEG s AS ANY, BYVAL n%)
    ...
    
       REDIM tmp(0 TO (BitPlaneSize - 1) \ 4) AS LONG  ' allocate memory
       DEF SEG = VARSEG(tmp(0))
       BLOAD f$, VARPTR(tmp(0))
       CALL fmemcpy(0, VideoPageSegment, tmp(0), BitPlaneSize)
       REDIM tmp(0) AS LONG  ' deallocate memory
                            
  • To use _fmemcpy in the interpreter environment, create a Quicklibrary named FMEMCPY.QLB by using the following commands:

    lib mlibce.lib *fmemcpy.obj;
    link /q fmemcpy.obj,,,vbdosqlb.lib mlibce.lib;
  • To link an EXE that uses _fmemcpy, use the following command. Use VBDRT10E.LIB for the run-time module, or VBDCL10E.LIB for stand-alone:

    link <objects here>,,,vbdrt10e.lib mlibce.lib;


STATUS

This behavior is by design. It is a limitation of DoubleSpace and SMARTDrive. Note that DoubleSpace comes with the MS-DOS operating system versions listed above, and SMARTDrive comes with many Microsoft products.

MORE INFORMATION

WARNING: One or more of the following functions are discussed in this article; VarPtr, VarPtrArray, VarPtrStringArray, StrPtr, ObjPtr. These functions are not supported by Microsoft Technical Support. They are not documented in the Visual Basic documentation and are provided in this Knowledge Base article "as is." Microsoft does not guarantee that they will be available in future releases of Visual Basic.

Steps to Reproduce Problem

The following program creates a solid rectangle in graphics SCREEN 9. The program saves this image, waits for a key press, then reloads the image. When the image is reloaded from a DoubleSpace or SMARTDrive disk, it is corrupted:

DECLARE SUB BSAVEImage ()
DECLARE SUB BLOADImage ()

CONST BitPlaneSize = 28000  ' Amount of disk space needed to save one
                            ' bit plane (in bytes) for SCREEN 9.
CONST VideoPageSegment = &HA800   ' Beginning of page 1 for
                                      ' SCREEN 9 in video memory.
CONST FileName = "IMAGE"
SCREEN 9, , 1, 1            ' Set the visual and active pages to 1.
CLS

LINE (50, 50)-(150, 150),, BF    ' Draw a solid box on the screen.
CALL BSAVEImage
CLS
PRINT "Press any key to reload the image "
WHILE INKEY$ = "": WEND
CALL BLOADImage
WHILE INKEY$ = "": WEND
END

SUB BLOADImage
   FOR i% = 0 TO 3
      OUT &H3C4, 2             ' Indicates index to Map Register.
      OUT &H3C5, 2 ^ i%        ' Select the bit plane to load into.
      f$ = FileName + CHR$(i% + 48) + ".GRA"
      ' replace the following two statements with the code for one
      ' of the workarounds
      DEF SEG = VideoPageSegment
      BLOAD f$, 0
   NEXT i%
   DEF SEG
END SUB

SUB BSAVEImage
   DEF SEG = VideoPageSegment
   FOR i% = 0 TO 3
      OUT &H3CE, 4             ' Select Read Map Select Register.
      OUT &H3CF, i%            ' Select the bit plane to save.
      f$ = FileName + CHR$(i% + 48) + ".GRA"
      BSAVE f$, 0, BitPlaneSize
   NEXT i%
   DEF SEG
END SUB
                

Keywords: kbprb KB101516