Microsoft KB Archive/92860

From BetaArchive Wiki

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

Q92860



The information in this article applies to:


  • The Microsoft Foundation Classes (MFC), included with:
    • Microsoft C/C++ for MS-DOS, version 7.0
    • Microsoft Visual C++, 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);
   } 

Additional query words:

Keywords : kb16bitonly kbFileIO kbMFC kbVC
Issue type : kbhowto
Technology : kbAudDeveloper kbMFC


Last Reviewed: May 8, 2001
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.