Service如何利用RegisterDeviceNotification监控Volume的装载和卸载 .
来源:互联网 发布:如何修复缺少网络协议 编辑:程序博客网 时间:2024/06/05 20:51
windows提供了以下api来向系统注册一个函数,当有volume增删(比如U盘插拔、新建分区)的时候,通知应用程序:
HDEVNOTIFY WINAPI RegisterDeviceNotification(
__in HANDLE hRecipient,// 可以是窗口句柄或者服务句柄
__in LPVOID NotificationFilter,
__in DWORD Flags // 制定hRecipient是窗口句柄,还是服务句柄
);
如果采用窗口句柄,根据msdn的文档,注册之后,系统会在volume增删的时候,向注册的窗口发送WM_DEVICECHANGE消息,只需要在窗口的消息循环中处理该消息就可以判断出U盘中的卷:
case WM_DEVICECHANGE:
if(wParam == DBT_DEVICEARRIVAL) //设备激活
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
// 下面可以进一步找到装载的卷名,如E:/
}
}
else if(wParam == DBT_DEVICEREMOVECOMPLETE)
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
// 下面可以进一步找到卸载卷名,如E:/
}
}
上面的代码经过验证是可行的。
但是窗口程序需要user登陆系统后才能执行,所以一般还是应该采用service来实现监控。但是如果采用在调用RegisterDeviceNotification的时候传入服务句柄,应该采取不同的处理方式,这点似乎与文档不一致。见下面代码的描述:
case SERVICE_CONTROL_DEVICEEVENT:
if(dwEventType == DBT_DEVICEARRIVAL)
{
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lpEventData;
switch(pHdr -> dbch_devicetype)
{
case DBT_DEVTYP_VOLUME:
{
// 本来应该在这里提取卷名称,但是实际上代码永远不会运行到这里
break;
}
case DBT_DEVTYP_DEVICEINTERFACE:
{
// 卷加载的时候,代码总是运行到这里
// pS->dbcc_name是形如这样的字符串://?/STORAGE#Volume#1&30a96598&0&Signature5C2864E7Offset4000Length67FC000#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
PDEV_BROADCAST_DEVICEINTERFACE pS = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
WriteLog(std::wstring(pS->dbcc_name));
// 处理代码
}
}
return NO_ERROR;
break;
}
}
研究了半天,最终还是在pS->dbcc_name上找到了突破口。
一个卷设备(比如E盘)在windows内核中是一个volume对象,对象名是/Device/HardDiskVolumeN,N为序号。但是用户态程序是不能直接通过/Device/HardDiskVolumeN对象名来打开volume对象的,必须通过三个SymbolLink来打开:
SymbolLink1形如//?/E:
SymbolLink2形如//?/Volume{GUID}
SymbolLink3形如//?/STORAGE#Volume#1&30a96598&0&Signature5C2864E7Offset4000Length67FC000#{GUID}
呵呵,发现了吧,pS->dbcc_name就是这里的SymbolLink3。
因此可以在UserMode的代码中用CreateFile打开pS->dbcc_name,获得一个Handle;
然后写一个driver,在driver的IOControl中,通过一个Handle查询对象的名字,也即是/Device/HardDiskVolumeN的字符串;
然后UserMode的代码通过DeviceIOControl调用Driver,调用的输入参数就是前面打开的Handle,这样就可以在UserMode中得到卷的名字了。
driver的通过Handle查询ObjectName的简化代码如下:
ObReferenceObjectByHandle(handle, 0, NULL, KernelMode, &pObj1, NULL)
unsigned char nameInfo1[ 512 ];
OBJECT_NAME_INFORMATION * pNameInfo1 = (OBJECT_NAME_INFORMATION *) (nameInfo1);
ULONG length;
NTSTATUS status = ObQueryNameString(pObj1, pNameInfo1, sizeof(nameInfo1) - sizeof(OBJECT_NAME_INFORMATION), &length);
ObDereferenceObject(pObj1);
很绕吧,可惜目前只找到了这个九曲十八弯的方法。
PS:
UserMode下的APPI函数GetVolumePathNamesForVolumeNameW是用不上的,它只能把SymbolLink2的字符串转换成盘符;如果传入SymbolLink3的字符串返回失败。最终在纯用户态下把SymbolLink3转换成volume的名字以失败告终 @@
- Service如何利用RegisterDeviceNotification监控Volume的装载和卸载
- Service如何利用RegisterDeviceNotification监控Volume的装载和卸载
- Service如何利用RegisterDeviceNotification监控Volume的装载和卸载 .
- Service如何利用RegisterDeviceNotification监控Volume的装载和卸载
- Com 组件的装载和卸载
- Com 组件的装载和卸载 .
- Com 组件的装载和卸载
- Com 组件的装载和卸载
- 关于sdcard卸载和装载的广播
- 利用RegisterDeviceNotification监视usb设备
- linux内核编程一:模块的装载和卸载
- Greenplum中装载和卸载数据
- Windows Service的安装卸载 和 Service控制
- 利用拦截器监控service的调用情况
- 动态库的装载与卸载
- 如何卸载服务(Service)?
- 如何卸载服务(Service)?
- Volume Shadow Copy Service(VSS)如何工作
- 局部单例模式以及C++实现
- 【KMP】 hdu2594 Simpsons’ Hidden Talents
- unity3d开发之二:开发环境的搭建及c#注意事项
- MyEclipse 快捷键
- javaEE之路
- Service如何利用RegisterDeviceNotification监控Volume的装载和卸载 .
- 个人总结NDIS中NDIS_PACKET,NDIS_BUFFER的关系
- 北大ACM poj1016
- 操作系统引导Boot的初步实现
- 一个男人关心的东西决定了他的层次
- windows 蓝屏 DMP文件分析
- pjsip2.0在vs2008配置下的问题
- Silverlight 加载JSON文件 以及反序列化
- java2 实用教程 第三版 第三章 习题 2