用拷贝钩子实现对文件夹的监控
当前位置:以往代写 > C/C++ 教程 >用拷贝钩子实现对文件夹的监控
2019-06-13

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

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

副标题#e#

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;
}


#p#副标题#e#

2. 在BCB中New–>ActiveX–>ActiveX Library,然后添加相应代码。

以下是修改后的Project1.cpp,各人可以直接copy已往。:

#p#分页标题#e#

//$$---- axlib proj source ---- (stAXLibProjectSource)
#define NO_WIN32_LEAN_AND_MEAN
#include <vcl.h>
#pragma hdrstop
#include <atl\atlvcl.h>
#include <objbase.h>
#include <olectl.h>
#include "TCopyHook.h"
#pragma package(smart_init)
TComModule Project1Module;
TComModule &_Module = Project1Module;
// 这是要添加到注册表中的项,留意假如你要利用这段代码,应该用UUIDGEN.exe生成一
// 个新的CLSID。
const char* szRegTable[][3]=
{
   {"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}", 0, "CopyHook"},
   {"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}\\InProcServer32", 0, (const char*)-1},
   {"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}\\InProcServer32", "ThreadingModel", "Apartment"},
   {"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}\\ProgID", 0, "webber84.CopyHook.1"},
   {"webber84.CopyHook.1", 0, "CopyHook"},
   {"webber84.CopyHook.1\\CLSID", 0, "{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}"}
};
HMODULE hInstance = NULL;
LONG nLocks = 0;
//---------------------------------------------------------------------------
// The ATL Object map holds an array of _ATL_OBJMAP_ENTRY structures that
// described the objects of your OLE server. The MAP is handed to your
// project's CComModule-derived _Module object via the Init method.
BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()
//---------------------------------------------------------------------------
// Entry point of your Server invoked by Windows for processes or threads are
// initialized or terminated.
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
   if(reason == DLL_PROCESS_ATTACH)
     hInstance = (HMODULE)hinst;
   return TRUE;
}
//---------------------------------------------------------------------------
// _Module.Term is typically invoked from the DLL_PROCESS_DETACH of your
// DllEntryPoint. However, this may result in an incorrect shutdown sequence.
// Instead an Exit routine is setup to invoke the cleanup routine
// CComModule::Term.
void ModuleTerm(void)
{
   _Module.Term();
}
#pragma exit ModuleTerm 63
//---------------------------------------------------------------------------
// Entry point of your Server invoked to inquire whether the DLL is no
// longer in use and should be unloaded.
STDAPI __export DllCanUnloadNow(void)
{
   return nLocks == 0? S_OK: S_FALSE;
}
//---------------------------------------------------------------------------
// Entry point of your Server allowing OLE to retrieve a class object from
// your Server
STDAPI __export DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
   HRESULT hr = E_OUTOFMEMORY;
   *ppv = NULL;
   TClassFactory *pClassFactory = new TClassFactory;
   if(pClassFactory != NULL)
     hr = pClassFactory->QueryInterface(riid, ppv);
   return hr;
}
//---------------------------------------------------------------------------
// Entry point of your Server invoked to instruct the server to create
// registry entries for all classes supported by the module
STDAPI __export DllRegisterServer(void)
{
   HRESULT hr = S_OK;
   int nItems = sizeof(szRegTable) / sizeof(szRegTable[0]);
   char szDllPath[MAX_PATH];
   GetModuleFileName(hInstance, szDllPath, MAX_PATH);
   for(int i=0; i<nItems && SUCCEEDED(hr); i++)
   {
     const char *szKeyName = szRegTable[i][0];
     const char *szValueName = szRegTable[i][1];
     const char *szValue = szRegTable[i][2];
     if(szValue == (const char*) - 1)
       szValue = szDllPath;
     HKEY hKey;
     LONG lReturn = RegCreateKey(HKEY_CLASSES_ROOT, szKeyName, &hKey);
     if(lReturn == ERROR_SUCCESS)
     {
       RegSetValueEx(hKey, szValueName, 0, REG_SZ,
           (const BYTE*)szValue, strlen(szValue)+1);
       RegCloseKey(hKey);
     }
     if(lReturn != ERROR_SUCCESS)
     {
       hr = SELFREG_E_CLASS;
       DllUnregisterServer();
     }
   }
   return hr;
}
//---------------------------------------------------------------------------
// Entry point of your Server invoked to instruct the server to remove
// all registry entries created through DllRegisterServer.
STDAPI __export DllUnregisterServer(void)
{
   HRESULT hr = S_OK;
   LONG lReturn = 0;
   int nItems = sizeof(szRegTable) / sizeof(szRegTable[0]);
   for(int i=nItems-1; i>=0; i--)
   {
     const char *szKeyName = szRegTable[i][0];
     if((i == nItems-1) || stricmp(szRegTable[i+1][0], szKeyName) != 0)
       lReturn = RegDeleteKey(HKEY_CLASSES_ROOT, szKeyName);
     if(lReturn != ERROR_SUCCESS)
       hr = SELFREG_E_CLASS;
   }
   return hr;
}
//---------------------------------------------------------------------------

3. 在BCB的IDE情况中,选择菜单的Project–>Add to Project–>找到适才建设的TCopyHook.cpp–>OK

编译工程。假如没有错误,将生成Project1.dll。

4. 修改注册表:

#p#分页标题#e#

在HKEY_CLASSES_ROOT\Directory\shellex\CopyHookHandlers\下新建一个项,定名为Test,变动其默认值为{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735},老妖注:这里的默认值应该和project1.cpp中的沟通注册项目沟通。

5. 注册COM组件:

运行regsvr32.exe 路径\project.dll,点击确定后不要剖析再弹出的错误窗口。从头启动计较机,试着copy一个文件夹,当paste的时候,结果出来了,嘿嘿。本身试试吧。

    关键字:

在线提交作业