HOWTO: Read From or Write To CFile From Buffer Larger Than 64K

Last reviewed: July 22, 1997
Article ID: Q92860

The information in this article applies to:
  • The Microsoft Foundation Classes (MFC), included with:

        - Microsoft C/C++ version 7.0
        - Microsoft Visual C++ for Windows, versions 1.0, 1.5, 1.51 1.52
    

SUMMARY

In certain situations, an application can read or write a file larger than 65,535 bytes using one large buffer that is usually allocated by calling the GlobalAlloc() function. Traditionally, to use one buffer the application must perform huge pointer manipulations on a buffer pointer and call the _lread() and _lwrite() functions (provided by Microsoft Windows) in a loop.

In an application developed with the Microsoft Foundation Classes, an attempt to use a huge pointer with the CFile::Read() or CFile::Write() functions fails at the following assertion:

   ASSERT(AfxIsValidAddress(lpBuf, nCount));

The CFile::Read() and CFile::Write() functions each contain the ASSERT.

MORE INFORMATION

Because the AfxIsValidAddress() function was not designed to work with huge pointers, the ASSERT fails when the application specifies a huge pointer.

Version 2.0 and later of the Microsoft Foundation Classes provides two functions, CFile::ReadHuge() and CFile::WriteHuge() that can accept huge pointers. Even though these functions are not listed in the online or printed documentation, the DIBLOOK sample application uses these functions. The AFX.H header file provides prototypes for these CFile member functions.

In code developed with version 1.0 of the Microsoft Foundation Classes, the method illustrated below demonstrates working around this limitation. The Microsoft Foundation Classes Object Linking and Embedding (OLE) Stream Get() and Put() functions implement this method. For more information, please refer to the source code for these functions in the OLECLI.CPP file in the MFC\SRC directory.

The text below provides the ReadHuge() and WriteHuge() functions to read from and write to a CFile object from a very large buffer. These functions use the _HugeCalcSize() helper function to determine whether a memory read or write crosses a segment boundary.

A second code example demonstrates using the WriteHuge() function.

Source Code for ReadHuge() and WriteHuge() using

Functions from the Microsoft Foundation Class Library, version 1.0

   //
   // Prototypes
   //
   static UINT _HugeCalcSize(DWORD cbTotal, const void FAR* lpStart);
   DWORD ReadHuge(void FAR* lpBuffer, DWORD dwCount, CFile* file);
   void  WriteHuge(const void FAR* lpBuffer, DWORD dwCount, CFile* file);

   //
   // Functions Definitions
   //
   static UINT _HugeCalcSize(DWORD cbTotal, const void FAR* lpStart)
   {
      // Return Size to Read/Write
      // (16K max unless limited by segment bounds)
      //
      DWORD cb = 0x10000L - _AFX_FP_OFF(lpStart);
      if (cb > cbTotal)
         cb = cbTotal;
      return (cb > 16384) ? 16384 : (UINT)cb;
   }

   DWORD ReadHuge(void FAR* lpBuffer, DWORD dwCount, CFile* file)
   {
      ASSERT_VALID(file);

      DWORD dwToRead = dwCount;
      while (dwToRead > 0)
      {
         UINT nRead = _HugeCalcSize(dwToRead, lpBuffer);
         if (file->Read(lpBuffer, nRead) < nRead)
            return ((dwCount - dwToRead) + nRead);
         dwToRead -= nRead;
         lpBuffer = ((BYTE _huge*)lpBuffer) + nRead;
      }
      return dwCount;
   }

   void WriteHuge(const void FAR* lpBuffer, DWORD dwCount, CFile* file)
   {
      ASSERT_VALID(file);

      DWORD dwToWrite = dwCount;
      while (dwToWrite > 0)
      {
         UINT nWrite = _HugeCalcSize(dwToWrite, lpBuffer);
         file->Write(lpBuffer, nWrite);
         dwToWrite -= nWrite;
         lpBuffer = ((const BYTE _huge*)lpBuffer) + nWrite;
      }
   }

Sample Code That Uses WriteHuge()

   // WriteTest():
   //
   // Uses WriteHuge() to write a buffer to disk using the CFile
   // class from Microsoft Foundation Classes version 1.0.
   //
   void WriteTest(CString strFileName, DWORD length)
   {
       HGLOBAL hBuff = GlobalAlloc(GHND, length);
       ASSERT(hBuff != NULL);
       char FAR* pBuff = (char FAR*) GlobalLock(hBuff);

       CFile* pFile = new CFile(strFileName, CFile::modeCreate |
                          CFile::modeWrite | CFile::typeBinary);

       DWORD index;

       // Fill Buffer with Test Pattern
       //
       for (index = 0; index < length; index++)
       {
          *(pBuff+index) = (char) (index % 0x00000100);
       }

       // Write Buffer to Disk
       //
       ::WriteHuge(pBuff, length, pFile);

       pFile->Close();
       delete pFile;
       GlobalUnlock(hBuff);
       GlobalFree(hBuff);
   }
 

	
	


Keywords : kb16bitonly MfcFileIO kbhowto
Technology : kbmfc
Version : 1.0 1.5 1.51 1.52 7.0
Issue type : kbhowto


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 22, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.