当前位置:首页 > 2014世界杯

详细解析CloseHandle()

admin 2025-12-13 07:50:19 2548

书籍:《Visual C++ 2017从入门到精通》的2.9 内存管理

环境:visual studio 2022

内容:[例 2.52] 文件API函数简单应用

以下是 CloseHandle() 函数的详细解析,涵盖其作用、参数、使用场景、注意事项及代码示例:

​函数原型

BOOL CloseHandle(

HANDLE hObject // 要关闭的句柄

);

​参数说明

​**hObject**

​类型: HANDLE​说明: 需要关闭的句柄,可以是以下类型:

文件或设备的句柄(通过 CreateFile 获取)。线程或进程的句柄(通过 CreateThread/CreateProcess 获取)。内存映射文件句柄(通过 CreateFileMapping 获取)。其他内核对象句柄(如事件、互斥量、信号量等)。 ​示例:

HANDLE hFile = CreateFile(L"test.txt", GENERIC_READ, ...);

CloseHandle(hFile); // 关闭文件句柄

​返回值

​成功: 返回 TRUE。​失败: 返回 FALSE,可通过 GetLastError() 获取错误码。

​常见错误码:

ERROR_INVALID_HANDLE (6): 句柄无效(已关闭或从未有效)。ERROR_NOT_FOUND (1168): 句柄未被系统识别(可能已被其他进程关闭)。

​核心作用

​释放系统资源

每个 CreateFile、CreateThread 等函数创建的句柄均占用系统资源。​未关闭的句柄会导致资源泄漏,最终可能耗尽系统资源(如句柄数上限)。 ​确保数据完整性

对于文件或设备句柄,关闭时会自动刷新缓冲区并释放资源。​示例: 文件写入后未关闭句柄,可能导致数据未完全写入磁盘。 ​安全合规

敏感资源(如密码文件句柄)需及时关闭,避免被恶意利用。

​使用场景

1. 文件操作后关闭

HANDLE hFile = CreateFile(L"data.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if (hFile != INVALID_HANDLE_VALUE) {

WriteFile(hFile, "Hello World", 11, NULL, NULL);

CloseHandle(hFile); // 必须关闭文件句柄

}

2. 线程或进程句柄管理

HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

// 等待线程结束并关闭句柄

WaitForSingleObject(hThread, INFINITE);

CloseHandle(hThread); // 释放线程句柄

3. 内存映射文件释放

HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, L"MyMap");

if (hMapFile) {

CloseHandle(hMapFile); // 关闭映射文件句柄

}

​关键注意事项

​禁止重复关闭句柄

对已关闭的句柄再次调用 CloseHandle 会导致 ERROR_INVALID_HANDLE。​示例:

HANDLE hFile = CreateFile(...);

CloseHandle(hFile);

CloseHandle(hFile); // 错误!返回 FALSE

​句柄有效性检查

在关闭前可检查句柄是否有效(但非必需,因 CloseHandle 对无效句柄返回错误)。​示例: ​内核对象的引用计数

句柄是内核对象的引用计数器。只有当计数为0时,系统才会销毁对象。​示例:

若多个句柄指向同一内核对象(如文件被多个进程打开),需逐一关闭所有句柄。 ​与 DeleteObject 的区别

DeleteObject 用于图形资源(如 GDI 对象),而 CloseHandle 用于内核对象。​错误示例:

HBITMAP hBitmap = CreateBitmap(...);

CloseHandle(hBitmap); // 错误!应使用 DeleteObject(hBitmap)

​自动关闭机制

​子进程句柄: 当父进程关闭子进程句柄后,子进程仍可独立运行。​跨进程传递句柄: 使用 DuplicateHandle 复制句柄后,原句柄仍需手动关闭。

​常见问题与解决方案

问题1:程序运行后句柄数异常增长

​原因: 未正确关闭文件、线程或设备句柄。​解决:

使用工具(如 ​Process Explorer)监控句柄使用情况。确保每个 CreateXXX 调用都有对应的 CloseHandle。

问题2:文件关闭后仍被占用

​原因:

文件映射视图(MapViewOfFile)未解除。其他进程持有该文件句柄。 ​解决:

确保调用 UnmapViewOfFile 解除内存映射。检查其他进程是否未正确关闭句柄。

问题3:关闭句柄后文件被立即删除

​场景: 使用 FILE_FLAG_DELETE_ON_CLOSE 标志时,关闭句柄会删除文件。​示例代码:

HANDLE hFile = CreateFile(

L"tempfile.tmp",

GENERIC_WRITE,

FILE_SHARE_READ,

NULL,

CREATE_ALWAYS,

FILE_FLAG_DELETE_ON_CLOSE, // 句柄关闭时删除文件

NULL

);

CloseHandle(hFile); // 文件被立即删除

​最佳实践

​RAII 模式管理句柄

封装句柄在对象中,利用析构函数自动调用 CloseHandle。​示例:

class FileHandle {

public:

FileHandle(LPCTSTR filename) {

hFile = CreateFile(filename, GENERIC_READ, ...);

}

~FileHandle() {

if (hFile != INVALID_HANDLE_VALUE) {

CloseHandle(hFile);

}

}

private:

HANDLE hFile;

};

​避免全局或静态句柄

全局句柄可能因程序逻辑复杂导致漏关,优先使用局部变量。 ​调试技巧

使用 ​Visual Studio 调试器 监控 CloseHandle 调用。启用 ​Windows 内核调试 检查句柄泄漏(需专业工具)。

​与示例代码的关联

在用户提供的代码中,CloseHandle 的调用如下:

::CloseHandle(handle); // 关闭文件句柄,触发 FILE_FLAG_DELETE_ON_CLOSE 自动删除文件

​关键行为:

由于 CreateFile 指定了 FILE_FLAG_DELETE_ON_CLOSE,句柄关闭时文件被立即删除。若需保留文件,应移除该标志。

​总结

​核心功能: 释放内核对象资源,避免泄漏。​核心原则:

每个 CreateXXX 必须有对应的 CloseHandle。及时关闭不再使用的句柄。 ​高级场景:

通过 DuplicateHandle 共享句柄。结合 FILE_FLAG_DELETE_ON_CLOSE 实现临时文件自动清理。