【源码下载地址】:http://210.33.90.250/download/vbsrc/vbcopyhook.rarShell有很多很多的接口,不过由于种种原因,在VB里面实现起来不是那么的简单,弄的人少了,这方面的资料也自然不是很多……最可气的是,国内竟然找不到那本可以说具有指导意义的Visual Basic Shell Programming卖……前几个星期突然想到是否做个windows外壳的系列,一方面提高自己的COM水平,另一方面也充实一下这互联网的资料库,呵呵 ^_^第1集是ICopyHook接口。ICopyHook是在系统进行文件夹和打印机操作前回调的一个具有确认效果的接口。举例来说,文件夹改名、复制、删除的时候系统就会调用这个接口。关于这个接口的其他语言的实现网上已经有很多了,而VB的却很少见,因此,关于这个接口的意义及用法,我这里就不多说了,主要谈谈我在VB中实现这个接口时的碰到的一些问题。问题1、ICopyHook的声明
这个问题是没有什么小道道好走了,只能老老实实的做个idl文件,然后编译成类型库问题2、CopyCallBack方法的返回值问题
CopyCallBack应该返回IDYES,IDNO或者IDCANCEL(分别对应VB中的vbYes,vbNo和vbCancel),而在VB中,COM的方法只能返回HRESULT,否则就拜拜了。解决的办法是,函数地址替换。用自己函数的地址替换掉ICopyHook接口VTable中的CopyCallBack方法的地址。
这个工作又碰到另外一个问题,那就是如何得到ICopyHook接口的对象指针。我们知道用ObjPtr(Me)可以得到当前类的对象指针,当我们执行下面的语句时,好玩的事情就发生了:Dim oICopyHookA As ICopyHookA
Set oICopyHookA = Me这里的这个Set语句就相当于在当前的类上调用了QueryInterface(IID_ICopyHookA,....),于是乎,很轻松得,我们得到了想要的东西。接下去只要把自己的函数地址写到该写的地方就OK了。问题3、多线程问题
当我解决了上面两个问题后就改了文件夹个名字来验证效果,呵呵,挺好,没有什么问题。但是,当我复制、删除文件夹的时候,Explorer刷刷得就拜拜了。后来,经过一翻跟踪分析,结果发现原来问题出在多线程上。当windows进行文件夹操作的时候会使用多线程,而在每次ExitThread的时候vb运行库就会开始回收对象,因此,在第2次调用的时候,原先的地址就变成了不可访问,最终也就连累了Explorer。思考良久,然后又分析了shell32.dll,终于看到了一丝的曙光。在呼叫CopyHook对象之前,系统会生成一个包含所有CopyHook对象的链表。每次在执行前会通过判断这个链表首地址是否有效来决定是否生成对象及链表。所以,如果在调用完毕之后把链表给喀嚓掉,那么系统就会重新生成一个有效的对象及链表。呵呵,虽然这么做不是十分理想,但的确能解决这个不大不小的问题。基本问题就是上面那么多,还有很多其他的乱七八糟的问题,以后再讲,呵呵我提供的例子的用法是:
1、注册dll
2、双击 .reg文件,导入注册表。这个注册表文件里只包含了和文件夹相关的入口,如果要钩到打印机,可以添加下面这段
[HKEY_CLASSES_ROOT\Printers\Shellex\CopyHookHandlers\CopyMonitor]
@="{4F07BFB0-B9FC-4BF7-BA17-0343C27C8A9E}"
奶奶的,上一帖显示不出来,只好再来一帖……

解决方案 »

  1.   

    http://www.mvps.org/emorcillo/vb6/index.shtml在这个站点里面对这些有比较详细的介绍喝范例。
      

  2.   

    幸好那上面没有ICopyHook的,否则就丢脸丢大了,呵呵~~~
      

  3.   

    一个小问题:为什么不用VB中的Long对应HRESULT来实现接口?另:你是怎么调到shell32中的联表的?能否介绍一下经验?在下实在佩服的五体投地!
      

  4.   

    问题不在于类型,HRESULT的确也是个4字节的类型,但问题是,在每次调用完对象方法后vb会自动检查HRESULT是否为S_OK(也就是0),否则就会蹦出讨厌的错误提示框~对象什么方法失败~。至于那个链表,呵呵,用SoftIce+IDA Pro分析了XP和2000的Shell32.dll之后发现的。XP和2000在调用ICopyHook上还是有一点点不一样的。
      

  5.   

    在对链表的处理上,我其实是有点偷懒的。我只是将链表第1个节点置0,而没有调用释放对象的代码,呵呵,其实就是在附近的,看太多汇编头疼,所以实在懒得弄了。通过跟踪分析发现,不管是xp还是2000,在调用钩子时都会把链表首地址存放在[edi]中,所以我用个了push,就能在vb里面对其做手脚了
      

  6.   

    好复杂哦,做梦也想不到这么复杂……
    看来当初C++决定抛弃垃圾回收是比较明智的咯~学习学习学习,至少softICE阿IDA阿连见都没见过了也~
      

  7.   

    呵呵~~pig上面的时间出卖了自己。