用拷贝钩子实现对文件夹的监控

ICopyHook是一个用于创建拷贝钩子处理程序COM接口,它决定一个文件夹或者打印机对象是否可以被移动,拷贝,重命名或删除。Shell在执行这些操作之前,会调用ICopyHook接口的CopyCallback方法对它们进行验证。CopyCallback返回一个int值指示Shell是否应该继续执行这个操作。返回值IDYES表示继续,而返回值IDNO和IDCANCEL则表示终止。

一个文件夹对象可以安装多个拷贝钩子处理程序。如果出现这种情况,Shell会依次调用每个处理程序。只有当每个处理程序都返回IDYES时,Shell才真正执行用户请求的操作。

拷贝钩子处理程序的作用是在上述四种操作执行前对它们进行验证,但是Shell并不会把操作的结果通知给拷贝钩子处理程序。而windows提供的API函数FindFirstChangeNotification和FindNextChangeNotification却可以实现这个功能。因此,只有把这种两种方法结合起来,才能对一个文件夹的状态进行完全的监控。

拷贝钩子处理程序实现并不困难,首先创建一个作为进程内组件的COM对象,它只需要暴露一个ICopyHook接口(当然还有IUnknown)。然后用regsrv32.exe注册这个COM组件。最后一步是向Shell注册你的这个拷贝钩子处理程序,方法是在注册表HKEY_CLASSES_ROOT\Directory\Shellex\CopyHookHandlers下创建一个名称任意的sub key,在此sub key中创建一个类型为REG_SZ的项并将你的COM对象的CLSID作为它的默认值就可以了。

下面就是一个拷贝钩子的实现程序(注:以下代码经老妖改动并添加了详细操作过程,在BCB6中成功编译并通过测试)

1. 从ICopyHook接口创建TCopyHook,从IClassFactory接口创建TClassFactory:

// TCopyHook.h
// TCopyHook类实现了ICopyHook接口,TClassFactory实现了IClassFactory接口
//---------------------------------------------------------------------------
#define NO_WIN32_LEAN_AND_MEAN
#include <shlobj.h>
//---------------------------------------------------------------------------
class TCopyHook: public ICopyHook
{
public:
   TCopyHook():m_refcnt(0) {}
   STDMETHODIMP QueryInterface(REFIID iid,void **ppvObject);
   STDMETHODIMP_(ULONG) AddRef();
   STDMETHODIMP_(ULONG) Release();
   STDMETHODIMP_(UINT) CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags,
       LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
       LPCTSTR pszDestFile, DWORD dwDestAttribs);
private:
   int m_refcnt;
};
//---------------------------------------------------------------------------
class TClassFactory : public IClassFactory
{
public:
   TClassFactory():m_refcnt(0) {}
   STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject);
   STDMETHODIMP_(ULONG) AddRef();
   STDMETHODIMP_(ULONG) Release();
   STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
   STDMETHODIMP LockServer(BOOL fLock);
private:
   int m_refcnt;
};
// TCopyHook.cpp
// TCopyHook对象和TClassFactory对象的实现文件
#include <stdio.h>
#include "TCopyHook.h"
//---------------------------------------------------------------------------
extern LONG nLocks;     // 对象计数,用于DllCanUnloadNow
ULONG __stdcall TCopyHook::AddRef()
{
   if(m_refcnt == 0)
     nLocks++;
   m_refcnt++;
   return m_refcnt;
}
//---------------------------------------------------------------------------
ULONG __stdcall TCopyHook::Release()
{
   int nNewCnt = --m_refcnt;
   if(nNewCnt <= 0)
   {
     nLocks--;
     delete this;
   }
   return nNewCnt;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TCopyHook::QueryInterface(REFIID dwIID, void **ppvObject)
{
   if(dwIID == IID_IUnknown)
     *ppvObject = static_cast<IUnknown*>(this);
   else
     if(dwIID == IID_IShellCopyHook)
       *ppvObject = static_cast<ICopyHook*>(this);
     else
       return E_NOINTERFACE;
   reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
   return S_OK;
}
//---------------------------------------------------------------------------
// 这就是CopyCallback方法,拷贝钩子的所有功能由它实现。参数的具体值参看MSDN
UINT __stdcall TCopyHook::CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags,
     LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
     LPCTSTR pszDestFile, DWORD dwDestAttribs)
{
   char szMessage[MAX_PATH+14];
   sprintf(szMessage, "对%s进行的操作,是否继续?", pszSrcFile);
   return MessageBox(NULL, szMessage, "确认", MB_YESNO | MB_ICONEXCLAMATION);
}
//---------------------------------------------------------------------------
ULONG __stdcall TClassFactory::AddRef()
{
   if(m_refcnt==0)
     nLocks++;
   m_refcnt++;
   return m_refcnt;
}
//---------------------------------------------------------------------------
ULONG __stdcall TClassFactory::Release()
{
   int nNewCnt = --m_refcnt;
   if(nNewCnt <= 0)
   {
     nLocks--;
     delete this;
   }
   return nNewCnt;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TClassFactory::QueryInterface(REFIID dwIID, void **ppvObject)
{
   if(dwIID == IID_IUnknown)
     *ppvObject = static_cast<IUnknown*>(this);
   else
     if(dwIID == IID_IClassFactory)
       *ppvObject = static_cast<IClassFactory*>(this);
     else
       return E_NOINTERFACE;
   reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
   return S_OK;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TClassFactory::CreateInstance(IUnknown* pUnkownOuter,
     REFIID riid, void** ppvObj)
{
   if(pUnkownOuter != NULL)
     return CLASS_E_NOAGGREGATION;
   TCopyHook *pObj = new TCopyHook;
   pObj->AddRef();
   HRESULT hr = pObj->QueryInterface(riid, ppvObj);
   pObj->Release();
   return hr;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TClassFactory::LockServer(BOOL fLock)
{
   if(fLock)
     nLocks++;
   else
     nLocks--;
   return S_OK;
}

时间: 2024-11-01 11:04:43

用拷贝钩子实现对文件夹的监控的相关文章

(WinForm)文件夹状态监控,最小化到托盘,开机自启动

原文 (WinForm)文件夹状态监控,最小化到托盘,开机自启动 1. 文件夾監控(監測文件夾中的文件動態): //MSDN上的例子 public class Watcher { public static void Main() { Run(); } [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] public static void Run() { string[] args = System.Environme

Asp.Net 文件操作基类(读取,删除,批量拷贝,删除,写入,获取文件夹大小,文件属性,遍历目录)_实用技巧

复制代码 代码如下: using System; using System.IO; using System.Text; using System.Data; using System.Web.UI; using System.Web.UI.WebControls; namespace ec { /// <summary> /// 文件操作类 /// </summary> public class FileObj : IDisposable { private bool _alre

拷贝-同一个文件夹里有多个图片要复制到另一个文件夹,要怎么做

问题描述 同一个文件夹里有多个图片要复制到另一个文件夹,要怎么做 首先我要能让系统得到每一张图片的名字,这样就可以用file.copy(源图片,目标图片,ture)将图片拷贝到另一个文件夹了,但问题是这样操作一张图片很简单,但是文件夹里有很多图片,我怎么得到每一张图片的名字并能分离开每一个图片名称?不知道描述的意思大神能懂吗 望助 解决方案 直接传入两个目录名,就可以. public void CopyDirectory( string sourceDirName, string destDir

巧妙解决删除文件或文件夹出错故障

半年前,朋友的一台电脑突然发生"删除文件或文件夹出错"故障,报错信息为:"无法删除xxx文档/文件夹:找不到指定的路径.请确定指定的路径是否正确".(如图一)当时在网上搜索了一下看是否有网友遇到类似的问题.搜索结果发现,多数这类错误是由于文件或者磁盘设成了只读.文件已经被删除图标还没有更新.或者文件被破坏甚至感染病毒造成的,这些问题均可以通过去掉文件只读属性.修复文件.DOS下删除文件或者用杀毒软件清除或者粉碎文件来解决. 图一 然而这台电脑所遇到的故障却让上述任何

android怎么从服务器的一个存放图片的文件夹中下载其中所有的图片,已知文件夹的url

问题描述 android怎么从服务器的一个存放图片的文件夹中下载其中所有的图片,已知文件夹的url android怎么从服务器的一个存放图片的文件夹中下载其中所有的图片,已知文件夹的url 解决方案 只要这个url和图片信息(比如名字)能组成有效的url就行了,然后再返回一个图片的名字列表,遍历下载就行了 解决方案二: QT下实现将图片从一个文件拷贝到另一个文件夹把存储在数据库的图片导入到一个文件夹 解决方案三: 考慮安裝一下 ""抓圖神器"" 這個APP應該就可以

Qt 复制文件夹下的所有文件及文件夹

问题描述 Qt 复制文件夹下的所有文件及文件夹 我想那某个文件夹下的所有文件和文件夹都拷贝到另一个文件夹下,在windows下应该怎样实现啊,给点关键思路就行,网上有好多都只是单独拷贝的文件夹,里面的文件没有一起拷贝过去,所以不太合用

文件夹看门狗v2.5免注册美化绿色版 下载_常用工具

[文件夹看门狗v2.5]适于安装Windows系统的计算机中◇本机硬盘◇和◇移动存储器◇中文件夹加密.操作简便,将软件拷贝到待加密文件夹中,输入密码点击"加密"按钮,就OK啦!为绿色免注册美化版! 无需原版  下载地址

监控一个文件夹,如果有图片创建,就读取文件流

问题描述 本人用的FileSystemWatcher,但是文件创建的时候读取只能读取到一部分,貌似文件还没有创建完成就读取了,请教各位大神有解决方法吗?谢谢!高分悬赏 解决方案 解决方案二:绑定元以下!解决方案三:延迟一定的时间后再读取解决方案四:///<summary>///当文件夹内监控内容发生变化时///</summary>///<paramname="sender"></param>///<paramname="e

DotNetCore跨平台~Quartz热部署的福音~监控文件夹的变化

在DotNetCore出来之后,同时也使用了quartz进行调度中心的设计,将它做到docker里方便部署,在之前的quartz版本里支持配置文件的方式,而现在不支持了,我们应该去想一下,为什么不去支持配置文件?当然大叔也为配置文件设计了支持的方式,但我们还是应该想想作者为什么不去支持配置? 热插拔,服务发现? 和上面两个概念可能有点关系,热插拔很容易理解,就是把dll模块放到正在运行的项目时,它可以直接启动,这个功能对调度中心来说,很是必要,因为你可能需要按着不同的功能设计一些服务job,而这