Copying Files from the .MVB File System

Now that DLLDEMO has access to the Viewer functions it needs, it is ready to copy a file from the .MVB file system. The ExportBag function performs this operation. ExportBag uses the following variables:

PUBLIC  RC PASCAL EXPORT ExportBag(
LPSTR    lszMVBname,
LPSTR    lszBagFName,
LPSTR    lszExportName,
DWORD    fFlags)
{
     RC      rc;            // return code
     HANDLE  hfMvb;         // handle for .MVB file
     HANDLE  hfBag;         // file handle to bag file
     DWORD   dBagStartPos;  // bag file start of file
                            //    position
     HANDLE  hFile;         // handle to output file
     BOOL    fClean = TRUE; // if set, delete file in error
                            //    state machine
     DWORD   dwBytesRead;   // input bytes read
     HANDLE  hMem;          // handle to copy buffer
     LPBYTE  lpMem;         // pointer to copy buffer

     VPTR    VPtr;

Getting a Handle to the .MVB File System

First, ExportBag uses the HfsOpenSz function to get a handle to the .MVB file system, as follows:

  if ((hfMvb = (*lpfn_HfsOpenSz)(lszMVBname, fFSOpenReadOnly)) == NULL) {
    rc = rcFailure;

    UNDOstateEXIT: 
    return rc;
  }

The lszMVBname parameter identifies the .MVB file for which it wants the handle. This parameter takes its value from Viewer's qchPath internal variable.

As you'll recall, ExportBag is executed from a hot spot in the DLLDEMO.MVB title. The DLLDEMO.MVP project file for that title includes a RegisterRoutine command that registers ExportBag as a Viewer authoring command. When ExportBag is run from the hot spot, qchPath is given as the first parameter to ExportBag.

Verifying the .MVB File

Next, ExportBag makes sure the baggage file within the .MVP file system is valid, as follows:

 if (((*lpfn_FAccessHfs)(hfMvb, lszBagFName, NULL)) == FALSE) {
    rc = rcNoExists;
    goto UNDOstateEXIT;
  }

The lszBagFName parameter to ExportBag gives this filename. Like the lszMVBname parameter, the baggage filename in lszBagFName is passed from the hot spot encoded in the DLLDEMO.MVB title. However, the baggage filename is hard-coded in the hot spot rather than obtained from a Viewer internal variable.

In this and other examples, the return code rc would normally be serviced in a common error routine at label UNDOstateEXIT. This error routine would inform the user of the problem. For simplicity, this error routine has been omitted from DLLDEMO.C.

Copying the Baggage File

ExportBag now opens the baggage file for reading, as folows:

  if ((hfBag = (*lpfn_HfOpenHfs)(hfMvb, lszBagFName, fFSOpenReadOnly)) ==
         NULL) {
        rc=rcNoExists;
                       UNDOstate1:
        (*lpfn_RcCloseHfs)(hfMvb);
        goto UNDOstateEXIT;
  }

It creates a buffer to improve efficiency in the copy:

  if ((hMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)wCOPY_SIZE)) == NULL) {
             rc = rcOutOfMemory;

                           UNDOstate2:
             (*lpfn_RcCloseHf)(hfBag);
             goto       UNDOstate1;
             }
        lpMem = GlobalLock(hMem);

To make sure the MS-DOS file it's copying to is not already present, ExportBag calls an assembler routine called lunlink. This routine executes a MS-DOS function to purge the filename ExportBag is using:

  lunlink(lszExportName);

ExportBag creates the MS-DOS file it's copying to and obtains a handle to the new file, as follows:

  if ((hFile = _lcreat(lszExportName,0)) == -1) {
     rc = rcOutOfMemory;
             UNDOstate3:
     GlobalUnlock(hMem);
     GlobalFree(hMem);
     goto      UNDOstate2;
  }

Now ExportBag starts the write loop that copies the baggage file to the new MS-DOS file, as follows:

  do {
    if ((dwBytesRead = (*lpfn_LcbReadHf)(hfBag, lpMem, wCOPY_SIZE)) == -1L)
    {
      rc = rcReadError;
             UNDOstate4:
      _lclose(hFile);
      if (fClean)
        lunlink(lszExportName);
      goto     UNDOstate3;
    }
    if (_lwrite(hFile, lpMem,(WORD)  dwBytesRead) != (WORD) dwBytesRead) {
      rc = rcDiskFull;
      goto     UNDOstate4;
    }
  } while (dwBytesRead == wCOPY_SIZE);

ExportBag reads chunks the size of the buffer it created until it reaches the end of the baggage file. The end-of-file condition is indicated when the LcbReadhf function returns -1L. ExportBag writes to the new MS-DOS file using the standard Windows function _lwrite.

When ExportBag has finished writing the MS-DOS file, it closes the baggage and MS-DOS files and cleans up its memory, as follows:

(*lpfn_RcCloseHfs)(hfMvb);
  _lclose(hFile);
  GlobalUnlock(hMem);
  GlobalFree(hMem);
  return rcSuccess; }