标头批注

[本主题介绍通过 Windows 7 的 Windows 标头中支持的批注。 如果要针对 Windows 8 进行开发,则应使用 SAL 批注中所述的注释。]

标头注释描述函数如何使用其参数和返回值。 这些批注已添加到许多 Windows 头文件,以帮助确保正确调用 Windows API。 如果启用从 Visual Studio 2005 开始可用的代码分析,如果不是根据注释中所述的使用调用这些函数,编译器将生成级别 6000 警告。 还可以在自己的代码中添加这些批注,以确保正确调用它。 若要在 Visual Studio 中启用代码分析,请参阅 Visual Studio 版本的文档。

这些批注在 Specstrings.h 中定义。 它们基于标准批注语言(SAL)的基元构建,并使用 _declspec("SAL_*")实现。

有两类批注:缓冲区批注和高级批注。

缓冲区批注

缓冲区注释描述函数如何使用其指针,并可用于检测缓冲区溢出。 每个参数可以使用零个或一个缓冲区批注。 缓冲区批注是用前导下划线和以下部分中介绍的组件构造的。

缓冲区大小 描述
大小
指定缓冲区的总大小。 与_bcount和_ecount配合使用;请勿与_part一起使用。 此值是可访问的空间;它可能小于分配的空间。
大小长度
指定缓冲区的总大小和初始化长度。 与_bcount_part和_ecount_part一起使用。 总大小可能小于分配的空间。
缓冲区大小单位 描述
_bcount
缓冲区大小以字节为单位。
_ecount
缓冲区大小在元素中。
方向 描述
_in
该函数从缓冲区读取。 调用方提供缓冲区并初始化它。
_inout
该函数同时读取和写入缓冲区。 调用方提供缓冲区并初始化它。 如果与_deref一起使用,则缓冲区可能会被函数重新分配。
_out
函数写入缓冲区。 如果对返回值或_deref使用,则函数提供缓冲区并初始化它。 否则,调用方提供缓冲区,函数初始化它。
间接 描述
_deref
取消引用参数以获取缓冲区指针。 此参数可能不 NULL
_deref_opt
取消引用参数以获取缓冲区指针。 此参数可以 NULL
初始化 描述
_full
该函数初始化整个缓冲区。 仅用于输出缓冲区。
_part
该函数初始化缓冲区的一部分,并显式指示了多少。 仅用于输出缓冲区。
必需或可选缓冲区 描述
_opt
此参数可以 NULL

以下示例显示了 GetModuleFileName 函数的批注。 hModule 参数是可选的输入参数。 lpFilename 参数是输出参数;其大小(以字符为单位)由 nSize 参数指定,其长度包括 null-terminating 字符。 nSize 参数是输入参数。

DWORD
WINAPI
GetModuleFileName(
    __in_opt HMODULE hModule,
    __out_ecount_part(nSize, return + 1) LPTSTR lpFilename,
    __in DWORD nSize
    );

以下是 Specstrings.h 中定义的批注。 使用上述表中的信息来解释其含义。

__bcount(大小
__bcount_opt(大小
__deref_bcount(大小
__deref_bcount_opt(大小
__deref_ecount(大小
__deref_ecount_opt(大小
__deref_in
__deref_in_bcount(大小
__deref_in_bcount_opt(大小
__deref_in_ecount(大小
__deref_in_ecount_opt(大小
__deref_in_opt
__deref_inout
__deref_inout_bcount(大小
__deref_inout_bcount_full(大小
__deref_inout_bcount_full_opt(大小
__deref_inout_bcount_opt(大小
__deref_inout_bcount_part(大小长度
__deref_inout_bcount_part_opt(大小长度
__deref_inout_ecount(大小
__deref_inout_ecount_full(大小
__deref_inout_ecount_full_opt(大小
__deref_inout_ecount_opt(大小
__deref_inout_ecount_part(大小长度
__deref_inout_ecount_part_opt(大小长度
__deref_inout_opt
__deref_opt_bcount(大小
__deref_opt_bcount_opt(大小
__deref_opt_ecount(大小
__deref_opt_ecount_opt(大小
__deref_opt_in
__deref_opt_in_bcount(大小
__deref_opt_in_bcount_opt(大小
__deref_opt_in_ecount(大小
__deref_opt_in_ecount_opt(大小
__deref_opt_in_opt
__deref_opt_inout
__deref_opt_inout_bcount(大小
__deref_opt_inout_bcount_full(大小
__deref_opt_inout_bcount_full_opt(大小
__deref_opt_inout_bcount_opt(大小
__deref_opt_inout_bcount_part(大小长度
__deref_opt_inout_bcount_part_opt(大小长度
__deref_opt_inout_ecount(大小
__deref_opt_inout_ecount_full(大小
__deref_opt_inout_ecount_full_opt(大小
__deref_opt_inout_ecount_opt(大小
__deref_opt_inout_ecount_part(大小长度
__deref_opt_inout_ecount_part_opt(大小长度
__deref_opt_inout_opt
__deref_opt_out
__deref_opt_out_bcount(大小
__deref_opt_out_bcount_full(大小
__deref_opt_out_bcount_full_opt(大小
__deref_opt_out_bcount_opt(大小
__deref_opt_out_bcount_part(大小长度
__deref_opt_out_bcount_part_opt(大小长度
__deref_opt_out_ecount(大小
__deref_opt_out_ecount_full(大小
__deref_opt_out_ecount_full_opt(大小
__deref_opt_out_ecount_opt(大小
__deref_opt_out_ecount_part(大小长度
__deref_opt_out_ecount_part_opt(大小长度
__deref_opt_out_opt
__deref_out
__deref_out_bcount(大小
__deref_out_bcount_full(大小
__deref_out_bcount_full_opt(大小
__deref_out_bcount_opt(大小
__deref_out_bcount_part(大小长度
__deref_out_bcount_part_opt(大小长度
__deref_out_ecount(大小
__deref_out_ecount_full(大小
__deref_out_ecount_full_opt(大小
__deref_out_ecount_opt(大小
__deref_out_ecount_part(大小长度
__deref_out_ecount_part_opt(大小长度
__deref_out_opt
__ecount(大小
__ecount_opt(大小
__在
__in_bcount(大小
__in_bcount_opt(大小
__in_ecount(大小
__in_ecount_opt(大小
__in_opt
__inout
__inout_bcount(大小
__inout_bcount_full(大小
__inout_bcount_full_opt(大小
__inout_bcount_opt(大小
__inout_bcount_part(大小长度
__inout_bcount_part_opt(大小长度
__inout_ecount(大小
__inout_ecount_full(大小
__inout_ecount_full_opt(大小
__inout_ecount_opt(大小
__inout_ecount_part(大小长度
__inout_ecount_part_opt(大小长度
__inout_opt
__外
__out_bcount(大小
__out_bcount_full(大小
__out_bcount_full_opt(大小
__out_bcount_opt(大小
__out_bcount_part(大小长度
__out_bcount_part_opt(大小长度
__out_ecount(大小
__out_ecount_full(大小
__out_ecount_full_opt(大小
__out_ecount_opt(大小
__out_ecount_part(大小长度
__out_ecount_part_opt(大小长度
__out_opt

高级批注

高级批注提供有关参数或返回值的其他信息。 每个参数或返回值都可以使用零个或一个高级批注。

注解 描述
__blocksOn(资源
函数在指定资源上块。
__callback
该函数可用作函数指针。
__checkReturn
调用方必须检查返回值。
__format_string
参数是一个字符串,其中包含 printf 样式 % 标记。
__in_awcount(expr大小
如果表达式在退出时为 true,则输入缓冲区的大小以字节为单位指定。 如果表达式为 false,则元素中指定大小。
__nullnullterminated
最多可访问缓冲区,包括两个 null 字符或指针的第一个序列。
__nullterminated
最多可访问缓冲区,包括第一个 null 字符或指针。
__out_awcount(expr大小
如果表达式在退出时为 true,则输出缓冲区的大小以字节为单位指定。 如果表达式为 false,则元素中指定大小。
__override
指定虚拟方法的 C#样式重写行为。
__reserved
参数保留供将来使用,必须为零或 NULL
__success(expr
如果表达式在退出时为 true,则调用方可以依赖于其他批注指定的所有保证。 如果表达式为 false,则调用方不能依赖保证。 此批注会自动添加到返回 HRESULT 值的函数中。
__typefix(ctype
将参数视为指定类型,而不是其声明的类型。

以下示例显示了 DeleteTimerQueueTimerFreeEnvironmentStrings以及 UnhandledExceptionFilter 函数的缓冲区和高级批注。

__checkReturn
BOOL
WINAPI
DeleteTimerQueueTimer(
    __in_opt HANDLE TimerQueue,
    __in     HANDLE Timer,
    __in_opt HANDLE CompletionEvent
    );

BOOL
WINAPI
FreeEnvironmentStrings(
    __in __nullnullterminated LPTCH
    );

__callback
LONG
WINAPI
UnhandledExceptionFilter(
    __in struct _EXCEPTION_POINTERS *ExceptionInfo
    );

SAL 注释

演练:分析缺陷 的 C/C++ 代码