[WINAPI] 聊聊 CloseHandle、INVALID_HANDLE_VALUE 与 NULL

陪她去流浪 桃子 2016年04月27日 编辑 阅读次数:4105

昨天在公司进行 Code Review 时同事有类似如下一段代码:

if (pi.hThread != NULL)
{
    CloseHandle(pi.hThread);
}

if (pi.hProcess != NULL)
{
    CloseHandle(pi.hProcess);
}

,这段代码位于函数的收尾处,所以没有通常能见到的关闭句柄后置NULL操作。这不是我的疑问,我的疑问是,“判断句柄非空”的意义是什么?当时那位同事没能很好地回答这个问题,虽然大家都经常这么做。CloseHandle(NULL); 会发生什么事?大家觉得什么都不会发生,相安无事。

MSDN上对 CloseHandle 的说明是:

BOOL WINAPI CloseHandle(
  _In_ HANDLE hObject
);

Closes an open object handle.

hObject [in]

    A valid handle to an open object.

关闭一个已经打开的对象句柄,一个有效的对象句柄。

NULL(0)是一个有效的对象句柄吗?肯定不是。

那 INVALID_HANDLE_VALUE(-1) 呢?这是另外一个代表句柄无效的值。 CloseHandle(INVALID_HANDLE_VALUE); 会发生什么事呢?实际上,当程序在正常运行状态时,跟 NULL 一样,啥也不会发生。

那这是不是意味着,我们无需检测 CloseHandle 参数的句柄值是 NULL 或 INVALID_HANDLE_VALUE 就可以直接传递过去呢?实际上这样行不通,如果仔细读 MSDN 的话,它这样说道:

If the application is running under a debugger, the function will throw an exception if it receives either a handle value that is not valid or a pseudo-handle value.

“在应用程序在被调试状态时,一个无效的句柄值伪句柄值将使 CloseHandle 抛出一个异常。” 啥是伪句柄? GetCurrentProcess() 的返回值 INVALID_HANDLE_VALUE(-1) 就是一个伪句柄。

所以,根据经验:仅仅调用 CloseHandle 来关闭那些你成功打开的句柄,并且对每个句柄仅关闭一次

所以,那位同事的做法可能需要一些改进才能使程序更加健全。

标签:WinAPI