Microsoft KB Archive/157073

= PRB: Exception Not Caught Using CArchive or CFile =

Article ID: 157073

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Foundation Class Library 4.2, when used with:  Microsoft Visual C++ 2.0 Professional Edition

 Microsoft Visual C++ 2.1

 Microsoft Visual C++ 2.2

 Microsoft Visual C++ 4.0 Standard Edition</li></ul>

 Microsoft Visual C++ 4.1 Subscription</li></ul>

 Microsoft Visual C++ 4.2 Enterprise Edition</li></ul>

 Microsoft Visual C++ 4.2 Professional Edition</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q157073

<div class="symptoms_section">

SYMPTOMS
When using CArchive or CFile, Visual C++ exceptions may not be caught if the CArchive and/or CFile are in the same try block as a read or write: void Test1 {       try { //Drive A: should contain a floppy with zero bytes free CFile file("A:\\BadFile.tmp", CFile::modeCreate                     | CFile::shareExclusive | CFile::modeWrite ); try { CArchive archive(&file, CArchive::store); //Fill up disk, and cause a              //CFileException::diskFull exception while(1) archive << (DWORD)17; }          catch ( CFileException* ex ) { ex->Delete; }          catch (...) { ASSERT(FALSE); }      }       catch ( CFileException* ex ) { ex->Delete; }      catch (...){ ASSERT(FALSE); }  } In this case, if the disk is full, the exception is not caught, terminate is called, and the application exits.

<div class="cause_section">

CAUSE
In the process of handling exceptions, objects inside the try block are destructed before the first catch block. During unwinding, when a second exception is thrown by a destructor before the first exception is caught, terminate is called.

Both the destructors for CArchive and CFile attempt to flush the buffer and close the open file. This can cause a second exception to get thrown and terminate to get called.

<div class="resolution_section">

RESOLUTION
Make sure that the CArchive or CFile object is not inside the same try block as any read or write on that object.

The CArchive object should also not be inside of the same try block as the CFile object it uses unless the CArchive was created in the CArchive::bNoFlushOnDelete mode. If this mode is used, the CArchive and CFile can safely be in the same try block. Care must be taken to call CArchive::Flush before the CArchive is deleted, and in a separate try block. The second example below shows using a CArchive in this mode.

<div class="status_section">

STATUS
This behavior is by design.

<div class="moreinformation_section">

MORE INFORMATION
This is a behavior of Visual C++ exception handling and did not occur with earlier versions of MFC, which did not use C++ exception handling.

Example 1
// This example shows placing CFile, CArchive, and writes in separate // try blocks /* Compile options needed: default AppWizard application */   void Test2 {      try { //Drive A: should contain a floppy with zero bytes free CFile file("A:\\BadFile.tmp", CFile::modeCreate                     | CFile::shareExclusive | CFile::modeWrite ); try { CArchive archive(&file, CArchive::store); try { //Fill up disk, and cause a                  // CFileException::diskFull exception while(1) archive << (DWORD)17; }              catch ( CFileException* ex ) { archive.Abort; ex->Delete; }              catch (...){ ASSERT(FALSE); }          }           catch ( CFileException* ex ) { file.Abort; ex->Delete; }          catch (...){ ASSERT(FALSE); }      }       catch ( CFileException* ex ) { ex->Delete; }      catch (...){ ASSERT(FALSE); }  }

Example 2
// This example uses CArchive::bNoFlushOnDelete so that CFile and // CArchive can be placed in the same try block. /* Compile options needed: default AppWizard application */   void Test3 {       try { //Drive A: should contain a floppy with zero bytes free CFile file("A:\\BadFile.tmp",              CFile::modeCreate | CFile::shareExclusive                           | CFile::modeWrite ); CArchive archive(&file,              CArchive::store | CArchive::bNoFlushOnDelete); try { //Fill up disk, and cause a CFileException::diskFull //exception while(1) archive << (DWORD)17; //Manually flush archive in try-block archive.Flush; }          catch ( CFileException* ex ) { archive.Abort; ex->Delete; }          catch (...){ ASSERT(FALSE); }      }       catch ( CFileException* ex ) { ex->Delete; }      catch (...){ ASSERT(FALSE); }  }

Additional query words: 2.00 2.10 2.20 4.00 4.10 4.20 kbdsd CArchive CFile Exception

Keywords: kbexcepthandling kbfileio kbprb KB157073

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.