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) {
|