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

本文原出处已不知。原作:webber84, 经ccrun(老妖)修改并在BCB在调试通过。
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_ROOTDirectoryShellexCopyHookHandlers 下创建一个名称任意的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 文章

Read: 732

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注