### 非内核实现文件监视 #### 一、引言 在计算机程序设计领域,尤其是在Windows平台上,监视文件及目录的变化是一项常见的需求。对于那些希望避免使用内核级技术(如文件系统过滤驱动程序)的开发者来说,利用应用程序级别的方法来实现文件监视功能尤为重要。本文将详细介绍一种通过未公开API——`SHChangeNotifyRegister`与`SHChangeNotifyDeregister`——实现文件监视的技术。 #### 二、非内核方式监视文件改动方法概述 在Windows操作系统中,存在多种监视文件变动的方法,但本篇重点介绍的是通过未公开API的方式实现。这种方法不需要编写内核级代码,因此降低了开发难度和潜在风险,同时也提高了程序的稳定性和安全性。接下来将详细介绍这一方法的原理、步骤以及具体的应用示例。 #### 三、通过`SHChangeNotifyRegister`实现文件监视 ##### 1. 原理 Windows内部提供了两个未公开的函数`SHChangeNotifyRegister`和`SHChangeNotifyDeregister`,用于实现文件或目录变化的通知功能。这两个函数位于`Shell32.dll`库中,通过序号方式导出。尽管这两个函数最初并未在官方文档中提及,但随着Windows版本的更新,它们已经被公开。通过使用这两个函数,可以将指定窗口加入到系统消息监视链中,从而接收到来自文件系统或Shell的通知消息。 ##### 2. 函数原型及参数 `SHChangeNotifyRegister`的原型如下: ```cpp ULONG SHChangeNotifyRegister( HWND hwnd, // 接收通知消息的窗口句柄 int fSources, // 指定事件源类型 LONG fEvents, // 要捕获的事件类型 UINT wMsg, // 发送给窗口的消息标识符 Int cEntries, // SHChangeNotifyEntry数组的元素数量 SHChangeNotifyEntry* pfsne // 指向SHChangeNotifyEntry结构体数组的指针 ); ``` ##### 3. 参数详解 - `hwnd`: 接收改变或通知消息的窗口句柄。 - `fSources`: 指示接收消息的事件源类型,支持以下标志: - `SHCNRF_InterruptLevel`: 接收来自文件系统的中断级别通知消息。 - `SHCNRF_ShellLevel`: 接收来自Shell的Shell级别通知消息。 - `SHCNRF_RecursiveInterrupt`: 接收目录及其所有子目录的中断事件。此标志必须与`SHCNRF_InterruptLevel`一起使用,并且`SHChangeNotifyEntry`结构体中的`fRecursive`成员需设为`TRUE`。 - `SHCNRF_NewDelivery`: 使用共享内存接收消息。必须先调用`SHChangeNotification_Lock`锁定内存,再访问数据,最后调用`SHChangeNotification_Unlock`释放内存。 - `fEvents`: 捕获的具体事件类型,详情参阅MSDN文档。 - `wMsg`: 产生对应事件后,发往窗口的消息标识符。 - `cEntries`: 指向的`SHChangeNotifyEntry`数组的元素数量。 - `pfsne`: 指向`SHChangeNotifyEntry`结构体数组的指针。 ##### 4. 实现步骤 1. **声明函数原型**:在项目中声明`SHChangeNotifyRegister`和`SHChangeNotifyDeregister`的函数原型,并添加必要的宏和结构定义。 2. **初始化窗口句柄**:创建一个窗口作为接收通知消息的目标。 3. **调用`SHChangeNotifyRegister`**:根据需求设置参数并调用该函数。 4. **消息处理**:编写窗口过程函数处理由`wMsg`指定的消息。 5. **取消监视**:当不再需要监视时,调用`SHChangeNotifyDeregister`取消监视。 ##### 5. 示例代码 以下是一个简化的示例代码片段,展示如何使用`SHChangeNotifyRegister`进行文件监视: ```cpp // 声明未公开API函数 extern "C" { typedef ULONG (WINAPI *PFN_SHChangeNotifyRegister)( HWND hwnd, int fSources, LONG fEvents, UINT wMsg, Int cEntries, SHChangeNotifyEntry* pfsne ); } // 定义SHChangeNotifyEntry结构体 typedef struct _SHChangeNotifyEntry { PCWSTR pszPath; BOOL fRecursive; } SHChangeNotifyEntry; // 初始化 HWND hWnd = CreateWindowEx(...); // 创建窗口 PFN_SHChangeNotifyRegister pfnSHChangeNotifyRegister = (PFN_SHChangeNotifyRegister)GetProcAddress(GetModuleHandle(L"Shell32.dll"), "SHChangeNotifyRegister"); // 注册监视 SHChangeNotifyEntry entry = { L"C:\\", TRUE }; ULONG ulID = pfnSHChangeNotifyRegister(hWnd, SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt, SHCNE_FILECREATE | SHCNE_FILEDELETE, WM_USER + 1, 1, &entry); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 取消监视 typedef BOOL (WINAPI *PFN_SHChangeNotifyDeregister)(ULONG ulID); PFN_SHChangeNotifyDeregister pfnSHChangeNotifyDeregister = (PFN_SHChangeNotifyDeregister)GetProcAddress(GetModuleHandle(L"Shell32.dll"), "SHChangeNotifyDeregister"); pfnSHChangeNotifyDeregister(ulID); ``` #### 四、总结 通过上述介绍可以看出,利用`SHChangeNotifyRegister`和`SHChangeNotifyDeregister`这两个未公开API可以在不依赖于内核级技术的情况下实现文件或目录的变化监视。这种方法不仅降低了开发复杂度,而且提供了更高的灵活性和安全性。对于希望在VC++环境下实现文件监视功能的开发者而言,这是一种非常实用且值得考虑的选择。
- 粉丝: 1
- 资源: 1
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助