异常处理

程序执行时,可能会出现许多异常情况和错误(称为“异常”)。 这可能包括内存不足、资源分配错误和找不到文件。

Microsoft 基础类库使用异常处理方案,该方案与 ANSI 标准委员会针对 C++ 提出的方案非常相似。 在调用可能遇到异常情况的函数之前,必须设置异常处理程序。 如果函数遇到异常情况,则会引发异常,并将控件传递给异常处理程序。

Microsoft 基础类库附带的多个宏将设置异常处理程序。 如有必要,有许多其他全局函数可用于引发专用异常并终止程序。 这些宏和全局函数分为以下几类:

  • 异常宏,用于构造异常处理程序。

  • 异常引发函数),用于生成特定类型的异常。

  • 终止函数,用于终止程序。

有关示例和详细信息,请参阅文章异常

异常宏

名称 描述
TRY 指定用于异常处理的代码块。
CATCH 指定一个代码块,用于从前面的 TRY 块中捕获异常
CATCH_ALL 指定一个代码块,用于从前面的 TRY 块中捕获所有异常
AND_CATCH 指定一个代码块,用于从前面的 TRY 块中捕获其他异常类型
AND_CATCH_ALL 指定一个代码块,用于捕获前面的 TRY 块中引发的所有其他异常类型
END_CATCH 结束最后一个 CATCH 或 AND_CATCH 代码块
END_CATCH_ALL 结束最后一个 CATCH_ALL 代码块
THROW 引发指定的异常。
THROW_LAST 将当前处理的异常引发到下一个外部处理程序。

异常引发函数

名称 描述
AfxThrowArchiveException 引发存档异常。
AfxThrowFileException 引发文件异常。
AfxThrowInvalidArgException 引发无效参数异常。
AfxThrowMemoryException 引发内存异常。
AfxThrowNotSupportedException 引发不支持异常。
AfxThrowResourceException 引发 Windows 资源未找到异常。
AfxThrowUserException 在用户启动的程序操作中引发异常。

MFC 专为 OLE 异常提供两个异常引发函数:

OLE 异常函数

名称 描述
AfxThrowOleDispatchException 在 OLE 自动化函数中引发异常。
AfxThrowOleException 引发 OLE 异常。

为了对数据库异常提供支持,数据库类提供两个异常类:CDBExceptionCDaoException,以及支持异常类型的全局函数:

DAO 异常函数

名称 描述
AfxThrowDAOException 从自己的代码中引发 CDaoException
AfxThrowDBException 从自己的代码中引发 CDBException

MFC 提供以下终止函数:

终止函数

名称 描述
AfxAbort 发生错误时调用以终止应用程序。

TRY

设置 TRY 块

TRY

备注

TRY 块标识可能引发异常的代码块。 这些异常在以下 CATCH 和 AND_CATCH 块中进行处理。 允许递归:可以通过忽略异常或使用 THROW_LAST 宏将异常传递给外部 TRY 块。 使用 END_CATCH 或 END_CATCH_ALL 宏结束 TRY 块

有关详细信息,请参阅异常一文。

示例

请参阅 CATCH 的示例。

要求

标头:afx.h

CATCH

定义一个代码块,用于捕获前面的 TRY 块中引发的第一个异常类型

CATCH(exception_class, exception_object_pointer_name)

参数

exception_class
指定要测试的异常类型。 有关标准异常类的列表,请参阅类 CException

exception_object_pointer_name
为将由宏创建的异常对象指针指定名称。 可以使用指针名访问 CATCH 块中的异常对象。 已为您声明此变量。

备注

适当时,异常处理代码可以询问异常对象以获取有关异常的具体原因的详细信息。 调用 THROW_LAST 宏以将处理移动到下一个外部异常帧。 使用 END_CATCH 宏结束 TRY 块

如果 exception_class 是 CException 类,则将捕获所有异常类型。 可以使用 CObject::IsKindOf 成员函数来确定引发的特定异常。 捕获多种异常的更好方法是使用顺序 AND_CATCH 语句,每个语句都有不同的异常类型

异常对象指针由宏创建。 无需自行进行声明。

注意

将 CATCH 块定义为用大括号分隔的 C ++ 范围。 如果您在此范围中声明变量,则只能在该范围中访问它们。 这也适用于 exception_object_pointer_name

有关异常和 CATCH 宏的详细信息,请参阅异常一文。

示例

CFile* pFile = NULL;
// Constructing a CFile object with this override may throw
// a CFile exception and won't throw any other exceptions.
// Calling CString::Format() may throw a CMemoryException,
// so we have a catch block for such exceptions, too. Any
// other exception types this function throws will be
// routed to the calling function.
TRY
{
   pFile = new CFile(_T("C:\\WINDOWS\\SYSTEM.INI"),
      CFile::modeRead | CFile::shareDenyNone);
   ULONGLONG dwLength = pFile->GetLength();
   CString str;
   str.Format(_T("Your SYSTEM.INI file is %I64u bytes long.") , dwLength);
   AfxMessageBox(str);
}
CATCH(CFileException, pEx)
{
   // Simply show an error message to the user.
   pEx->ReportError();
}
AND_CATCH(CMemoryException, pEx)
{
   // We can't recover from this memory exception, so we'll
   // just terminate the app without any cleanup. Normally, 
   // an application should do everything it possibly can to
   // clean up properly and not call AfxAbort().
   AfxAbort();
}
END_CATCH
// If an exception occurs in the CFile constructor,
// the language will free the memory allocated by new
// and will not complete the assignment to pFile.
// Thus, our cleanup code needs to test for NULL.
if (pFile != NULL)
{
   pFile->Close();
   delete pFile;
}

CATCH_ALL

定义用来捕获前面的 TRY 块中引发的所有异常类型的代码块

CATCH_ALL(exception_object_pointer_name)

参数

exception_object_pointer_name
为将由宏创建的异常对象指针指定名称。 您可以使用指针名访问 CATCH_ALL 块中的异常对象。 已为您声明此变量。

备注

适当时,异常处理代码可以询问异常对象以获取有关异常的具体原因的详细信息。 调用 THROW_LAST 宏以将处理移动到下一个外部异常帧。 如果使用的是 CATCH_ALL,那么请使用 END_CATCH_ALL 宏结束 TRY 块

注意

将 CATCH_ALL 块定义为用大括号分隔的 C++ 范围。 如果您在此范围中声明变量,则只能在该范围中访问它们。

有关异常的详细信息,请参阅异常一文。

示例

请参阅 CFile::Abort 的示例。

要求

标头:afx.h

AND_CATCH

定义一个代码块,用于捕获前面的 TRY 块中引发的其他异常类型

AND_CATCH(exception_class, exception_object_pointer_name)

参数

exception_class
指定要测试的异常类型。 有关标准异常类的列表,请参阅类 CException

exception_object_pointer_name
由宏创建的异常对象指针的名称。 可以使用指针名访问 AND_CATCH 块中的异常对象。 已为您声明此变量。

注解

使用 CATCH 宏捕获一种异常类型,然后 AND_CATCH 宏捕获每个后续类型。 使用 END_CATCH 宏结束 TRY 块

适当时,异常处理代码可以询问异常对象以获取有关异常的具体原因的详细信息。 调用 AND_CATCH 块中的 THROW_LAST 宏,将处理转移到下一个外部异常帧。 AND_CATCH 标记前面的 CATCH 或 AND_CATCH 块的末尾

注意

将 AND_CATCH 块定义为 C ++ 范围(用大括号分隔)。 如果在此范围中声明变量,请记住,只能在该范围中访问它们。 这也适用于 exception_object_pointer_name 变量

示例

请参阅 CATCH 的示例。

要求

标头:afx.h

AND_CATCH_ALL

定义一个代码块,用于捕获前面的 TRY 块中引发的其他异常类型

AND_CATCH_ALL(exception_object_pointer_name)

参数

exception_object_pointer_name
由宏创建的异常对象指针的名称。 可以使用指针名访问 AND_CATCH_ALL 块中的异常对象。 已为您声明此变量。

备注

使用 CATCH 宏捕获一种异常类型,然后使用 AND_CATCH_ALL 宏捕获所有其他后续类型。 如果使用的是 AND_CATCH_ALL,那么请使用 END_CATCH_ALL 宏结束 TRY 块

适当时,异常处理代码可以询问异常对象以获取有关异常的具体原因的详细信息。 调用 AND_CATCH_ALL 块中的 THROW_LAST 宏,将处理转移到下一个外部异常帧。 AND_CATCH_ALL 标记前面的 CATCH 或 AND_CATCH_ALL 块的末尾

注意

将 AND_CATCH_ALL 块定义为 C ++ 范围(用大括号分隔)。 如果在此范围中声明变量,请记住,只能在该范围中访问它们。

要求

标头:afx.h

END_CATCH

标记最后一个 CATCH 或 AND_CATCH 块的末尾

END_CATCH

备注

有关 END_CATCH 宏的详细信息,请参阅异常一文。

要求

标头:afx.h

END_CATCH_ALL

标记最后一个 CATCH_ALL88 或 AND_CATCH_ALL 块的末尾

END_CATCH_ALL

要求

标头:afx.h

THROW (MFC)

引发指定的异常。

THROW(exception_object_pointer)

参数

exception_object_pointer
指向派生自 CException 的异常对象。

备注

THROW 会中断程序执行,并将控件传递给程序中关联的 CATCH 块。 如果尚未提供 CATCH 块,则会将控件传递给 Microsoft 基础类库模块,该模块会打印错误消息并退出

有关详细信息,请参阅异常一文。

要求

标头:afx.h

THROW_LAST

将异常抛回到下一个外部 CATCH 块

THROW_LAST()

备注

此宏允许引发本地创建的异常。 如果尝试引发刚刚捕获的异常,则通常会超出范围并被删除。 使用 THROW_LAST 将异常正确传递到下一 个 CATCH 处理程序

有关详细信息,请参阅异常一文。

示例

请参阅 CFile::Abort 的示例。

要求

标头:afx.h

AfxThrowArchiveException

引发存档异常。

void  AfxThrowArchiveException(int cause, LPCTSTR lpszArchiveName);

参数

cause
指定一个整数,用于指示异常的原因。 有关可能值的列表,请参阅 CArchiveException::m_cause

lpszArchiveName
指向一个字符串,该字符串包含导致异常的 CArchive 对象的名称(如果可用)。

要求

标头:afx.h

AfxThrowFileException

引发文件异常。

void AfxThrowFileException(
    int cause,
    LONG lOsError = -1,
    LPCTSTR lpszFileName = NULL);

参数

cause
指定一个整数,用于指示异常的原因。 有关可能值的列表,请参阅 CFileException::m_cause

lOsError
包含说明异常原因的操作系统错误号(如果可用)。 有关错误代码列表,请参阅操作系统手册。

lpszFileName
指向包含导致异常的文件名的字符串(如果可用)。

注解

你负责根据操作系统错误代码确定原因。

要求

标头:afx.h

AfxThrowInvalidArgException

引发无效参数异常。

语法

void AfxThrowInvalidArgException( );

备注

使用无效参数时调用此函数。

要求

标头: afx.h

AfxThrowMemoryException

引发内存异常。

void AfxThrowMemoryException();

备注

如果调用基础系统内存分配器(例如 mallocGlobalAlloc Windows 函数)失败,则调用此函数。 无需为 new 调用它,因为如果内存分配失败,new 会自动引发内存异常。

要求

标头:afx.h

AfxThrowNotSupportedException

因请求不支持的功能而引起的异常。

void AfxThrowNotSupportedException();

要求

标头:afx.h

AfxThrowResourceException

引发资源异常。

void  AfxThrowResourceException();

备注

当无法加载 Windows 资源时,通常会调用此函数。

要求

标头:afx.h

AfxThrowUserException

引发异常以停止最终用户操作。

void AfxThrowUserException();

备注

此函数通常在 AfxMessageBox 向用户报告错误后立即调用。

要求

标头:afx.h

AfxThrowOleDispatchException

使用此函数将在 OLE 自动化函数中引发异常。

void AFXAPI AfxThrowOleDispatchException(
    WORD wCode ,
    LPCSTR lpszDescription,
    UINT nHelpID = 0);

void AFXAPI AfxThrowOleDispatchException(
    WORD wCode,
    UINT nDescriptionID,
    UINT nHelpID = -1);

参数

wCode
特定于应用程序的错误代码。

lpszDescription
错误的文字说明。

nDescriptionID
错误文字说明的资源 ID。

nHelpID
应用程序的帮助 (.HLP) 文件的帮助上下文。

备注

提供给此函数的信息可由驱动应用程序(Microsoft Visual Basic 或其他 OLE 自动化客户端应用程序)显示。

示例

// Sort is method of automation class CStrArrayDoc
long CStrArrayDoc::Sort(VARIANT* vArray)
{
   USES_CONVERSION;

   // Type check VARIANT parameter. It should contain a BSTR array
   // passed by reference. The array must be passed by reference; it is
   // an in-out-parameter.

   // throwing COleDispatchException allows the EXCEPINFO structure of 
   // IDispatch::Invoke() to set
   if (V_VT(vArray) != (VT_ARRAY | VT_BSTR))
      AfxThrowOleDispatchException(1001,
         _T("Type Mismatch in Parameter. Pass a string array by reference"));

   // ...
   // ...

   return 0;
}

要求

标头:afx.h

AfxThrowOleException

创建 COleException 类型的对象并引发异常。

void AFXAPI AfxThrowOleException(SCODE sc);
void AFXAPI AfxThrowOleException(HRESULT hr);

参数

sc
指示异常原因的 OLE 状态代码。

hr
指示异常原因的结果代码的句柄。

备注

采用 HRESULT 作为参数的版本会将结果代码转换为相应的 SCODE。 有关 HRESULT 和 SCODE 的详细信息,请参阅 Windows SDK 中的 COM 错误代码结构

要求

标头 afxdao.h

AfxThrowDaoException

调用此函数,从自己的代码引发 CDaoException 类型的异常。

void AFXAPI AfxThrowDaoException(
    int nAfxDaoError = NO_AFX_DAO_ERROR,
    SCODE scode = S_OK);

参数

nAfxDaoError
表示 DAO 扩展错误代码的整数值,可以是 CDaoException::m_nAfxDaoError 下列出的某个值。

scode
DAO 的 OLE 错误代码,类型为 SCODE。 有关详细信息,请参阅 CDaoException::m_scode

备注

框架还调用 AfxThrowDaoException。 在调用过程中,可以传递其中一个参数或两者。 例如,如果要引发 CDaoException::nAfxDaoError 中定义的某个错误,但无需注意 scode 参数,请在 nAfxDaoError 参数中传递有效代码并接受 scode 的默认值

有关与 MFC DAO 类相关的异常的信息,请参阅此书中的 CDaoException 类以及异常:数据库异常一文。

要求

标头:afxdb.h

AfxThrowDBException

调用此函数,从自己的代码引发 CDBException 类型的异常。

void AfxThrowDBException(
    RETCODE nRetCode,
    CDatabase* pdb,
    HSTMT hstmt);

参数

nRetCode
RETCODE 类型的值,定义引发异常的错误的类型。

pdb
指向 CDatabase 对象的指针,该对象表示与异常关联的数据源连接。

hstmt
ODBC HSTMT 句柄,指定与异常关联的语句句柄。

注解

当框架从对 ODBC API 函数的调用中接收到 ODBC RETCODE 并将 RETCODE 解释为异常情况而非预期错误时,该框架将调用 AfxThrowDBException。 例如,由于磁盘读取错误,数据访问操作可能会失败。

有关 ODBC 定义的 RETCODE 值的信息,请参阅 Windows SDK 中的第 8 章“检索状态和错误信息”。 有关这些代码的 MFC 扩展的信息,请参阅 CDBException 类。

要求

标头:afx.h

AfxAbort

MFC 提供的默认终止函数。

void  AfxAbort();

备注

出现致命错误时(例如无法处理未捕获的异常),MFC 成员函数会在内部调用 AfxAbort。 在遇到的极少数无法从中恢复的灾难性错误时,可以调用 AfxAbort

示例

请参阅 CATCH 的示例。

要求

标头:afx.h

另请参阅

宏和全局函数
CException 类
CInvalidArgException 类