如果你注意各种返回 HANDLE 值的函数,你会发现它们有些返回 NULL (如 CreateThread) 而有些则返回 INVALID_HANDLE_VALUE(如 CreateFile)。你不得不查询文档找出每种函数在失败时返回什么。
为什么返回值不统一?
如你所猜测,是历史原因。
这些值是用于兼容16位 Windows。16位函数 OpengFile, _lopen 和 _lcreate 在失败的时候返回-1。因此32位 CreateFile 函数返回 INVALID_HANDLE_VALUE 以便于从 Win16 中移植代码.
(基于此,你可以回答下面的问题:为什么我调用 CreateFile 而实际上并不是创建一个文?为什么不调用 OpenFile?答案是:是,OpenFile 是个更好的名字,但这个名字已经被用了。)
另一方面,没有与 Win16 等价的 CreateThread 或 CreateMutex,因此它们返回 NULL。
因为前已经设定了不统一的返回值,无论什么时候增加一个新函数,就有点难以确定新函数返回 NULL 或者 INVALID_HANDLE_VALUE。
这种不统一有几个后果。
第一,当然,你不得不小心地适时检查函数的返回值。
第二,这意味着如果你写一个通用的句柄封装类,你必须留意两个可能的“非句柄”值。
第三,如果你想预先初始化一个句柄变量,你必须初始化它为一个与你将用的值兼容。如,下面的代码是错误的:
代码有两个bug。首先,从 CreateFile 返回值的检查不正确。上面的代码检查 NULL 而不是 INVALID_HANDLE_VALUE。其次,代码初始化 h 变量不正确。下面是正确的版本:
第四,你必须非常小心地对待 INVALID_HANDLE_VALUE 值:偶然地,INVALID_HANDLE_VALUE 恰好等于 GetCurrentProcess() 返回的伪句柄。许多内核函数接受伪句柄,因此如果你不幸地偶然调用了,那么,WaitForSingleObject 一个 INVALID_HANDLE_VALUE 句柄,而事实上你在等待自已的进程,这个等待,显而易见,决不能因为进程退出时发出信号完成,因此你将等待你自己终止它。
原文链接:http://blogs.msdn.com/b/oldnewthing/archive/2004/03/02/82639.aspx