Copying Files from the .HLP File System

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

PUBLIC BOOL PASCAL EXPORT ExportBag(
LPSTR lszHLPname,
LPSTR lszBagFName,
LPSTR lszExportName,
QME qError)
{
HANDLE hfsHlp;// handle to .HLP file
HANDLE hfBag;// file handle to bag file
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;// ptr to copy buffer
OFSTRUCT ofs;

Getting a Handle to the .HLP File System

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

if ((hfsHlp = (*lpfn_HfsOpenSz)(lszHLPname, fFSOpenReadOnly)) == NULL)
{
qError->fwFlags = fwMERR_ABORT;
qError->wError = wMERR_PARAM;
goto ExitBag;
}

The lszHLPname parameter identifies the .HLP file for which it wants the handle. This parameter takes its value from Windows Help’s qchPath internal variable.

As you’ll recall, ExportBag is executed from two entry macros in the DLLDEMO.HLP Help file. The DLLDEMO.HPJ project file for that Help file includes a RegisterRoutine macro that registers ExportBag as a Help authoring macro. When ExportBag is run from the macros, qchPath is given as the first parameter to ExportBag.

Verifying the .HLP File

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

if (((*lpfn_FAccessHfs)(hfsHlp, lszBagFName, NULL)) == FALSE)
{
qError->fwFlags = fwMERR_RETRY;
qError->wError = wMERR_MESSAGE;
lstrcpy(qError->rgchError, "Could not open baggage file `");
lstrcat(qError->rgchError, lszBagFName);
lstrcat(qError->rgchError, "'.");
goto ExitBag;
}

The lszBagFName parameter to ExportBag gives this filename. Like the lszHLPname parameter, the baggage filename in lszBagFName is passed from the entry macros encoded in the DLLDEMO.HLP file. However, the baggage filename is hard-coded in the macro rather than obtained from a Windows Help 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)(hfsHlp, lszBagFName, fFSOpenReadOnly))
== NULL)
{
qError->fwFlags = fwMERR_ABORT;
qError->wError = wMERR_ERROR;
goto ExitBag;
}

It creates a buffer to improve efficiency in the copy:

if ((hMem = GlobalAlloc(GMEM_MOVEABLE,
(DWORD)wCOPY_SIZE)) == NULL)
{
qError->fwFlags = fwMERR_ABORT;
qError->wError = wMERR_MEMORY;
goto ExitBag;
}

lpMem = GlobalLock(hMem);

To make sure the MS-DOS file it’s copying to is not already present, ExportBag calls the Windows API OpenFile. This function executes an MS-DOS function to purge the filename ExportBag is using:

OpenFile(lszExportName, &ofs, OF_DELETE);

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)
{
qError->fwFlags = fwMERR_ABORT;
qError->wError = wMERR_ERROR;
goto ExitBag;
}

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)
{
qError->fwFlags = fwMERR_ABORT;
qError->wError = wMERR_ERROR;
goto ExitBag;
}
if (_lwrite(hFile, lpMem,(WORD) dwBytesRead) != (WORD) dwBytesRead)
{
qError->fwFlags = fwMERR_ABORT | fwMERR_RETRY;
qError->wError = wMERR_MESSAGE;
lstrcpy(qError->rgchError, "Out of disk space.");
goto ExitBag;
}
} while (dwBytesRead == wCOPY_SIZE);

ExportBag reads 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 _lwrite function.

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

ExitBag:
if (hfBag != NULL)
(*lpfn_RcCloseHf)(hfBag);
if (hfsHlp != NULL)
(*lpfn_RcCloseHfs)(hfsHlp);
if (hMem != NULL)
{
GlobalUnlock(hMem);
GlobalFree(hMem);
}
if (hFile != -1)
_lclose(hFile);
if (qError->wError != wMERR_NONE && fClean)
OpenFile(lszExportName, &ofs, OF_DELETE);