文件系统监控工具开发指南

在当今信息时代,移动存储设备如U盘、移动硬盘等已成为数据传输的重要工具。然而,它们也可能导致敏感数据的意外泄露。因此,监控移动存储设备上的文件活动变得尤为重要,尤其是在那些拥有大量敏感数据的组织中。遗憾的是,在网上找不到太多相关的文献或应用程序。因此,决定开发一个简单的应用程序,允许用户监控移动存储设备上的文件活动。这个应用程序既适用于只想监控移动存储设备上文件活动的用户,也适用于程序员和开发者,他们可以在阅读本文后根据自己的需要修改程序(例如,使窗口不可见、在Windows启动时运行、远程监控等)。

应用程序的主要特点

在接下来的段落中,将描述应用程序的主要特点。

根据MSDN的描述,FileSystemWatcher "监听文件系统更改通知,并在目录或目录中的文件发生变化时引发事件"。将简要介绍FileSystemWatcher类的重要特性。

要监控的活动所在的路径。默认情况下包括子目录,但如果想更改它,可以将IncludeSubdirectories属性设置为false。

这指定了要监控的更改类型。对于这个应用程序,感兴趣的过滤器是LastAccess、LastWrite、FileName和DirectoryName。程序员可以添加或删除任何可用的过滤器。

每当触发与文件活动相关的事件时,都需要执行一些操作。这些操作包含在需要与相应属性注册的单独函数中。这些属性是Changed、Created、Renamed和Delete。这些引用需要以特殊的签名(称为委托)关联。如果不熟悉委托,只需知道需要以特殊格式(通常是发送者和函数本身)将函数与事件关联起来。当在下一部分查看实现时,这将变得更加清晰。

指定要监控的文件类型。默认情况下监控所有类型的文件。

当此属性为true时,启动FileSystemWatcher活动。

要查看此类的完整实现,请下载源代码。它基本上是一个包含26个FileSystemWatcher对象的数组,每个驱动器一个(0对应A,1对应B,...,25对应Z)。在构造函数中调用了initializeArray()函数。

在开始时,检查现有的可移动驱动器,并将值存储在名为drives的bool数组中。(0对应A,1对应B,...,25对应Z)。

bool * drives = DrivesFunctions::CheckExistingRemovableDrives();

DrivesFunctions类将在下一节简要介绍。接下来,它使用不同的值初始化数组中的所有对象,这取决于drives数组。这是通过每个FileSystemWatcher对象数组中的Path和EnableRaisingEvents属性完成的。

for(int i = 0; i < 26; i++) { watcherArray[i] = gcnew FileSystemWatcher(); if(drives[i]) { watcherArray[i]->Path = StringManipulations::AsciiToChar(i+65); watcherArray[i]->EnableRaisingEvents = true; } else { watcherArray[i]->Path = ""; watcherArray[i]->EnableRaisingEvents = false; } // for loop continues... watcherArray[i]->NotifyFilter = static_cast(NotifyFilters::LastAccess | NotifyFilters::LastWrite | NotifyFilters::FileName | NotifyFilters::DirectoryName); }

最后,为每种类型的事件注册函数。对于目的,没有包括Changed属性,因为这引入了冗余。然而,如果程序员希望激活它,可以通过遵循类似的方法来实现。

watcherArray[i]->Created += gcnew FileSystemEventHandler(this, &WatcherArray::onCreated); watcherArray[i]->Deleted += gcnew FileSystemEventHandler(this, &WatcherArray::onDeleted); watcherArray[i]->Renamed += gcnew RenamedEventHandler(this, &WatcherArray::onRenamed); }

onCreated、onDeleted和onRenamed是包含文件创建、删除和重命名时执行的实现的函数。在案例中,实现包括将信息写入日志文件。

这些函数接受要启动或停止FileSystemWatcher的驱动器字母作为参数。一旦设备连接到系统,覆盖的windows过程函数(稍后描述)在检测到驱动器字母并检查设备是否可移动后调用beginWatcherOnDrive。类似地,stopWatcherOnDrive在驱动器移除后停止FileSystemWatcher。这些操作再次通过Path和EnableRaisingEvents属性完成。

用静态函数解释这个类将需要另一篇文章。如果想知道它们是如何实现的,请阅读GetLogicalDrives()、GetVolumeInformation()和GetDriveType()。将简要讨论DrivesFunctions类的主要功能。

这返回一个26个bool数组,其中包含可移动驱动器存在的索引位置为true,其余为false。

这返回可移动设备连接或断开连接后所在的驱动器字母,或者在WndProc函数(稍后描述)接收到的掩码后评估。

在这个函数中,只是通过其驱动器字母返回设备的类型(可移动、固定等)。然而,可以从中提取更多信息(见上面的文章)。

硬件更改,如连接USB,通过一个名为WndProc的函数传达给所有顶级窗口。关于更改的信息(例如,在例子中是设备到达或移除、驱动器字母等)发送到这个函数中的Message对象。为了读取此消息中的信息,需要覆盖WndProc方法。这是在Form的函数声明区域完成的。

virtual void WndProc(System::Windows::Forms::Message %m) override { switch(m.Msg) { case WM_DEVICECHANGE: Main_OnDeviceChange(m.WParam, m.LParam); } Form::WndProc(m); }

Message类有几个属性,其中三个是感兴趣的。第一个是Msg,它是一个整数,告诉收到的消息类型。在这种情况下,它是WM_DEVICECHANGE。另外两个是WParam和LParam,它们包含有关设备更改的信息和有关驱动器的详细信息。要从LParam变量中提取有关驱动器的有用信息,需要执行两步类型转换。

PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lparam.ToPointer(); PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; char driveType[15] = "", driveName; switch(wparam.ToInt32()) { case DBT_DEVICEARRIVAL: driveName = DrivesFunctions::EvaluateMask(lpdbv->dbcv_unitmask); strcpy(driveType, ""); strcpy(driveType, DrivesFunctions::DetermineDriveType(driveName)); if(strcmp(driveType, "Removable") == 0) if(usbWatcher) usbWatcher->beginWatcherOnDrive(driveName); break; case DBT_DEVICEREMOVECOMPLETE: driveName = DrivesFunctions::EvaluateMask(lpdbv->dbcv_unitmask); // Drive letter determined, remove FileSystemWatcher if(usbWatcher) usbWatcher->stopWatcherOnDrive(driveName); break; default: break; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485