利用未公开函数实现Shell操作监视
在windows下有一个未公开函数shchangenotifyregister可以吧你的窗口添加到系统的系统消息监视链中,该函数在delphi中的定义如下:
function shchangenotifyregister(hwnd,uflags,dweventid,umsg,citems:longword;
lpps:pidlstruct):integer;stdcall;external shell32.dll index 2;
其中参数hwnd定义了监视系统操作的窗口得句柄,参数uflags dweventid定义监视操作参数,参数umsg定义操作消息,参数citems
定义附加参数,参数lpps指定一个pidlstruct结构,该结构指定监视的目录。
当函数调用成功之后,函数会返回一个监视操作句柄,同时系统就会将hwnd指定的窗口加入到操作监视链中,当有文件操作发生
时,系统会向hwnd发送umsg指定的消息,我们只要在程序中加入该消息的处理函数就可以实现对系统操作的监视了。
如果要退出程序监视,就要调用另外一个未公开得函数shchangenotifyderegister来取消程序监视。
下面是使用delphi编写的具体程序实现范例,首先建立一个新的工程文件,然后在form1中加入一个button控件和一个memo控件,
程序的代码如下:
unit unit1;
interface
uses
windows, messages, sysutils, classes, graphics, controls, forms, dialogs,
stdctrls,shlobj,activex;
const
shcne_renameitem = $1;
shcne_create = $2;
shcne_delete = $4;
shcne_mkdir = $8;
shcne_rmdir = $10;
shcne_mediainserted = $20;
shcne_mediaremoved = $40;
shcne_driveremoved = $80;
shcne_driveadd = $100;
shcne_netshare = $200;
shcne_netunshare = $400;
shcne_attributes = $800;
shcne_updatedir = $1000;
shcne_updateitem = $2000;
shcne_serverdisconnect = $4000;
shcne_updateimage = $8000;
shcne_driveaddgui = $10000;
shcne_renamefolder = $20000;
shcne_freespace = $40000;
shcne_assocchanged = $8000000;
shcne_diskevents = $2381f;
shcne_globalevents = $c0581e0;
shcne_allevents = $7fffffff;
shcne_interrupt = $80000000;
shcnf_idlist = 0; // lpitemidlist
shcnf_patha = $1; // path name
shcnf_printera = $2; // printer friendly name
shcnf_dword = $3; // dword
shcnf_pathw = $5; // path name
shcnf_printerw = $6; // printer friendly name
shcnf_type = $ff;
shcnf_flush = $1000;
shcnf_flushnowait = $2000;
shcnf_path = shcnf_pathw;
shcnf_printer = shcnf_printerw;
wm_shnotify = $401;
noerror = 0;
type
tform1 = class(tform)
button1: tbutton;
memo1: tmemo;
procedure formclose(sender: tobject; var action: tcloseaction);
procedure button1click(sender: tobject);
procedure formcreate(sender: tobject);
private
{ private declarations }
procedure wmshellreg(var message:tmessage);message wm_shnotify;
public
{ public declarations }
end;
type pshnotifystruct=^shnotifystruct;
shnotifystruct = record
dwitem1 : pitemidlist;
dwitem2 : pitemidlist;
end;
type pshfileinfobyte=^shfileinfobyte;
_shfileinfobyte = record
hicon :integer;
iicon :integer;
dwattributes : integer;
szdisplayname : array [0..259] of char;
sztypename : array [0..79] of char;
end;
shfileinfobyte=_shfileinfobyte;
type pidlstruct = ^idlstruct;
_idlstruct = record
pidl : pitemidlist;
bwatchsubfolders : integer;
end;
idlstruct =_idlstruct;
function shnotify_register(hwnd : integer) : bool;
function shnotify_unregister:bool;
function sheventname(strpath1,strpath2:string;lparam:integer):string;
function shchangenotifyderegister(hnotify:integer):integer;stdcall;
external shell32.dll index 4;
function shchangenotifyregister(hwnd,uflags,dweventid,umsg,citems:longword;
lpps:pidlstruct):integer;stdcall;external shell32.dll index 2;
function shgetfileinfopidl(pidl : pitemidlist;
dwfileattributes : integer;
psfib : pshfileinfobyte;
cbfileinfo : integer;
uflags : integer):integer;stdcall;
external shell32.dll name shgetfileinfoa;
var
form1: tform1;
m_hshnotify:integer;
m_pidldesktop : pitemidlist;
implementation
{$r *.dfm}
function sheventname(strpath1,strpath2:string;lparam:integer):string;
var
sevent:string;
begin
case lparam of file://根据参数设置提示消息
shcne_renameitem: sevent := 重命名文件+strpath1+为+strpath2;
shcne_create: sevent := 建立文件 文件名:+strpath1;
shcne_delete: sevent := 删除文件 文件名:+strpath1;
shcne_mkdir: sevent := 新建目录 目录名:+strpath1;
shcne_rmdir: sevent := 删除目录 目录名:+strpath1;
shcne_mediainserted: sevent := strpath1+中插入可移动存储介质;
shcne_mediaremoved: sevent := strpath1+中移去可移动存储介质+strpath1+ +strpath2;
shcne_driveremoved: sevent := 移去驱动器+strpath1;
shcne_driveadd: sevent := 添加驱动器+strpath1;
shcne_netshare: sevent := 改变目录+strpath1+的共享属性;
shcne_attributes: sevent := 改变文件目录属性 文件名+strpath1;
shcne_updatedir: sevent := 更新目录+strpath1;
shcne_updateitem: sevent := 更新文件 文件名:+strpath1;
shcne_serverdisconnect: sevent := 断开与服务器的连接+strpath1+ +strpath2;
shcne_updateimage: sevent := shcne_updateimage;
shcne_driveaddgui: sevent := shcne_driveaddgui;
shcne_renamefolder: sevent := 重命名文件夹+strpath1+为+strpath2;
shcne_freespace: sevent := 磁盘空间大小改变;
shcne_assocchanged: sevent := 改变文件关联;
else
sevent:=未知操作+inttostr(lparam);
end;
result:=sevent;
end;
function shnotify_register(hwnd : integer) : bool;
var
ps:pidlstruct;
begin
{$r-}
result:=false;
if m_hshnotify = 0 then begin
file://获取桌面文件夹的pidl
if shgetspecialfolderlocation(0, csidl_desktop,
m_pidldesktop)<> noerror then
form1.close;
if boolean(m_pidldesktop) then begin
ps.bwatchsubfolders := 1;
ps.pidl := m_pidldesktop;
// 利用shchangenotifyregister函数注册系统消息处理
m_hshnotify := shchangenotifyregister(hwnd, (shcnf_type or shcnf_idlist),
(shcne_allevents or shcne_interrupt),
wm_shnotify, 1, ps);
result := boolean(m_hshnotify);
end
else
// 如果出现错误就使用 cotaskmemfree函数来释放句柄
cotaskmemfree(m_pidldesktop);
end;
{$r+}
end;
function shnotify_unregister:bool;
begin
result:=false;
if boolean(m_hshnotify) then
file://取消系统消息监视,同时释放桌面的pidl
if boolean(shchangenotifyderegister(m_hshnotify)) then begin
{$r-}
m_hshnotify := 0;
cotaskmemfree(m_pidldesktop);
result := true;
{$r-}
end;
end;
procedure tform1.wmshellreg(var message:tmessage); file://系统消息处理函数
var
strpath1,strpath2:string;
charpath:array[0..259]of char;
pidlitem:pshnotifystruct;
begin
pidlitem:=pshnotifystruct(message.wparam);
file://获得系统消息相关得路径
shgetpathfromidlist(pidlitem.dwitem1,charpath);
strpath1:=charpath;
shgetpathfromidlist(pidlitem.dwitem2,charpath);
strpath2:=charpath;
memo1.lines.add(sheventname(strpath1,strpath2,message.lparam)+chr(13)+chr(10));
end;
procedure tform1.formclose(sender: tobject; var action: tcloseaction);
begin
file://在程序退出的同时删除监视
if boolean(m_pidldesktop) then
shnotify_unregister;
end;
procedure tform1.button1click(sender: tobject); file://button1的click消息
begin
m_hshnotify:=0;
if shnotify_register(form1.handle) then begin file://注册shell监视
showmessage(shell监视程序成功注册);
button1.enabled := false;
end
else
showmessage(shell监视程序注册失败);
end;
procedure tform1.formcreate(sender: tobject);
begin
button1.caption := 打开监视;
end;
end.
运行程序,点击“打开监视”按钮,如果出现一个显示“shell监视程序成功注册”的对话框,说明form1已经加入到系统操作监视链中了,
你可以试着在资源管理器中建立、删除文件夹,移动文件等操作,你可以发现这些操作都被纪录下来并显示在文本框中。
在上面的程序中多次使用到了一个pitemidlist的结构,这个数据结构指定windows下得一个“项目”,在windows下资源实现统一管理
一个“项目”可以是一个文件或者一个文件夹,也可以是一个打印机等资源。另外一些api函数也涉及到了shell(windows外壳)操作,各位
读者可以参考相应的参考资料。
- · 利用Delphi消息处理建立类似Windows开始菜单
- · Delphi中的图形显示技巧
- · Form产生时的事件次序;
- · Delphi中布尔类型辨析
- · AccesS密码的打击
- · Delphi嵌入式汇编一例
- · 在Delphi中实现任意形状的窗体
- · sql server 2005中的DDL触发器
- · asp.net 2.0下嵌套masterpage页的可视化编辑
- · PHP程序加速探索之缓存输出
- · 用C#代码编写的SN快速输入工具
- · (PHP)模板引擎Smarty介绍
- · 用PHP操纵Oracle的LOB类型的数据
- · C# 2.0中泛型编程初级入门教程
- · asp.net 2.0中加密web.config
- · ADO.NET操纵数据库
- · 关于asp.net c#中对cookie的操作
- · asp.net 2.0里当readonly遇上enableviewstate=false
- · C# 2.0与泛型
- · 让3721也无奈的弹出窗口(代码)
- · 玩透9种网页弹出窗口(精)
- · 网站左右两边浮动广告JS代码
- · 一个IP只提示一次设为首页的代码
- · 常用ASP脚本程序集锦*精(适合初学者)
- · 鼠标自动移动/点击
- · PHP程序加速探索之加速工具软件
- · SQLServer2000数据访问基类
- · 图解MySQL数据库的安装和操作
- · 一些ASP初学者常用的代码
- · ASP经典问答收藏之一
- · 一段防注入的通用脚本
- · 简单的防盗链(代码)
- · PHP窜红:革命尚未成功 Java仍需努力
- · 使用PHP编写基于Web的文件管理系统
- · 理解PHP中的MVC编程之控制器
- · 理解PHP中的MVC编程之MVC框架简介
- · SQL Server Express 数据库自动部署问题及解决
- · 用PHP文件上传的具体思路及实现
- · 回顾与展望PHP 5.0的变化与PHP 6.0展望
- · 一个产生中文累计数的代码片断
- · 在SQL Server 2005中解决死锁
- · 30分钟正则表达式指导
- · 不算不知道 44% 数据库开发者使用MySQL
- · 立即释放.net下的com组件
- · XHTML的目标,规则和细节
- · SQL Server 2005 提供的分页查询支持
- · ASP.NET程序中常用的三十三种代码
- · Sql server存储过程和C#分页类简化你的代码
- · SQL Server 2005新功能-TSQL
- · 在SQL Server 2005中编辑SQL Server 2000 DTS
- · .NET 连接到 Oracle的oci.dll加载错误解决方案
- · 如何在调用线程的时候传递参数
- · 专家预言:PHP将比Java更好更受欢迎
- · 在IIS6.0下ASP .NET 的版本冲突问题
- · 解决SqlTransaction用尽的问题(SQL处理超时)
- · 以前编写Like谓词被忽略的使用方法
- · 在编写存储过程时使用 Set NoCount On
- · ASP.NET 2.0运行时简要分析
- · .Net中如何操作IIS(原理篇)
- · 用.net开发不同操作系统下应用的winform的size大小问题

